Akka HTTP

Client and server backed by Akka HTTP.

Client

"org.julienrf" %% "endpoints-akka-http-client" % "0.15.0"

API documentation

Endpoints

The Endpoints interpreter fixes the Endpoint[A, B] type to a function from A to Future[B]:

type Endpoint[A, B] = A => Future[B]

This means that, given the following endpoint definition:

val someResource: Endpoint[Int, String] =
  endpoint(get(path / "some-resource" / segment[Int]()), ok(textResponse))

It can be invoked as follows:

val eventuallyString: Future[String] = someResource(42)

ChunkedEntities

The ChunkedEntities interpreter fixes the Chunks[A] type to akka.stream.scaladsl.Source[A, _]:

type Chunks[A] = akka.stream.scaladsl.Source[A, _]

This means that, given the following endpoint definition:

val logo: Endpoint[Unit, Chunks[Array[Byte]]] =
  endpoint(get(path / "logo.png"), ok(bytesChunksResponse))

It can be invoked as follows:

import akka.stream.scaladsl.Source

val bytesSource: Source[Array[Byte], _] =
  Source.futureSource(logo(()))

bytesSource.runForeach { bytes => println(s"Received ${bytes.length} bytes") }

Server

"org.julienrf" %% "endpoints-akka-http-server" % "0.15.0"

API documentation

Endpoints

The Endpoints interpreter fixes the Endpoint[A, B] type to something that, given an implementation function A => B, returns an akka.http.scaladsl.server.Route that can be integrated to your Akka HTTP application.

For instance, given the following endpoint definition:

val someResource: Endpoint[Int, String] =
  endpoint(get(path / "some-resource" / segment[Int]()), ok(textResponse))

It can be implemented as follows:

val route: Route =
  someResource.implementedBy(x => s"Received $x")

Alternatively, there is also a method implementedByAsync that takes an implementing function returning a Future[B].

ChunkedEntities

The ChunkedEntities interpreter fixes the Chunks[A] type to akka.stream.scaladsl.Source[A, _].

For instance, given the following chunked endpoint definition:

val logo: Endpoint[Unit, Chunks[Array[Byte]]] =
  endpoint(get(path / "logo.png"), ok(bytesChunksResponse))

It can be implemented as follows:

import java.nio.file.Paths
import akka.stream.scaladsl.FileIO

val logoRoute: Route =
  logo.implementedBy { _ =>
    FileIO.fromPath(Paths.get("/foo/bar/logo.png")).map(_.toArray)
  }

Error handling

When the server processes requests, three kinds of errors can happen: the incoming request doesn’t match any endpoint, the request does match an endpoint but is invalid (e.g. one parameter has a wrong type), or an exception is thrown.

The incoming request doesn’t match any endpoint

In that case, the routes constructed by endpoints can’t do anything. You have to deal with such errors in the usual Akka HTTP way: by using an implicit akka.http.scaladsl.server.RejectionHandler having a handleNotFound clause.

The incoming request is invalid

In that case, endpoints returns a “Bad Request” (400) response reporting all the errors in a JSON array. You can change this behavior by overriding the handleClientErrors method.

An exception is thrown

If an exception is thrown during request decoding, or when running the business logic, or when encoding the response, endpoints returns an “Internal Server Error” (500) response reporting the error in a JSON array. You can change this behavior by overriding the handleServerError method.