Generación de Documentación OpenAPI
OpenAPI es una especificación de código abierto para describir el diseño de interfaces de API RESTful. Define las estructuras de solicitud y respuesta de la API, parámetros, tipos de retorno, códigos de error y otros detalles en formato JSON o YAML, haciendo que la comunicación entre cliente y servidor sea más explícita y estandarizada.
OpenAPI originalmente era la versión de código abierto de la especificación Swagger y ahora se ha convertido en un proyecto independiente respaldado por muchas grandes empresas y desarrolladores. Usar la especificación OpenAPI ayuda a los equipos de desarrollo a colaborar mejor, reducir costos de comunicación y mejorar la eficiencia del desarrollo. Además, OpenAPI proporciona a los desarrolladores herramientas para generar automáticamente documentación de API, datos simulados y casos de prueba, facilitando el trabajo de desarrollo y pruebas.
Salvo proporciona integración con OpenAPI (modificado desde utoipa). Salvo extrae elegantemente automáticamente la información relevante de tipos de datos de OpenAPI desde Handler basándose en sus propias características. Salvo también integra varias interfaces OpenAPI de código abierto populares como SwaggerUI, Scalar, RapiDoc y ReDoc.
Dado que los nombres de tipos en Rust pueden ser largos y no siempre adecuados para el uso en OpenAPI, salvo-oapi proporciona el tipo Namer, que permite personalizar reglas para cambiar los nombres de tipos en OpenAPI según sea necesario.
Código de Ejemplo
Ingresa http://localhost:8698/swagger-ui en tu navegador para ver la página de Swagger UI.
La integración de OpenAPI en Salvo es bastante elegante. Para el ejemplo anterior, en comparación con un proyecto normal de Salvo, solo hicimos los siguientes pasos:
-
Habilitar la característica
oapienCargo.toml:salvo = { workspace = true, features = ["oapi"] }; -
Reemplazar
#[handler]con#[endpoint]; -
Usar
name: QueryParam<String, false>para obtener el valor de la cadena de consulta. Cuando visitashttp://localhost/hello?name=chris, la cadena de consultanameserá analizada. ElfalseenQueryParam<String, false>significa que este parámetro es opcional. Si visitashttp://localhost/hello, no dará error. Por el contrario, si esQueryParam<String, true>, significa que este parámetro debe ser proporcionado, de lo contrario se devolverá un error. -
Crear
OpenAPIy el correspondienteRouter. Elmerge_routerenOpenApi::new("test api", "0.0.1").merge_router(&router)significa que esteOpenAPIobtiene la información documental necesaria analizando una determinada ruta y sus subrutas. AlgunosHandlers de rutas pueden no proporcionar información para generar documentos, y estas rutas serán ignoradas, como losHandlers definidos usando la macro#[handler]en lugar de la macro#[endpoint]. Es decir, en proyectos reales, por razones como el progreso del desarrollo, puedes elegir no generar documentos OpenAPI, o generarlos parcialmente. Posteriormente, puedes aumentar gradualmente la cantidad de interfaces OpenAPI generadas, y todo lo que necesitas hacer es cambiar#[handler]por#[endpoint]y modificar la firma de la función.
Extractores de Datos
Puedes importar extractores de datos comunes predefinidos a través de use salvo::oapi::extract::*;. El extractor proporcionará a Salvo alguna información necesaria para que Salvo pueda generar documentos OpenAPI.
-
QueryParam<T, const REQUIRED: bool>: Un extractor para extraer datos de cadenas de consulta.QueryParam<T, false>significa que este parámetro no es obligatorio y puede omitirse.QueryParam<T, true>significa que este parámetro es obligatorio y no puede omitirse. Si no se proporciona, se devolverá un error; -
HeaderParam<T, const REQUIRED: bool>: Un extractor para extraer datos del encabezado de la solicitud.HeaderParam<T, false>significa que este parámetro no es obligatorio y puede omitirse.HeaderParam<T, true>significa que este parámetro es obligatorio y no puede omitirse. Si no se proporciona, se devolverá un error; -
CookieParam<T, const REQUIRED: bool>: Un extractor para extraer datos de la cookie de la solicitud.CookieParam<T, false>significa que este parámetro no es obligatorio y puede omitirse.CookieParam<T, true>significa que este parámetro es obligatorio y no puede omitirse. Si no se proporciona, se devolverá un error; -
PathParam<T>: Un extractor para extraer parámetros de ruta de la URL de la solicitud. Si este parámetro no existe, la coincidencia de ruta no será exitosa, por lo que no hay caso en que pueda omitirse; -
FormBody<T>: Extrae información del formulario enviado en la solicitud; -
JsonBody<T>: Extrae información del payload en formato JSON enviado por la solicitud;
#[endpoint]
Al generar documentos OpenAPI, necesitas usar la macro #[endpoint] en lugar de la macro regular #[handler]. En realidad, es una versión mejorada de la macro #[handler].
-
Puede obtener la información necesaria para generar OpenAPI a través de la firma de la función;
-
Para información que no sea conveniente proporcionar a través de la firma, puedes proporcionarla directamente agregando atributos en la macro
#[endpoint]. La información proporcionada de esta manera se fusionará con la información obtenida a través de la firma de la función. Si hay un conflicto, sobrescribirá la información proporcionada por la firma de la función.
Puedes usar el atributo incorporado de Rust #[deprecated] para marcar un Handler como obsoleto. Aunque el atributo #[deprecated] admite agregar información como la razón de la depreciación y la versión, OpenAPI no lo admite, por lo que esta información será ignorada al generar OpenAPI.
La parte del comentario de documentación en el código se extraerá automáticamente para generar OpenAPI. La primera línea se usa para generar summary, y toda la parte del comentario se usará para generar description.
ToSchema
Puedes usar #[derive(ToSchema)] para definir estructuras de datos:
Puedes usar #[salvo(schema(...))] para definir configuraciones opcionales:
-
example = ...puede serjson!(...).json!(...)será analizado porserde_json::json!comoserde_json::Value. -
xml(...)se puede usar para definir propiedades de objetos Xml:
ToParameters
Genera [parámetros de ruta][path_parameters] a partir de los campos de la estructura.
Esta es la implementación #[derive] del rasgo [ToParameters][to_parameters].
Normalmente, los parámetros de ruta deben definirse en [#[salvo_oapi::endpoint(...parameters(...))]][path_parameters] del endpoint. Sin embargo, al usar una [struct][struct] para definir parámetros, se pueden omitir los pasos anteriores. No obstante, si necesitas dar una descripción o cambiar la configuración predeterminada, entonces los parámetros de ruta de [tipos primitivos][primitive] y [String][std_string] o los parámetros de ruta de estilo [tupla] aún deben definirse en parameters(...).
Puedes usar el atributo incorporado de Rust #[deprecated] para marcar campos como obsoletos, lo que se reflejará en la especificación OpenAPI generada.
El atributo #[deprecated] admite agregar información adicional como la razón de la depreciación o la versión desde la cual está obsoleto, pero OpenAPI no lo admite. OpenAPI solo admite un valor booleano para determinar si está obsoleto. Aunque es perfectamente posible declarar una depreciación con una razón, como #[deprecated = "Hay una mejor manera de hacer esto"], esta razón no se presentará en la especificación OpenAPI.
El documento de comentario en el campo de la estructura se usará como la descripción del parámetro en la especificación OpenAPI generada.
Atributos de Contenedor ToParameters para #[salvo(parameters(...))]
Los siguientes atributos se pueden usar en el atributo de contenedor #[salvo(parameters(…))] de la estructura derivada de ToParameters
names(...)Define una lista separada por comas de nombres para los campos sin nombre de la estructura utilizados como parámetros de ruta. Solo se admite en estructuras sin nombre.style = ...Define el método de serialización para todos los parámetros, especificado por [ParameterStyle][style]. El valor predeterminado se basa en el atributoparameter_in.default_parameter_in = ...Define la posición predeterminada utilizada por los parámetros de este campo. El valor de esta posición proviene de [parameter::ParameterIn][in_enum]. Si no se proporciona este atributo, el predeterminado esquery.rename_all = ...Se puede usar como alternativa arename_alldeserde. En realidad, proporciona la misma funcionalidad.
Usa names para definir un nombre para un solo parámetro sin nombre.
Usa names para definir nombres para múltiples parámetros sin nombre.
Atributos de Campo ToParameters para #[salvo(parameter(...))]
Los siguientes atributos se pueden usar en los campos de estructura #[salvo(parameter(...))]:
-
style = ...Define cómo se serializan los parámetros mediante [ParameterStyle][style]. El valor predeterminado se basa en el atributoparameter_in. -
parameter_in = ...Usa el valor de [parameter::ParameterIn][in_enum] para definir dónde está este parámetro de campo. Si no se proporciona este valor, el predeterminado esquery. -
explodeDefine si crear un nuevo parparameter=valuepara cada parámetro enobjectoarray. -
allow_reservedDefine si se permiten caracteres reservados:/?#[]@!$&'()*+,;=en el valor del parámetro. -
example = ...Puede ser una referencia a un método ojson!(...). El ejemplo dado anulará cualquier ejemplo del tipo de parámetro subyacente. -
value_type = ...Se puede usar para anular el tipo predeterminado utilizado por los campos en la especificación OpenAPI. Esto es útil cuando el tipo predeterminado no corresponde al tipo real, por ejemplo, cuando se usan tipos de terceros no definidos en [ToSchema][to_schema] o tipos [primitivos][primitive]. El valor puede ser cualquier tipo de Rust que pueda serializarse a JSON en circunstancias normales, o un tipo personalizado como _Object_._Object`_ que se representará como un objeto genérico de OpenAPI. -
inlineSi está habilitado, la definición de este tipo de campo debe provenir de [ToSchema][to_schema], y esta definición se incluirá en línea. -
default = ...Puede ser una referencia a un método ojson!(...). -
format = ...Puede ser una variante de la enumeración [KnownFormat][known_format], o un valor abierto en forma de cadena. Por defecto, el formato se infiere del tipo del atributo según la especificación OpenApi. -
write_onlyDefine que el atributo solo se usa para operaciones de escritura POST,PUT,PATCH y no para GET. -
read_onlyDefine que el atributo solo se usa para operaciones de lectura GET y no para POST,PUT,PATCH. -
nullableDefine si el atributo puede sernull(nota que esto es diferente de no requerido). -
required = ...Se usa para forzar que el parámetro sea obligatorio. Ver reglas. -
rename = ...Se puede usar como alternativa arenamedeserde. En realidad, proporciona la misma funcionalidad. -
multiple_of = ...Se usa para definir un múltiplo del valor. El valor del parámetro se considera válido solo cuando el valor del parámetro se divide por el valor de esta palabra clave y el resultado es un número entero. El valor múltiple debe ser estrictamente mayor que0. -
maximum = ...Se usa para definir el límite superior del valor, incluido el valor actual. -
minimum = ...Se usa para definir el límite inferior del valor, incluido el valor actual. -
exclusive_maximum = ...Se usa para definir el límite superior del valor, excluyendo el valor actual. -
exclusive_minimum = ...Se usa para definir el límite inferior del valor, excluyendo el valor actual. -
max_length = ...Se usa para definir la longitud máxima de un valor de tipostring. -
min_length = ...Se usa para definir la longitud mínima de un valor de tipostring. -
pattern = ...Se usa para definir una expresión regular válida que el valor del campo debe coincidir. La expresión regular adopta la versión ECMA-262. -
max_items = ...Se puede usar para definir el número máximo de elementos permitidos en un campo de tipoarray. El valor debe ser un número entero no negativo. -
min_items = ...Se puede usar para definir el número mínimo de elementos permitidos en un campo de tipoarray. El valor debe ser un número entero no negativo. -
with_schema = ...Usa una referencia de función para crear unschemaen lugar delschemapredeterminado. La función debe satisfacer la definiciónfn() -> Into<RefOr<Schema>>. No recibe ningún parámetro y debe devolver cualquier valor que pueda convertirse enRefOr<Schema>. -
additional_properties = ...Se usa para definir tipos de forma libre paramap, comoHashMapyBTreeMap. Los tipos de forma libre permiten que cualquier tipo se use en los valores del mapa. Los formatos admitidos sonadditional_propertiesyadditional_properties = true.
Reglas de nulabilidad y obligatoriedad de campos
Algunas de las reglas para los atributos de nulabilidad y obligatoriedad de campos de ToParameters también se pueden usar para atributos de campo de ToSchema. Ver reglas.
Soporte parcial de atributos #[serde(...)]
La derivación ToParameters actualmente admite algunos [atributos serde][serde attributes]. Estos atributos admitidos se reflejarán en la documentación OpenAPI generada. Actualmente se admiten los siguientes atributos:
rename_all = "..."se admite a nivel de contenedor.rename = "..."se admite solo a nivel de campo.defaultse admite a nivel de contenedor y campo según [atributos serde][serde attributes].skip_serializing_if = "..."se admite solo a nivel de campo.with = ...se admite solo a nivel de campo.skip_serializing = "..."se admite solo a