构建一个包含查询参数的 Tapir 终端点,从包括查询参数的 URL 字符串开始

huangapple go评论57阅读模式
英文:

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

问题

我需要使用一个API,它在其响应中返回下一页的URL。
我的代码是按照一种方式编写的,我需要构建Tapir端点来进行HTTP调用。
但我看不到将URL字符串转换为EndpointInput的方法。该URL包含查询参数,而.in(string)似乎无法处理它。

如何正确将包含查询参数的URL字符串转换为Tapir EndpointInput?

英文:

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?

答案1

得分: 1

我不认为Tapir以那种方式工作。

如果您查看文档,您将看到以下定义

Tapir

声明性的、类型安全的Web端点库。

Intro

使用Tapir,您可以将HTTP API端点描述为不可变的Scala值。每个端点可以包含多个输入和输出参数。

Why tapir?

  • 类型安全性:编译时保证,开发时自动完成,读取时信息
  • 声明性:将端点的形状(“what”)与服务器逻辑(“how”)分开

项目目标

  • 基于纯粹的Case Class-based、不可变和可重用的数据结构
  • 合理的类型安全性:只有尽可能多的类型以安全生成服务器/客户端/文档

使用tapir构建的端点如下所示

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
     )

所有的String都会被转换为EndpointInput.FixedPath,因为存在一个implicit def stringToPath

然后,您有端点的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 // ...

正如您所见,您有Endpoint类,它是端点的定义,包含有关输入和输出的信息。in方法来自特质EndpointInputsOps,它混入了Endpoint类,这就是您可以调用该方法的原因。

从那里,您可以使用所需的解释器,如akka-httpzio-httpVert.xOpenAPIAsyncAPI,在编译时Scala代码生成客户端服务器文档

您还可以从OpenAPI生成端点定义,但同样,它在编译时工作。


在您的问题中,您说:

我需要使用返回其响应中下一页的URL的API

这意味着,在您的项目的某个部分,会有类似以下的内容

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

URL在运行时返回,而tapir在编译时工作。


如果您在编译时知道URL,可以使用一些解析器(也许只需使用正则表达式)。这不合理,将已知字符串解析为然后生成端点定义。

英文:

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

huangapple
  • 本文由 发表于 2023年6月30日 00:51:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76583103.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定