Geração de Documentação OpenAPI
OpenAPI é uma especificação de código aberto para descrever o design de interfaces de API RESTful. Ele define estruturas de requisição e resposta da API, parâmetros, tipos de retorno, códigos de erro e outros detalhes em formato JSON ou YAML, tornando a comunicação entre cliente e servidor mais explícita e padronizada.
OpenAPI era originalmente a versão de código aberto da especificação Swagger e agora se tornou um projeto independente apoiado por muitas grandes empresas e desenvolvedores. Usar a especificação OpenAPI ajuda as equipes de desenvolvimento a colaborar melhor, reduzir custos de comunicação e melhorar a eficiência de desenvolvimento. Além disso, o OpenAPI fornece aos desenvolvedores ferramentas para gerar automaticamente documentação de API, dados simulados e casos de teste, facilitando o trabalho de desenvolvimento e teste.
O Salvo fornece integração OpenAPI (modificada a partir do utoipa). O Salvo extrai elegantemente informações relevantes de tipos de dados OpenAPI automaticamente do Handler com base em suas próprias características. O Salvo também integra várias interfaces OpenAPI de código aberto populares, como SwaggerUI, Scalar, RapiDoc e ReDoc.
Como os nomes de tipos Rust podem ser longos e nem sempre adequados para uso no OpenAPI, o salvo-oapi fornece o tipo Namer, que permite personalizar regras para alterar nomes de tipos no OpenAPI conforme necessário.
Código de Exemplo
Digite http://localhost:8698/swagger-ui em seu navegador para ver a página do Swagger UI.
A integração OpenAPI no Salvo é bastante elegante. Para o exemplo acima, em comparação com um projeto Salvo normal, apenas fizemos as seguintes etapas:
-
Habilitar o recurso
oapiemCargo.toml:salvo = { workspace = true, features = ["oapi"] }; -
Substituir
#[handler]por#[endpoint]; -
Usar
name: QueryParam<String, false>para obter o valor da string de consulta. Quando você acessahttp://localhost/hello?name=chris, a string de consultanameserá analisada. OfalseemQueryParam<String, false>significa que este parâmetro é opcional. Se você acessarhttp://localhost/hello, não retornará um erro. Por outro lado, se forQueryParam<String, true>, significa que este parâmetro deve ser fornecido, caso contrário, um erro será retornado. -
Criar
OpenAPIe oRoutercorrespondente. Omerge_routeremOpenApi::new("test api", "0.0.1").merge_router(&router)significa que esteOpenAPIobtém as informações de documento necessárias analisando uma determinada rota e suas sub-rotas. AlgunsHandlers de rotas podem não fornecer informações para gerar documentos, e essas rotas serão ignoradas, comoHandlers definidos usando a macro#[handler]em vez da macro#[endpoint]. Ou seja, em projetos reais, por razões como progresso de desenvolvimento, você pode optar por não gerar documentos OpenAPI ou gerar documentos OpenAPI parcialmente. Posteriormente, você pode aumentar gradualmente o número de interfaces OpenAPI geradas, e tudo o que você precisa fazer é alterar#[handler]para#[endpoint]e modificar a assinatura da função.
Extratores de Dados
Você pode importar extratores de dados comuns predefinidos através de use salvo::oapi::extract::*;. O extrator fornecerá algumas informações necessárias ao Salvo para que o Salvo possa gerar documentos OpenAPI.
-
QueryParam<T, const REQUIRED: bool>: Um extrator para extrair dados de strings de consulta.QueryParam<T, false>significa que este parâmetro não é obrigatório e pode ser omitido.QueryParam<T, true>significa que este parâmetro é obrigatório e não pode ser omitido. Se não for fornecido, um erro será retornado; -
HeaderParam<T, const REQUIRED: bool>: Um extrator para extrair dados do cabeçalho da requisição.HeaderParam<T, false>significa que este parâmetro não é obrigatório e pode ser omitido.HeaderParam<T, true>significa que este parâmetro é obrigatório e não pode ser omitido. Se não for fornecido, um erro será retornado; -
CookieParam<T, const REQUIRED: bool>: Um extrator para extrair dados do cookie da requisição.CookieParam<T, false>significa que este parâmetro não é obrigatório e pode ser omitido.CookieParam<T, true>significa que este parâmetro é obrigatório e não pode ser omitido. Se não for fornecido, um erro será retornado; -
PathParam<T>: Um extrator para extrair parâmetros de caminho da URL da requisição. Se este parâmetro não existir, a correspondência de rota não será bem-sucedida, portanto, não há caso em que possa ser omitido; -
FormBody<T>: Extrai informações do formulário enviado pela requisição; -
JsonBody<T>: Extrai informações do payload em formato JSON enviado pela requisição;
#[endpoint]
Ao gerar documentos OpenAPI, você precisa usar a macro #[endpoint] em vez da macro regular #[handler]. Na verdade, é uma versão aprimorada da macro #[handler].
-
Ela pode obter as informações necessárias para gerar OpenAPI através da assinatura da função;
-
Para informações que não são convenientes de fornecer através da assinatura, você pode fornecê-las diretamente adicionando atributos na macro
#[endpoint]. As informações fornecidas dessa forma serão mescladas com as informações obtidas através da assinatura da função. Se houver conflito, elas substituirão as informações fornecidas pela assinatura da função.
Você pode usar o atributo #[deprecated] embutido do Rust para marcar um Handler como obsoleto. Embora o atributo #[deprecated] suporte a adição de informações como motivo da depreciação e versão, o OpenAPI não o suporta, portanto, essas informações serão ignoradas ao gerar OpenAPI.
A parte do comentário de documentação no código será extraída automaticamente para gerar OpenAPI. A primeira linha é usada para gerar summary, e toda a parte do comentário será usada para gerar description.
ToSchema
Você pode usar #[derive(ToSchema)] para definir estruturas de dados:
Você pode usar #[salvo(schema(...))] para definir configurações opcionais:
-
example = ...pode serjson!(...).json!(...)será analisado porserde_json::json!comoserde_json::Value. -
xml(...)pode ser usado para definir propriedades do objeto Xml:
ToParameters
Gera [parâmetros de caminho][path_parameters] a partir dos campos da estrutura.
Esta é a implementação #[derive] do trait [ToParameters][to_parameters].
Normalmente, os parâmetros de caminho precisam ser definidos em [#[salvo_oapi::endpoint(...parameters(...))]][path_parameters] do endpoint. No entanto, ao usar uma [struct][struct] para definir parâmetros, as etapas acima podem ser omitidas. No entanto, se você precisar fornecer uma descrição ou alterar a configuração padrão, então parâmetros de caminho de [tipos primitivos][primitive] e [String][std_string] ou parâmetros de caminho no estilo [tupla] ainda precisam ser definidos em parameters(...).
Você pode usar o atributo #[deprecated] embutido do Rust para marcar campos como obsoletos, o que será refletido na especificação OpenAPI gerada.
O atributo #[deprecated] suporta a adição de informações extras, como o motivo da depreciação ou a versão a partir da qual está obsoleto, mas o OpenAPI não o suporta. O OpenAPI suporta apenas um valor booleano para determinar se está obsoleto. Embora seja perfeitamente possível declarar uma depreciação com um motivo, como #[deprecated = "Há uma maneira melhor de fazer isso"], esse motivo não será apresentado na especificação OpenAPI.
O documento de comentário no campo da estrutura será usado como descrição do parâmetro na especificação OpenAPI gerada.
Atributos de Contêiner ToParameters para #[salvo(parameters(...))]
Os seguintes atributos podem ser usados no atributo de contêiner #[salvo(parameters(…))] da estrutura derivada de ToParameters
names(...)Define uma lista separada por vírgulas de nomes para os campos não nomeados da estrutura usados como parâmetros de caminho. Suportado apenas em estruturas não nomeadas.style = ...Define o método de serialização para todos os parâmetros, especificado por [ParameterStyle][style]. O valor padrão é baseado no atributoparameter_in.default_parameter_in = ...Define a posição padrão usada pelos parâmetros deste campo. O valor desta posição vem de [parameter::ParameterIn][in_enum]. Se este atributo não for fornecido, o padrão équery.rename_all = ...pode ser usado como uma alternativa aorename_alldoserde. Na verdade, fornece a mesma funcionalidade.
Use names para definir um nome para um único parâmetro não nomeado.
Use names para definir nomes para vários parâmetros não nomeados.
Atributos de Campo ToParameters para #[salvo(parameter(...))]
Os seguintes atributos podem ser usados em campos de estrutura #[salvo(parameter(...))]:
-
style = ...Define como os parâmetros são serializados por [ParameterStyle][style]. O valor padrão é baseado no atributoparameter_in. -
parameter_in = ...Use o valor de [parameter::ParameterIn][in_enum] para definir onde este parâmetro de campo está. Se este valor não for fornecido, o padrão équery. -
explodeDefine se deve criar um novo parparameter=valuepara cada parâmetro emobjectouarray. -
allow_reservedDefine se caracteres reservados:/?#[]@!$&'()*+,;=são permitidos no valor do parâmetro. -
example = ...pode ser uma referência de método oujson!(...). O exemplo fornecido substituirá quaisquer exemplos do tipo de parâmetro subjacente. -
value_type = ...pode ser usado para substituir o tipo padrão usado pelos campos na especificação OpenAPI. Isso é útil quando o tipo padrão não corresponde ao tipo real, por exemplo, ao usar tipos de terceiros não definidos em [ToSchema][to_schema] ou tipos [primitivos][primitive]. O valor pode ser qualquer tipo Rust que possa ser serializado para JSON em circunstâncias normais, ou um tipo personalizado como _Object_._Object`_ que será renderizado como um objeto OpenAPI genérico. -
inlineSe habilitado, a definição deste tipo de campo deve vir de [ToSchema][to_schema], e esta definição será embutida. -
default = ...pode ser uma referência de método oujson!(...). -
format = ...pode ser uma variante do enum [KnownFormat][known_format], ou um valor aberto na forma de string. Por padrão, o formato é inferido do tipo do atributo de acordo com a especificação OpenApi. -
write_onlyDefine que o atributo é usado apenas para operações de escrita POST,PUT,PATCH e não GET. -
read_onlyDefine que o atributo é usado apenas para operações de leitura GET e não POST,PUT,PATCH. -
nullableDefine se o atributo pode sernull(note que isso é diferente de não obrigatório). -
required = ...é usado para forçar o parâmetro a ser obrigatório. Veja as regras. -
rename = ...pode ser usado como uma alternativa aorenamedoserde. Na verdade, fornece a mesma funcionalidade. -
multiple_of = ...é usado para definir um múltiplo do valor. O valor do parâmetro é considerado válido apenas quando o valor do parâmetro é dividido pelo valor desta palavra-chave e o resultado é um inteiro. O valor múltiplo deve ser estritamente maior que0. -
maximum = ...é usado para definir o limite superior do valor, incluindo o valor atual. -
minimum = ...é usado para definir o limite inferior do valor, incluindo o valor atual. -
exclusive_maximum = ...é usado para definir o limite superior do valor, excluindo o valor atual. -
exclusive_minimum = ...é usado para definir o limite inferior do valor, excluindo o valor atual. -
max_length = ...é usado para definir o comprimento máximo de um valor do tipostring. -
min_length = ...é usado para definir o comprimento mínimo de um valor do tipostring. -
pattern = ...é usado para definir uma expressão regular válida que o valor do campo deve corresponder. A expressão regular adota a versão ECMA-262. -
max_items = ...pode ser usado para definir o número máximo de itens permitidos em um campo do tipoarray. O valor deve ser um inteiro não negativo. -
min_items = ...pode ser usado para definir o número mínimo de itens permitidos em um campo do tipoarray. O valor deve ser um inteiro não negativo. -
with_schema = ...usa uma referência de função para criar umschemaem vez doschemapadrão. A função deve satisfazer a definiçãofn() -> Into<RefOr<Schema>>. Ela não recebe nenhum parâmetro e deve retornar qualquer valor que possa ser convertido emRefOr<Schema>. -
additional_properties = ...é usado para definir tipos de forma livre paramap, comoHashMapeBTreeMap. Tipos de forma livre permitem que qualquer tipo seja usado nos valores do mapa. Os formatos suportados sãoadditional_propertieseadditional_properties = true.
Regras de nulidade e obrigatoriedade de campos
Algumas das regras para nulidade e obrigatoriedade de atributos de campo ToParameters também podem ser usadas para atributos de campo ToSchema. Veja as regras.
Suporte parcial a atributos #[serde(...)]
A derivação ToParameters atualmente suporta alguns [atributos serde][serde attributes]. Esses atributos suportados serão refletidos na documentação OpenAPI gerada. Os seguintes atributos são atualmente suportados:
rename_all = "..."é suportado no nível do contêiner.rename = "..."é apenas suportado no nível do campo.defaulté suportado no nível do contêiner e do campo de acordo com [atributos serde][serde attributes].