forked from endpoints4s/endpoints4s
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
197 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
# JSON codecs | ||
|
||
The [JSON entities algebras](/algebras/json-entities.md) show that several options | ||
are available to define endpoints having JSON entities. In this guide, we show | ||
which options should be used in which case, and which interpreters are compatible | ||
with which algebras. | ||
|
||
## Use codecs at the algebra level | ||
|
||
The most general algebra for defining JSON entities uses separate | ||
types for request and response entities: | ||
|
||
~~~ scala src=../../../../../algebras/algebra/src/main/scala/endpoints/algebra/JsonEntities.scala#request-response-types | ||
~~~ | ||
|
||
However, in case your endpoint definitions are interpreted in multiple ways these types | ||
should be aligned so that requests and responses are consistently encoded, decoded and | ||
documented by client, server and documentation interpreters. A consequence of this is that an | ||
implicit instance of such codecs has to be available for your data types at the | ||
definition-site of your endpoints. | ||
|
||
The next sections show how to use the two families of “codec”-based `JsonEntities` algebra | ||
specializations: `JsonEntitiesFromCodec` and `JsonSchemaEntities`. | ||
|
||
## `JsonEntitiesFromCodec` | ||
|
||
### Algebra | ||
|
||
In case you don’t need to document the JSON schemas of your request and response entities, the | ||
`JsonEntitiesFromCodec` family of algebras is the preferred approach. These algebras fix both | ||
the `JsonRequest` and `JsonResponse` types to a same (abstract) `JsonCodec` type: | ||
|
||
~~~ scala src=../../../../../algebras/algebra/src/main/scala/endpoints/algebra/JsonEntities.scala#json-codec-type | ||
~~~ | ||
|
||
Generally, you want to use a `JsonEntitiesFromCodec` algebra that fixes this `JsonCodec` type to | ||
a concrete type. An example is `endpoints.algebra.playjson.JsonEntitiesFromCodec`, which | ||
aligns the `JsonCodec` type with Play’s `Format` type: | ||
|
||
~~~ scala src=../../../../../algebras/algebra-playjson/src/main/scala/endpoints/algebra/playjson/JsonEntitiesFromCodec.scala#type-carrier | ||
~~~ | ||
|
||
The [JSON entities algebra](/algebras/json-entities.md#jsonentitiesfromcodec) documentation page | ||
shows the list of `JsonEntitiesFromCodec` algebras that fixes the `JsonCodec` type to a concrete type. | ||
|
||
### Interpreters | ||
|
||
To interpret endpoints defined with such algebras, apply any interpreter named `JsonEntitiesFromCodec` | ||
that matches your [family](/algebras-and-interpreters.md#interpreters) of interpreters. For instance, | ||
if you use interpreters from the `endpoints.xhr` package (ie. the Scala.js web interpreters), you | ||
should use the `endpoints.xhr.JsonEntitiesFromCodec` interpreter. | ||
|
||
## `JsonSchemaEntities` | ||
|
||
### Algebra | ||
|
||
The `endpoints.algebra.JsonSchemaEntities` algebra allows you to document the JSON schema of request | ||
and response entities (when you apply a documentation interpreter to endpoints defined with this | ||
algebra). Both the `JsonRequest` and `JsonResponse` types are fixed to the | ||
`JsonSchema` type provided by the [JsonSchemas](/algebras/json-schemas.md) algebra: | ||
|
||
~~~ scala src=../../../../../algebras/algebra/src/main/scala/endpoints/algebra/JsonSchemaEntities.scala#type-carrier | ||
~~~ | ||
|
||
### Interpreters | ||
|
||
To interpret endpoints defined with this algebra, pick an interpreter that matches your | ||
[family](/algebras-and-interpreters.md#interpreters) of interpreters and, if relevant, | ||
the underlying JSON library to use. For instance, the | ||
`endpoints.play.server.circe.JsonSchemaEntities` trait is a server interpreter based | ||
on Play framework that uses the circe JSON library. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
# `Tupler` | ||
|
||
This guide explains why we use implicit [`Tupler`](api:endpoints.Tupler) parameters | ||
in the signature of some algebra operations and how it works. | ||
|
||
## Motivation | ||
|
||
As explained in the [design](/design.md) page, to model a request that carries | ||
an information of type `A`, we use the type `Request[A]`. This type `A` is | ||
important because it represents what is needed by clients to build such | ||
a request and what is received by servers to process such a request. For | ||
instance, a request carrying a user id could be modeled as `Request[Long]`. | ||
Clients would have to supply a `Long` value in order to build such a request, | ||
and servers would decode a `Long` value. Tracking these types is important | ||
because it guarantees that requests and responses are well-formed. | ||
|
||
Now, suppose that we define a request that has an URL carrying a user id | ||
(of type `Long`), and an entity carrying an `UpdateUser` value (describing | ||
changes to apply to a user resource). Such a request would have type | ||
`Request[(Long, UpdateUser)]`. | ||
|
||
To support the definition of such requests, the algebra provides an | ||
operation that, given an URL and a request entity, returns a request. | ||
A naive definition of such an operation could be the following: | ||
|
||
~~~ scala | ||
def request[U, E](url: Url[U], entity: RequestEntity[E]): Request[(U, E)] | ||
~~~ | ||
|
||
So that, given an `Url[Long]` and a `RequestEntity[UpdateUser]`, it | ||
would return a `Request[(Long, UpdateUser)]`. | ||
|
||
However, some requests have no entity. An empty request entity is modeled | ||
by the `emptyEntity` constructor, which has type `RequestEntity[Unit]`. | ||
|
||
This means that given the above definition of `request`, defining a | ||
request whose URL carries a `Long` value, but having no entity, would | ||
have type `Request[(Long, Unit)]`. Also, to build such requests | ||
clients would have to supply a `(Long, Unit)` value, and to handle | ||
such requests servers would have to process a `(Long, Unit)` value. | ||
However, these `Unit` values are never meaningful: they can not carry | ||
any useful information. | ||
|
||
Things are even worse because in practice requests are formed of an | ||
`Url[U]`, a `RequestEntity[E]` and a `RequestHeaders[H]`. So, the | ||
“naive” return type of a request should be `Request[(U, E, H)]`, | ||
even if several of these type parameters are instantiated to `Unit`. | ||
|
||
The goal of the `Tupler` type is to compute more useful tuple types | ||
by discarding the `Unit` parameters. For instance, it produces a | ||
`Request[Long]` instead of a `Request[(Long, Unit)]`. Additionally, | ||
nested tuples are flattened: `Request[((Long, Boolean), String)]` | ||
becomes `Request[(Long, Boolean, String)]`. | ||
|
||
## How it works | ||
|
||
The `Tupler[A, B]` type takes two type parameters `A` and `B` | ||
and defines an abstract type member `Out`. This `Out` type defines | ||
the “useful” form of tupling `A` and `B`. | ||
|
||
~~~ scala src=../../../../../algebras/algebra/src/main/scala/endpoints/Tupler.scala#definition | ||
~~~ | ||
|
||
Algebra operations that want to tuple types `A` and `B` take as | ||
parameter an implicit `tupler: Tupler[A, B]` and return a | ||
`tupler.Out` instead of an `(A, B)`. | ||
|
||
Several implicit instances of `Tupler` are provided. For example, | ||
the following instance returns a pair of `(A, B)` for all types | ||
`A` and `B`: | ||
|
||
~~~ scala | ||
implicit def pair[A, B]: Tupler[A, B] { type Out = (A, B) } | ||
~~~ | ||
|
||
But we have seen that our goal is to special case tupling `Unit` | ||
types. This is achieved by defining another `Tupler` instance | ||
with a higher priority than this one, for the case where one | ||
of the type parameters is `Unit`. For instance: | ||
|
||
~~~ scala | ||
implicit def keepFirst[A]: Tupler[A, Unit] { type Out = A } | ||
~~~ | ||
|
||
The `keepFirst` instance computes the type of tupling `A` | ||
and `Unit`, for all type `A`, to be `A`. | ||
|
||
When the operation that takes an implicit `Tupler` as parameter | ||
is called, appropriate instances of `Tupler` will compute the type | ||
of the resulting tuple, by discarding `Unit` types and flattening | ||
nested tuples. |