Search code examples
scalatapir

Constructing a Tapir Endpoint from a URL String that Includes query parameters


I need to use an API that returns a url to the next page in its response. My code is written in a way that I need to construct tapir endpoint to make http call. But I don't see a way to transform url string into EndpointInput. The url contains query parameters and .in(string) doesn't seem to be able to handle it.

What is the correct way to transform a URL string, which contains query parameters, into a Tapir EndpointInput?


Solution

  • I don't think Tapir works in that way.

    If you check the docs, you will see the following definitions

    Tapir

    Declarative, type-safe web endpoints library.

    Intro

    With tapir, you can describe HTTP API endpoints as immutable Scala values. Each endpoint can contain a number of input and output parameters.

    Why tapir?

    • type-safety: compile-time guarantees, develop-time completions, read-time information
    • declarative: separate the shape of the endpoint (the “what”), from the server logic (the “how”)

    Goals of the project

    • based purely on case class-based, immutable and reusable data structures
    • reasonably type safe: only, and as much types to safely generate the server/client/docs

    An endpoint built using tapir looks like

    val endpointDefinition: Endpoint = 
      endpoint
        .delete.         // EndpointInput.FixedMethod
        .in(             // EndpointInput
             "api"       // String ==> EndpointInput.FixedPath
             /           // EndpointInput.Pair
             "v1"        // String ==> EndpointInput.FixedPath
             /           // EndpointInput.Pair
             "noun"      // String ==> EndpointInput.FixedPath
             / path[Int] // EndpointInput.PathCapture
         )
         .out(           // EndpointOutput
           stringBody    // EndpointIO.Body
         )
    

    All the Strings will be transformed to EndpointInput.FixedPath because there is an implicit def stringToPath.

    Then you have the case class Endpoint

    case class Endpoint[SECURITY_INPUT, INPUT, ERROR_OUTPUT, OUTPUT, -R](
        securityInput: EndpointInput[SECURITY_INPUT],
        input: EndpointInput[INPUT],
        errorOutput: EndpointOutput[ERROR_OUTPUT],
        output: EndpointOutput[OUTPUT],
        info: EndpointInfo
    ) extends EndpointInputsOps 
         with // ...
    

    As you can see, you have the Endpoint class which is the definition of the endpoint with some attributes that contains info about the inputs and outputs. The in method comes from the trait EndpointInputsOps which is mixed in the Endpoint class and that's why you can call that method.

    From there, you can generate a client, a server and the docs from scala code at compile-time using the interpreter you need such as akka-http, zio-http, Vert.x, OpenAPI, AsyncAPI.

    You can also Generate Endpoint definitions from OpenAPI, but again it works at compile-time.


    In your question you said:

    I need to use an API that returns a url to the next page in its response

    Which means, in some part of your project there will be something like

    val response = service.execute(params...)
    val url = response.nextUrl
    val result = client.sendRequest(url)
    

    The url is returned in runtime, mean while tapir works at compile-time.


    If you know the URL at compilation time, you could use some parser (maybe with a regex is enough). Which doesn't make any sense parse a known string to then generate an endpoint definition