$30 off During Our Annual Pro Sale. View Details »

Pain-free APIs with Smithy4s

Pain-free APIs with Smithy4s

Most back-end projects eventually reach a point when they have to define an API. We implement their routes, document them, sometimes we write a client. We do essentially the same work multiple times - each view of an endpoint contains the same path, and yet we don't have a "single source of truth".

In this talk, I'll show how Smithy (https://smithy.io) and smithy4s enable defining an API in a single place, and how they make it easy to build its server, client, and even a CLI - in a Scala-friendly, tooling-compatible way.

Jakub Kozłowski

March 23, 2023
Tweet

More Decks by Jakub Kozłowski

Other Decks in Technology

Transcript

  1. Pain-free APIs
    Pain-free APIs
    with Smithy4s
    with Smithy4s
    Jakub Kozłowski | Scalar 2023 |
    Jakub Kozłowski | Scalar 2023 |
    linktr.ee/kubukoz
    linktr.ee/kubukoz

    View Slide

  2. Agenda
    Agenda

    View Slide

  3. 1/3
    1/3
    Let's talk about
    Let's talk about
    problems
    problems

    View Slide

  4. View Slide

  5. Communication
    Communication

    View Slide

  6. Misunderstood
    Misunderstood
    requirements
    requirements

    View Slide

  7. Omitting important
    Omitting important
    details
    details

    View Slide

  8. Solving the wrong
    Solving the wrong
    problem
    problem

    View Slide

  9. And that's not even all!
    And that's not even all!

    View Slide

  10. Implementation
    Implementation
    What can go wrong?
    What can go wrong?

    View Slide

  11. Writing problems
    Writing problems

    View Slide

  12. Documentation
    Documentation
    problems
    problems

    View Slide

  13. Maintenance problems
    Maintenance problems

    View Slide

  14. 2/3
    2/3
    Smithy to the
    Smithy to the
    rescue
    rescue

    View Slide

  15. What is Smithy?
    What is Smithy?

    View Slide

  16. Interface
    Interface
    definition
    definition
    language
    language
    (IDL)
    (IDL)
    operation GetWeather {
    input := {
    @required
    city: String
    }
    output := {
    @required
    weather: Weather
    }
    }
    structure Weather {
    @required
    degrees: Integer
    details: String
    }

    View Slide

  17. Created by AWS
    Created by AWS

    View Slide

  18. Protocol-agnostic
    Protocol-agnostic
    input := {
    + @httpHeader("JK-CITY")
    @required city: String
    }

    View Slide

  19. Readable for machines
    Readable for machines

    View Slide

  20. // not like this (http4s)
    HttpRoutes.of[IO] {
    case GET -> Root / "weather" / city :?
    params => ???
    }
    // more like this (tapir)
    endpoint.in(
    "weather" /
    path[String]("city") /
    query[String]("temp")
    )

    View Slide

  21. Readable for humans
    Readable for humans

    View Slide

  22. HTTP example
    HTTP example namespace hello
    use alloy#simpleRestJson
    @simpleRestJson
    service WeatherService {
    operations: [GetWeather]
    }
    @http(
    method: "GET",
    uri: "/weather/{city}"
    )
    @readonly
    operation GetWeather {
    ...
    }

    View Slide

  23. 3/3
    3/3
    How does Smithy
    How does Smithy
    solve the
    solve the
    problems?
    problems?

    View Slide

  24. Facilitates
    Facilitates
    communication
    communication

    View Slide

  25. Single source of truth
    Single source of truth

    View Slide

  26. Language-agnostic
    Language-agnostic

    View Slide

  27. Smithy4s
    Smithy4s

    View Slide

  28. What do we get?
    What do we get?
    // give me business logic, I'll give you
    routes
    def server(impl: WeatherService[IO]):
    HttpRoutes[IO]
    // give me a HTTP client, I'll give you a
    high-level interface
    def client(c: Client[IO]):
    WeatherService[IO]

    View Slide

  29. Server (routes)
    Server (routes)
    val impl: WeatherService[IO] = ...
    def run: IO[Unit] =
    SimpleRestJsonBuilder
    .routes(impl)
    .resource
    .flatMap { routes =>
    // normal http4s stuff from now on
    EmberServerBuilder
    .default[IO]
    .withHttpApp(routes.orNotFound)
    .build
    }
    .useForever

    View Slide

  30. Client
    Client
    EmberClientBuilder.default[IO].build
    .flatMap {
    SimpleRestJsonBuilder(WeatherService)
    .client(_)
    .uri(url)
    .resource
    }

    View Slide

  31. OpenAPI
    OpenAPI
    smithy4s.http4s.swagger
    .docs[IO](WeatherService):
    HttpRoutes[IO]

    View Slide

  32. Links
    Links
    Slides: see
    – linktr.ee/kubukoz
    Contact/YouTube/blog: see above ;)

    – smithy.io
    – disneystreaming.github.io/smithy4s
    – Scaling APIs with Smithy
    – Revisiting visitors: a talk about generalising
    serialisation
    – smithy4s fullstack (blogpost series)

    View Slide

  33. Bonus
    Bonus
    Why not just X?
    Why not just X?

    View Slide

  34. OpenAPI
    OpenAPI

    View Slide

  35. tapir, endpoints4s, Udash,
    tapir, endpoints4s, Udash,
    http4s-rho ...
    http4s-rho ...

    View Slide

  36. gRPC, GraphQL, RSocket...
    gRPC, GraphQL, RSocket...

    View Slide

  37. See also
    See also
    Smithy Playground
    Smithy Playground
    github.com/kubukoz/smithy-playground

    View Slide