experimental project: see issues #39 and #41
Define type safe APIs and let the Scala compiler do the rest:
import typedapi._
val MyApi =
// GET {body: User} /fetch/user?{name: String}
api(method = Get[MT.`application/json`, User],
path = Root / "fetch" / "user",
queries = Queries add Query[String]('name)) :|:
// POST {body: User} /create/user
apiWithBody(method = Post[MT.`application/json`, User],
body = ReqBody[Json, User],
path = Root / "create" / "user")
And for the Servant lovers:
import typedapi.dsl._
val MyApi =
// GET {body: User} /fetch/user?{name: String}
(:= :> "fetch" :> "user" :> Query[String]('name) :> Get[MT.`application/json`, User]) :|:
// POST {body: User} /create/user
(:= :> "create" :> "user" :> ReqBody[Json, User] :> Post[MT.`application/json`, User])
import typedapi.client._
val (fetch, create) = deriveAll(MyApi)
import typedapi.client.http4s._; import cats.effect.IO; import org.http4s.client.blaze.Http1Client
val cm = ClientManager(Http1Client[IO]().unsafeRunSync, "http://my-host", 8080)
fetch("joe").run[IO](cm): IO[User]
import typedapi.server._
val fetch: String => IO[Result[User]] = name => findUserIO(name).map(success)
val create: User => IO[Result[User]] = user => createUserIO(user).map(success)
val endpoints = deriveAll[IO](MyApi).from(fetch, create)
import typedapi.server.http4s._; import cats.effect.IO; import org.http4s.server.blaze.BlazeBuilder
val sm = ServerManager(BlazeBuilder[IO], "http://my-host", 8080)
val server = mount(sm, endpoints)
server.unsafeRunSync()
This is all you have to do to define an API with multiple endpoints and to create a working client and server for them.
You can find the above code as a complete project here.
This library is the result of the following questions:
How much can we encode on the type level? Are we able to describe a whole API and generate the call functions from that without using Macros?
It is inspired by Servant and it provides an API layer which is independent of the underlying server/client implementation. Right now Typedapi supports:
- http4s
- akka-http
- scalaj-http on the client-side
- ScalaJS on the client-side
If you need something else take a look at this doc.
It is available for Scala 2.11, 2.12 and ScalaJS and can be downloaded as Maven artifact:
// dsl
"com.github.pheymann" %% "typedapi-client" % <version>
"com.github.pheymann" %% "typedapi-server" % <version>
// http4s support
"com.github.pheymann" %% "typedapi-http4s-client" % <version>
"com.github.pheymann" %% "typedapi-http4s-server" % <version>
// akka-http support
"com.github.pheymann" %% "typedapi-akka-http-client" % <version>
"com.github.pheymann" %% "typedapi-akka-http-server" % <version>
// Scalaj-Http client support
"com.github.pheymann" %% "typedapi-scalaj-http-client" % <version>
// ScalaJS client support
"com.github.pheymann" %% "typedapi-js-client" % <version>
You can also build it on your machine:
git clone https://github.com/pheymann/typedapi.git
cd typedapi
sbt "+ publishLocal"
Typedapi also offers an improved experience for Ammonite and ScalaScripts:
import $ivy.`com.github.pheymann::typedapi-ammonite-client:<version>`
import typedapi._
import client._
import amm._
val Readme = api(Get[MT.`text/html`, String], Root / "pheymann" / "typedapi" / "master" / "README.md")
val readme = derive(Readme)
// gives you the raw scalaj-http response
val cm = clientManager("https://raw.githubusercontent.com")
val response = get().run[Id].raw(cm)
response.body
response.headers
...
In case Ammonite cannot resolve com.dwijnand:sbt-compat:1.0.0
, follow this solution.
The documentation is located in docs and covers the following topics so far:
- How to define an API
- How to create a client
- How to create a server
- Extend the library
- Typelevel Summit 2018 Berlin Talk Typedapi: Define your API on the type-level
- and a post on the Typelevel Blog describing the basic concept behind this library.
Contributions are highly appreciated. If you find a bug or you are missing the support for a specific client/server library consider opening a PR with your solution.