Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Endpoints

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.

Introduction to Endpoints

Endpoints is a Scala library for defining communication protocols over HTTP between applications. It allows to describe API endpoints as first-class Scala values and interpret them in multiple ways: as server, client or documentation making sure documentation is always consistent with server implementation.

Avatar for Piotr Krzemiński

Piotr Krzemiński

January 19, 2019
Tweet

More Decks by Piotr Krzemiński

Other Decks in Programming

Transcript

  1. Introduction to Endpoints Agenda • In the pursuit of type-safe,

    consistent API servers, clients, docs • Endpoints quick start • Endpoints architecture • Explicit resource optionality • Validation • Authentication • Custom interpreters • Summary
  2. Issues with manual approach 1. Consistency 2. Duplication 3. Correctness

    4. Boilerplate 5. Maintainability at scale HTTP API server Frontend Documentation API client
  3. Approach #1 RPC autowiring https://github.com/lihaoyi/autowire trait MyApi class MyApiImpl extends

    MyApi class MyApiClient extends MyApi (auto generated) • describe endpoints as methods in some trait MyApi • server implementation is just a class that implements procedural interface • client code is automatically generated by a macro • method call arguments / return value are pickled and transported in the wire (auto wired)
  4. Approach #2 Doc annotations https://github.com/swagger-akka-http/swa gger-akka-http https://github.com/swagger-api/swagger-p lay • use

    your target server implementation • write annotations to provide doc information • documentation is generated from type info and/or annotations • implementation and doc information in single place https://github.com/krzemin/currency-api/blob/master/src/main/scala/com/example/CurrencyApiRoutes.scala
  5. Approach #3 Code generation https://www.apibuilder.io https://grpc.io https://openapi-generator.tech api spec •

    api endpoints and entity models are described in some external, rich language • the spec file is an input to code generator which emits code in the target language • interoperability of clients / servers implemented in different target languages Code generator Play routes Documentation Api client (Scala) Api client (Kotlin) JSON codecs
  6. Approach #4 Interpreted EDSL https://julienrf.github.io/endpoints https://github.com/http4s/rho https://haskell-servant.github.io https://github.com/softwaremill/tapir Endpoints definition

    • endpoint definition as a construct in programming language • ability to interpret definition in the same programming language • easy customizability: plugging in own interpreters Documentation interpreter Server interpreter Client interpreter Documentation Client Server custom interpreter custom output
  7. Approaches summary approach consistency boilerplate extensibility autowiring only server and

    client minimal minimal annotations none (neither even server and docs) high none code generation full (relies on generator) minimal depends on generator interpreted EDSL full (relies on interpreter) minimal high
  8. Minimal example Endpoints definition def listPizzas: Endpoint[Unit, List[Pizza]] = endpoint(

    get(path / "pizzas"), jsonResponse[List[Pizza]]( docs = Some("List of available Pizzas in menu") ) ) def putPizza: Endpoint[Pizza, Unit] = endpoint( put(path / "pizzas", jsonRequest[Pizza](docs = Some("Pizza"))), emptyResponse(docs = Some("Pizza upserted")) ) def deletePizza: Endpoint[Int, Unit] = endpoint( delete(path / "pizzas" / segment[Int](name = "id")), emptyResponse(docs = Some("Pizza deleted")) )
  9. Minimal example Akka http routes trait Repository { def findAllPizzas:

    List[Pizza] def upsertPizza(pizza: Pizza): Unit def deletePizzaById(id: Int): Unit } def listPizzasRoute: Route = listPizzas.implementedBy(_ => repository.findAllPizzas) def putPizzaRoute: Route = putPizza.implementedBy(repository.upsertPizza) def deletePizzaRoute: Route = deletePizza.implementedBy(repository.deletePizzaById) val route: Route = listPizzasRoute ~ putPizzaRoute ~ deletePizzaRoute
  10. Minimal example OpenApi documentation def openapi: OpenApi = openApi(Info("Pizza Store",

    "1.0.0"))( listPizzas, putPizza, deletePizza ) def openapiJson: Json = openapi.asJson { "openapi": "3.0.0", "info": { "title": "Pizza Store", "version": "1.0.0" }, "paths": { "/pizzas": { "get": { "responses": { "200": { "description": "List of available Pizzas in menu", "content": { "application/json": { "schema": { "type": "array", "items": { ...
  11. Exercises $ git clone https://github.com/krzemin/endpoints-scala-workshop ❏ Exercise 1 - add

    few endpoints ❏ Exercise 2 - support entity non-existence with HTTP 404 ❏ Exercise 3 - validation ❏ Exercise 4 - authentication
  12. Resources Julien’s talk on object algebras https://www.youtube.com/watch?v=snbsYyBS4Bs Talks and publications

    http://julienrf.github.io/endpoints/talks.html Custom (token based) authentication tutorial http://julienrf.github.io/endpoints/guides/custom-authentication.html Gitter https://gitter.im/julienrf/endpoints