• Stars
    star
    161
  • Rank 233,470 (Top 5 %)
  • Language
    Scala
  • License
    MIT License
  • Created over 6 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Build your web API on the type level.

Build Status Maven Central Gitter Scala.js

experimental project: see issues #39 and #41

Typedapi

Define type safe APIs and let the Scala compiler do the rest:

Api definition

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])

Client side

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]

Server side

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.

Motivation

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:

If you need something else take a look at this doc.

Get this library

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"

Ammonite

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.

Documentation

The documentation is located in docs and covers the following topics so far:

Dependencies

Contribution

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.