Génération de Documentation OpenAPI
OpenAPI est une spécification open source pour décrire la conception d'interfaces d'API RESTful. Il définit les structures de requête et de réponse de l'API, les paramètres, les types de retour, les codes d'erreur et autres détails au format JSON ou YAML, rendant la communication entre le client et le serveur plus explicite et standardisée.
OpenAPI était à l'origine la version open source de la spécification Swagger et est désormais devenu un projet indépendant soutenu par de nombreuses grandes entreprises et développeurs. L'utilisation de la spécification OpenAPI aide les équipes de développement à mieux collaborer, à réduire les coûts de communication et à améliorer l'efficacité du développement. De plus, OpenAPI fournit aux développeurs des outils pour générer automatiquement la documentation d'API, des données fictives (mock) et des cas de test, facilitant ainsi les travaux de développement et de test.
Salvo fournit une intégration OpenAPI (modifiée à partir de utoipa). Salvo extrait élégamment et automatiquement les informations pertinentes sur les types de données OpenAPI à partir du Handler en fonction de ses propres caractéristiques. Salvo intègre également plusieurs interfaces OpenAPI open source populaires telles que SwaggerUI, Scalar, RapiDoc et ReDoc.
Étant donné que les noms de types Rust peuvent être longs et pas toujours adaptés à l'utilisation OpenAPI, salvo-oapi fournit le type Namer, qui permet de personnaliser les règles pour modifier les noms de types dans OpenAPI selon les besoins.
Exemple de Code
Entrez http://localhost:8698/swagger-ui dans votre navigateur pour voir la page Swagger UI.
L'intégration OpenAPI dans Salvo est assez élégante. Pour l'exemple ci-dessus, comparé à un projet Salvo normal, nous avons simplement effectué les étapes suivantes :
-
Activer la fonctionnalité
oapidansCargo.toml:salvo = { workspace = true, features = ["oapi"] }; -
Remplacer
#[handler]par#[endpoint]; -
Utiliser
name: QueryParam<String, false>pour obtenir la valeur de la chaîne de requête. Lorsque vous visitezhttp://localhost/hello?name=chris, la chaîne de requêtenamesera analysée. LefalsedansQueryParam<String, false>signifie que ce paramètre est facultatif. Si vous visitezhttp://localhost/hello, cela ne générera pas d'erreur. À l'inverse, s'il s'agit deQueryParam<String, true>, cela signifie que ce paramètre doit être fourni, sinon une erreur sera retournée. -
Créer
OpenAPIet leRoutercorrespondant. Lemerge_routerdansOpenApi::new("test api", "0.0.1").merge_router(&router)signifie que cetOpenAPIobtient les informations documentaires nécessaires en analysant une certaine route et ses sous-routes. CertainsHandlerde routes peuvent ne pas fournir d'informations pour générer des documents, et ces routes seront ignorées, comme lesHandlerdéfinis à l'aide de la macro#[handler]au lieu de la macro#[endpoint]. Autrement dit, dans des projets réels, pour des raisons telles que l'avancement du développement, vous pouvez choisir de ne pas générer de documents OpenAPI, ou de générer partiellement des documents OpenAPI. Par la suite, vous pouvez augmenter progressivement le nombre d'interfaces OpenAPI générées, et tout ce que vous avez à faire est de changer#[handler]en#[endpoint]et de modifier la signature de la fonction.
Extracteurs de Données
Vous pouvez importer des extracteurs de données communs prédéfinis via use salvo::oapi::extract::*;. L'extracteur fournira certaines informations nécessaires à Salvo afin que Salvo puisse générer des documents OpenAPI.
-
QueryParam<T, const REQUIRED: bool>: Un extracteur pour extraire des données des chaînes de requête.QueryParam<T, false>signifie que ce paramètre n'est pas requis et peut être omis.QueryParam<T, true>signifie que ce paramètre est requis et ne peut être omis. S'il n'est pas fourni, une erreur sera retournée ; -
HeaderParam<T, const REQUIRED: bool>: Un extracteur pour extraire des données de l'en-tête de la requête.HeaderParam<T, false>signifie que ce paramètre n'est pas requis et peut être omis.HeaderParam<T, true>signifie que ce paramètre est requis et ne peut être omis. S'il n'est pas fourni, une erreur sera retournée ; -
CookieParam<T, const REQUIRED: bool>: Un extracteur pour extraire des données du cookie de la requête.CookieParam<T, false>signifie que ce paramètre n'est pas requis et peut être omis.CookieParam<T, true>signifie que ce paramètre est requis et ne peut être omis. S'il n'est pas fourni, une erreur sera retournée ; -
PathParam<T>: Un extracteur pour extraire les paramètres de chemin de l'URL de la requête. Si ce paramètre n'existe pas, la correspondance de route ne réussira pas, donc il n'y a pas de cas où il peut être omis ; -
FormBody<T>: Extrait les informations du formulaire soumis par la requête ; -
JsonBody<T>: Extrait les informations de la charge utile au format JSON soumise par la requête ;
#[endpoint]
Lors de la génération de documents OpenAPI, vous devez utiliser la macro #[endpoint] au lieu de la macro #[handler] habituelle. Il s'agit en réalité d'une version améliorée de la macro #[handler].
-
Elle peut obtenir les informations nécessaires à la génération d'OpenAPI via la signature de la fonction ;
-
Pour les informations qu'il n'est pas pratique de fournir via la signature, vous pouvez les fournir directement en ajoutant des attributs dans la macro
#[endpoint]. Les informations fournies de cette manière seront fusionnées avec les informations obtenues via la signature de la fonction. En cas de conflit, elles écraseront les informations fournies par la signature de la fonction.
Vous pouvez utiliser l'attribut intégré #[deprecated] de Rust pour marquer un Handler comme obsolète. Bien que l'attribut #[deprecated] prenne en charge l'ajout d'informations telles que la raison de la dépréciation et la version, OpenAPI ne le prend pas en charge, donc ces informations seront ignorées lors de la génération d'OpenAPI.
La partie commentaire de documentation dans le code sera automatiquement extraite pour générer OpenAPI. La première ligne est utilisée pour générer le summary, et l'ensemble de la partie commentaire sera utilisé pour générer la description.
ToSchema
Vous pouvez utiliser #[derive(ToSchema)] pour définir des structures de données :
Vous pouvez utiliser #[salvo(schema(...))] pour définir des paramètres optionnels :
-
example = ...peut êtrejson!(...).json!(...)sera analysé parserde_json::json!commeserde_json::Value. -
xml(...)peut être utilisé pour définir les propriétés de l'objet Xml :
ToParameters
Génère les [paramètres de chemin][path_parameters] à partir des champs de la structure.
Ceci est l'implémentation #[derive] du trait [ToParameters][to_parameters].
Habituellement, les paramètres de chemin doivent être définis dans [#[salvo_oapi::endpoint(...parameters(...))]][path_parameters] du point de terminaison. Cependant, lors de l'utilisation d'une [struct][struct] pour définir les paramètres, les étapes ci-dessus peuvent être omises. Néanmoins, si vous devez donner une description ou modifier la configuration par défaut, alors les paramètres de chemin de [types primitifs][primitive] et de [String][std_string] ou les paramètres de chemin de style [tuple] doivent toujours être définis dans parameters(...).
Vous pouvez utiliser l'attribut intégré #[deprecated] de Rust pour marquer les champs comme obsolètes, ce qui sera reflété dans la spécification OpenAPI générée.
L'attribut #[deprecated] prend en charge l'ajout d'informations supplémentaires telles que la raison de la dépréciation ou la version à partir de laquelle elle est dépréciée, mais OpenAPI ne le prend pas en charge. OpenAPI ne prend en charge qu'une valeur booléenne pour déterminer si quelque chose est déprécié. Bien qu'il soit parfaitement possible de déclarer une dépréciation avec une raison, comme #[deprecated = "Il existe une meilleure façon de faire cela"], cette raison ne sera pas présentée dans la spécification OpenAPI.
Le commentaire de documentation sur le champ de la structure sera utilisé comme description du paramètre dans la spécification OpenAPI générée.
Attributs de Conteneur ToParameters pour #[salvo(parameters(...))]
Les attributs suivants peuvent être utilisés dans l'attribut de conteneur #[salvo(parameters(…))] de la structure dérivée de ToParameters
names(...)Définit une liste de noms séparés par des virgules pour les champs non nommés de la structure utilisés comme paramètres de chemin. Pris en charge uniquement sur les structures non nommées.style = ...Définit la méthode de sérialisation pour tous les paramètres, spécifiée par [ParameterStyle][style]. La valeur par défaut est basée sur l'attributparameter_in.default_parameter_in = ...Définit la position par défaut utilisée par les paramètres de ce champ. La valeur de cette position provient de [parameter::ParameterIn][in_enum]. Si cet attribut n'est pas fourni, la valeur par défaut estquery.rename_all = ...peut être utilisé comme alternative aurename_alldeserde. Il fournit en réalité la même fonctionnalité.
Utilisez names pour définir un nom pour un seul paramètre non nommé.
Utilisez names pour définir des noms pour plusieurs paramètres non nommés.
Attributs de Champ ToParameters pour #[salvo(parameter(...))]
Les attributs suivants peuvent être utilisés sur les champs de structure #[salvo(parameter(...))] :
-
style = ...Définit comment les paramètres sont sérialisés par [ParameterStyle][style]. La valeur par défaut est basée sur l'attributparameter_in. -
parameter_in = ...Utilise la valeur de [parameter::ParameterIn][in_enum] pour définir où se trouve ce paramètre de champ. Si cette valeur n'est pas fournie, la valeur par défaut estquery. -
explodeDéfinit s'il faut créer une nouvelle paireparameter=valeurpour chaque paramètre dans unobjetou untableau. -
allow_reservedDéfinit si les caractères réservés:/?#[]@!$&'()*+,;=sont autorisés dans la valeur du paramètre. -
example = ...peut être une référence de méthode oujson!(...). L'exemple donné écrasera tout exemple du type de paramètre sous-jacent. -
value_type = ...peut être utilisé pour remplacer le type par défaut utilisé par les champs dans la spécification OpenAPI. Ceci est utile lorsque le type par défaut ne correspond pas au type réel, par exemple, lors de l'utilisation de types tiers non définis dans [ToSchema][to_schema] ou des types [primitifs][primitive]. La valeur peut être n'importe quel type Rust pouvant être sérialisé en JSON dans des circonstances normales, ou un type personnalisé comme _Object_._Object`_ qui sera rendu comme un objet OpenAPI générique. -
inlineSi activé, la définition de ce type de champ doit provenir de [ToSchema][to_schema], et cette définition sera intégrée en ligne. -
default = ...peut être une référence de méthode oujson!(...). -
format = ...peut être une variante de l'énumération [KnownFormat][known_format], ou une valeur ouverte sous forme de chaîne. Par défaut, le format est déduit du type de l'attribut selon la spécification OpenApi. -
write_onlyDéfinit que l'attribut est uniquement utilisé pour les opérations d'écriture POST, PUT, PATCH et non pour GET. -
read_onlyDéfinit que l'attribut est uniquement utilisé pour les opérations de lecture GET et non pour POST, PUT, PATCH. -
nullableDéfinit si l'attribut peut êtrenull(notez que ceci est différent de non requis). -
required = ...est utilisé pour forcer le paramètre à être requis. Voir les règles. -
rename = ...peut être utilisé comme alternative aurenamedeserde. Il fournit en réalité la même fonctionnalité. -
multiple_of = ...est utilisé pour définir un multiple de la valeur. La valeur du paramètre est considérée comme valide uniquement lorsque la valeur du paramètre est divisée par la valeur de ce mot-clé et que le résultat est un entier. La valeur multiple doit être strictement supérieure à0. -
maximum = ...est utilisé pour définir la limite supérieure de la valeur, y compris la valeur actuelle. -
minimum = ...est utilisé pour définir la limite inférieure de la valeur, y compris la valeur actuelle. -
exclusive_maximum = ...est utilisé pour définir la limite supérieure de la valeur, à l'exclusion de la valeur actuelle. -
exclusive_minimum = ...est utilisé pour définir la limite inférieure de la valeur, à l'exclusion de la valeur actuelle. -
max_length = ...est utilisé pour définir la longueur maximale d'une valeur de typestring. -
min_length = ...est utilisé pour définir la longueur minimale d'une valeur de typestring. -
pattern = ...est utilisé pour définir une expression régulière valide à laquelle la valeur du champ doit correspondre. L'expression régulière adopte la version ECMA-262. -
max_items = ...peut être utilisé pour définir le nombre maximum d'éléments autorisés dans un champ de typearray. La valeur doit être un entier non négatif. -
min_items = ...peut être utilisé pour définir le nombre minimum d'éléments autorisés dans un champ de typearray. La valeur doit être un entier non négatif. -
with_schema = ...utilise une référence de fonction pour créer unschémaau lieu duschémapar défaut. La fonction doit satisfaire la définitionfn() -> Into<RefOr<Schema>>. Elle ne reçoit aucun paramètre et doit retourner n'importe quelle valeur pouvant être convertie enRefOr<Schema>. -
additional_properties = ...est utilisé pour définir des types de forme libre pourmap, tels queHashMapetBTreeMap. Les types de forme libre permettent d'utiliser n'importe quel type dans les valeurs de la map. Les formats pris en charge sont _additional_properties