Tapir Documentation

repository·master·Indexed 23 days ago

https://github.com/softwaremill/tapir

A Scala library for describing HTTP APIs in a declarative, type-safe manner. Tapir allows developers to define endpoint shapes once to generate servers (e.g., Netty, Akka HTTP), clients, and documentation in OpenAPI, AsyncAPI, and JSON Schema formats. The library separates the endpoint shape from the business logic to provide compile-time guarantees.

Tokens
150K
Snippets
325
Records
606
Agent score
77%

What's inside Tapir

  1. What is Tapir?

    master

    Tapir is a library for describing HTTP APIs in a type-safe, declarative way. It allows you to define the shape of an endpoint (the "what") separately from its implementation (the "how"). Once an endpoint is defined, Tapir can automatically:

    • Expose it as a server: Integrate with major Scala HTTP server implementations (Netty, Akka HTTP, Pekko HTTP, Http4s, etc.).
    • Consume it as a client: Generate client requests using interpreters (like sttp4).
    • Document it: Automatically generate documentation in OpenAPI, AsyncAPI, or JSON Schema formats.

    Key benefits include compile-time type safety, high performance (via a Netty-based server), and seamless integration with the Scala ecosystem (JSON libraries like Circe, observability tools, and functional programming stacks).

    endpoint
      .get.in("hello").in(query[String]("name"))
      .out(stringBody)
      .handleSuccess(name => s"Hello, $name!")
  2. Introduction to Tapir

    master

    Tapir is a library used to describe HTTP APIs in a declarative way. Once an endpoint is described, Tapir can:

    • Expose it as a server: Integrate with major Scala HTTP server implementations (e.g., Netty, Akka HTTP).
    • Consume it as a client: Automatically generate HTTP requests to interact with the described API.
    • Document it: Generate documentation using open standards like OpenAPI, AsyncAPI, and JSON Schema.

    Tapir separates the shape of the endpoint (the "what") from the logic (the "how"), providing type-safety and compile-time guarantees.

  3. Overview of Tapir server integrations

    master
    • Netty: Supports direct-style, Futures, cats-effect, or ZIO.
    • Http4s: Uses HttpRoutes[F] (cats-effect or ZIO).
    • Pekko HTTP: Uses Routes/Directives.
    • Akka HTTP: Uses Routes/Directives.
    • Vert.X: Uses Router => Route (supports Futures, cats-effect, or ZIO).
    • Armeria: Uses HttpServiceWithRoutes (supports Futures, cats-effect, or ZIO).
    • ZIO Http: Uses Http.
    • Play: Uses Route.
    • Helidon Níma: Uses JVM 21 Virtual Threads and direct style.
    • Finatra: Uses http.Controller.
    • JDK HTTP: Uses HttpHandler (simple, synchronous API only).
    • AWS: Integration via Lambda, SAM, or Terraform.
    • gRPC: Supported via specialized integration.
  4. Tapir ecosystem and integrations

    master

    Tapir is designed to fit into various Scala programming styles and existing server ecosystems:

    Supported Effect Types

    • Future-based
    • cats-effect
    • ZIO

    Supported Server Implementations

    • akka-http
    • http4s
    • vertx
    • Play framework

    Documentation and Observability

    • Documentation: Generates "raw" OpenAPI YAML files, compatible with SwaggerUI and Redoc. Supports AsyncAPI out-of-the-box.
    • Observability: Integrates with tools to enrich metrics, logs, or traces using the metadata provided by Tapir endpoints.
  5. Tapir ecosystem compatibility

    master

    Tapir is designed to integrate with various Scala programming styles and existing server implementations:

    Supported Effect Types

    • Future-based
    • cats-effect
    • ZIO

    Supported Server Implementations

    • akka-http
    • http4s
    • vertx
    • Play framework

    Documentation & Observability

    • Documentation: Generates OpenAPI (YAML) and AsyncAPI. Supports rendering via SwaggerUI and Redoc.
    • Observability: Metadata can be used to enrich metrics, logs, and traces via various observability tool integrations.
  6. Core design goals of Tapir

    master

    Tapir is designed to provide a type-safe, programmer-friendly way to define HTTP endpoints. Its primary objectives include:

    • Developer Experience: Uses human-comprehensible types that are easy to write, discover via standard IDE auto-complete, and are inferencable by IntelliJ.
    • Separation of Concerns: Decouples business logic from endpoint definitions and documentation.
    • Simplicity in Generation: Aims to make generating servers, clients, and documentation as simple as possible.
    • Data-Driven Design: Built entirely on case class-based, immutable, and reusable data structures.
    • OpenAPI Support: Provides first-class OpenAPI support with configurable levels of detail.
    • Type Safety: Uses only the necessary amount of types to safely generate servers, clients, and documentation without unnecessary complexity.
  7. What is a Codec in Tapir?

    master

    A Codec[L, H, CF] is a bi-directional mapping between a low-level value of type L and a high-level value of type H, where the low-level value is formatted as CF (the CodecFormat).

    A codec provides three main capabilities:

    1. Decoding: A function to transform a low-level value (e.g., a String from a URL) into a high-level type (e.g., a User case class).
    2. Encoding: A function to transform a high-level type back into a low-level value.
    3. Schema: A description of the high-level type used for validation and documentation generation.

    Example: A Codec[String, User, CodecFormat.Json] would decode a JSON String into a User object and encode a User object into a JSON String.

  8. What is the Identity type in Tapir documentation?

    master

    In Tapir, the Identity type constructor is used when working with direct-style, synchronous code that does not use a functional effect wrapper (like IO, ZIO, or Task).

    type Identity[X] = X

    When calling methods like fromServerEndpoints that require a type constructor parameter (often denoted as F[_]), passing Identity tells Tapir that the computations are synchronous and do not involve asynchronous or effectful wrappers. This is common when using simple server interpreters like NettySyncServer.

  9. What is Tapir and how does it work?

    master

    Tapir is a library designed to provide a programmer-friendly, type-safe API for describing HTTP endpoints as immutable Scala values.

    Instead of using annotations (which can be difficult to refactor), Tapir allows you to capture the complete metadata of an endpoint in a Scala value. This description can then be interpreted in three primary ways:

    1. As a Server: Implementing the logic to handle the described endpoints.
    2. As a Client: Automatically generating code to consume the described endpoints.
    3. As Documentation: Generating API documentation like OpenAPI (SwaggerUI/Redoc) or AsyncAPI.

    Because endpoints are standard Scala values, you can use Scala's abstraction capabilities to extend, reuse, and refactor them easily.

  10. Define Endpoint Inputs and Outputs

    master

    Tapir endpoints are composed of inputs and outputs.

    • Inputs are described by EndpointInput and represent data coming from the request (e.g., path, query, headers, body).
    • Outputs are described by EndpointOutput and represent data sent in the response (e.g., status code, body, headers).
    • EndpointIO is a trait implemented by types that can serve as both an input and an output.

    Common Input Methods

    • path[T]: Captures a path segment as type T.
    • query[T](name): Captures a query parameter.
    • queryParams: Captures all query parameters as QueryParams.
    • header[T](name): Captures a header.
    • cookie[T](name): Captures a cookie.
    • extractFromRequest: Extracts a value from the request (server-only; ignored by documentation/client interpreters).
    • Body types: stringBody, jsonBody[T], plainBody[T], rawBinaryBody[R], binaryBody[R, T], formBody[T], multipartBody[T], fileBody, streamBody[S], and oneOfBody.

    Common Output Methods

    • statusCode: Maps to a dynamic sttp.model.StatusCode.
    • statusCode(code): Maps to a fixed status code.
    • Body types: Same as inputs (e.g., jsonBody[T], stringBody).
    • Headers/Cookies: header[T](name), headers, setCookie(name), setCookies.
  11. Handle decode failures and endpoint matching

    master

    When a request fails to decode, Tapir follows OpenAPI conventions to decide whether to return an error or try the next endpoint:

    • 405 Method Not Allowed: Returned if the path matches one or more endpoints, but the HTTP method does not match any of them. This can be customized using a RejectInterceptor.
    • 404 Not Found: Returned if neither the path nor the method matches any interpreted endpoint.
    • 400 Bad Request: Returned if the path matches, but a parameter (query, header, body, or path segment) fails to decode or fails validation.
    • 401 Unauthorized: Returned if an authentication input fails to decode.

    You can customize this behavior by providing a sttp.tapir.server.interceptor.decodefailure.DecodeFailureHandler in your server options.

  12. Inlined vs Referenced Schemas in OpenAPI

    master

    In the generated OpenAPI document, how schemas are represented depends on whether they have a name:

    • Referenced Schemas: If a schema has a Schema.name property defined, it will be placed in the components section and referenced at the point of use.
    • Inlined Schemas: To inline a schema instead of referencing it, remove the name from the schema definition.