muffin icon indicating copy to clipboard operation
muffin copied to clipboard

Mattermost API v4 Client for Scala

Muffin

Build

Mattermost v4 API client for Scala 3.

Getting started

  1. Add muffin to your project dependencies:
libraryDependencies += "ru.tinkoff" %% "muffin-core" % "latest version in badge"
  1. Choose your integrations and include them, for example circe, http4s, and sttp with AsyncHttpClientCatsBackend:
libraryDependencies += "ru.tinkoff" %% "muffin-circe-json-interop" % "latest version in badge"
libraryDependencies += "ru.tinkoff" %% "muffin-sttp-http-interop" % "latest version in badge"
libraryDependencies += "com.softwaremill.sttp.client3" %% "async-http-client-backend-cats" % "3.7.6"
  1. Full example
import java.time.{LocalDateTime, ZoneId}

import cats.effect.*
import sttp.client3.asynchttpclient.cats.AsyncHttpClientCatsBackend

import io.circe.*

import muffin.api.*
import muffin.model.*
import muffin.dsl.*
import muffin.interop.circe.codec
import muffin.interop.http.Http4sRoute

type Api = ApiClient[IO, Encoder, Decoder]

class SimpleCommandHandler(api: Api){
  def time(command: CommandAction): IO[AppResponse[Nothing]] = {
    api.postToChannel(command.channelId, LocalDateTime.now().toString.some).as(ok)
  }
}

object Application extends IOApp.Simple {
    for {
        backend      <- AsyncHttpClientCatsBackend[IO]()
        httpClient   <- SttpClient[Task, Task, Encoder, Decoder](backend)
        given ZoneId <- ZIO.succeed(ZoneId.systemDefault())
        cfg          = ClientConfig("base mattermost api url", "auth token", "bot name", "your service base url")
        apiClient    = ApiClient[IO, Encoder, Decoder](httpClient, cfg)(codec)
      
        handler = SimpleCommandHandler(apiClient)
      
        router <- handle(handler).command(_.time).in[Task, Task]
      
        _ <- EmberServerBuilder
          .default[IO]
          .withHost(ipv4"0.0.0.0")
          .withPort(port"8080")
          .withHttpApp(Router("/" -> Http4sRoute.routes(router, codec)).orNotFound)
          .build
          .allocated
          .never
    } yield ()
}

More examples here

Supported integrations

Json integrations

circe

libraryDependencies += "ru.tinkoff" %% "muffin-circe-json-interop" % "latest version in badge"
import muffin.interop.circe.codec.given

zio-json

libraryDependencies += "ru.tinkoff" %% "muffin-zio-json-interop" % "latest version in badge"
import muffin.interop.zio.codec.given

Http integrations

http4s

libraryDependencies += "ru.tinkoff" %% "muffin-http4s-http-interop" % "latest version in badge"
import cats.effect.IO

import muffin.interop.http.Http4sRoute

val router: Router[IO] = ???
val codec = ??? // Choose you codec in json integrations section

val server = EmberServerBuilder
  .default[IO]
  .withHost(ipv4"0.0.0.0")
  .withPort(port"8080")
  .withHttpApp(Router("/" -> Http4sRoute.routes(app, codec)).orNotFound)
  .build

zio-http

libraryDependencies += "ru.tinkoff" %% "muffin-zio-http-interop" % "latest version in badge"
import zio.*

import muffin.interop.http.ZioServer
import muffin.interop.circe.codec

val router: Router[Task] = ???
val codec = ??? // Choose you codec in json integrations section

val client = ZioClient[Task, /* Supported json encoder */, /* Supported json decoder */](codec)


val server = Server.start(8080, ZioServer.routes(router, codec))

sttp

libraryDependencies += "ru.tinkoff" %% "muffin-sttp-http-interop" % "latest version in badge"
import java.time.ZoneId

import cats.effect.IO

import muffin.model.*

val client = SttpClient[IO, IO, /* Supported json encoder */, /* Supported json decoder */](backend, codec)

Copyright

Copyright the maintainers

Logos made by Midjourney