diff --git a/Makefile b/Makefile index f44fcc4..c970ca1 100644 --- a/Makefile +++ b/Makefile @@ -38,3 +38,10 @@ examples: ## Launch examples for a directory, e.g. make examples mapping-tools @restcli --full "$(filter-out $@,$(MAKECMDGOALS))/examples.http" + +example-metadata: ## Give an example metadata, from examples.http, e.g. make example-metadata affiliations-tools 3 + @./bin/generate-example-metadata.mjs $(filter-out $@,$(MAKECMDGOALS)) + +# Remove error message about lacking rules for targets' parameters +%: + @: diff --git a/README.md b/README.md index 9f45680..b19e89a 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,8 @@ post.requestBody.content.application/json.schema.$ref = #/components/schemas/anyValue ``` +#### Tags + Si vous souhaitez enrichir la documentation par défaut, en ajoutant des _tags_, des components, il est possible d'ajouter un fichier standard `swagger.json` à la racine de votre instance. @@ -191,6 +193,42 @@ informations concernant les routes (qui doivent être placées dans le fichier `.ini`). +#### Exemples + +Il est très important de mettre des exemples dans la documentation OpenAPI. +Malheureusement, la syntaxe utilisée (notation pointée) pour ce faire dans les +`.ini` est très rébarbative. +Mais on peut utiliser un fichier `examples.http` placé à la racine d'une +instance et la cible make `example-metadata` pour générer ces exemples: il +exécute une requête du fichier `examples.http` et fournit les lignes en notation +pointée pour la requête et la réponse de l'exemple. + +Exemple: + +```bash +$ make example-metadata mapping-tools 0 +post.requestBody.content.application/json.example.0.id: 1 +post.requestBody.content.application/json.example.0.value: 200919362L +post.requestBody.content.application/json.example.1.id: 2 +post.requestBody.content.application/json.example.1.value: 200112440X +post.responses.default.content.application/json.example.0.id: 1 +post.responses.default.content.application/json.example.0.value: INEE +post.responses.default.content.application/json.example.1.id: 2 +post.responses.default.content.application/json.example.1.value: INS2I +``` + +Il suffit ensuite de copier-coller ces lignes en haut du `.ini`, à la fin des +métadonnées. Prenez quand même garde à ne pas mettre plusieurs `example.0` (il +existe une autre syntaxe pour mettre plusieurs exemples). + +> **Note**: pour que ce script fonctionne, il faut que node 14+ soit installé, +> et que la commande `npm install` ait été lancée à partir de la racine du +> dépôt. +> +> **Note 2**: préférez plusieurs valeurs dans le tableau de l'exemple, pour +> éviter que le script ne fasse abstraction du tableau (auquel cas il faudrait +> l'ajouter à la main dans les exemples). + ### Déclarer la documentation Swagger Le répertoire `www-home` contient le HTML de la page d'accueil diff --git a/biblio-tools/examples.http b/biblio-tools/examples.http index 5d86ef8..ec8a313 100644 --- a/biblio-tools/examples.http +++ b/biblio-tools/examples.http @@ -1,5 +1,9 @@ +# To test locally, replace with +# @baseUrl = http://localhost:31976 +@baseUrl = https://biblio-tools.services.inist.fr + # unpaywall/is_oa -POST https://biblio-tools.services.inist.fr/v1/unpaywall/is_oa?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/unpaywall/is_oa?indent=true HTTP/1.1 Content-Type: application/json [ @@ -14,7 +18,7 @@ # unpaywall/expand -POST https://biblio-tools.services.inist.fr/v1/unpaywall/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/unpaywall/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -28,7 +32,7 @@ ### # unpaywall/corhal -POST https://biblio-tools.services.inist.fr/v1/unpaywall/corhal?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/unpaywall/corhal?indent=true HTTP/1.1 Content-Type: application/json [ @@ -43,9 +47,7 @@ ### # unpaywall/works/expand -# POST http://localhost:31976/v1/unpaywall/works/expand?indent=true HTTP/1.1 - -POST https://biblio-tools.services.inist.fr/v1/unpaywall/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/unpaywall/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -60,7 +62,7 @@ ### # crossref/prefixes/1 -POST https://biblio-tools.services.inist.fr/v1/crossref/prefixes/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/crossref/prefixes/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -76,7 +78,7 @@ # crossref/works/2 -POST https://biblio-tools.services.inist.fr/v1/crossref/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/crossref/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -91,7 +93,7 @@ ### # inspirehep/works/expand -POST https://biblio-tools.services.inist.fr/v1/inspirehep/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/inspirehep/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -107,7 +109,7 @@ ### # openalex/works/expand -POST https://biblio-tools.services.inist.fr/v1/openalex/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/openalex/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -123,7 +125,7 @@ ### # istex/works/expand -POST https://biblio-tools.services.inist.fr/v1/istex/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/istex/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ @@ -135,7 +137,7 @@ ### # wos/fecth -POST http://localhost:31976/v1/wos/fetch?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/wos/fetch?indent=true HTTP/1.1 Content-Type: application/json [ @@ -165,7 +167,7 @@ ### # wos/works/expand -POST http://localhost:31976/v1/wos/works/expand?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/wos/works/expand?indent=true HTTP/1.1 Content-Type: application/json [ diff --git a/bin/generate-example-metadata.mjs b/bin/generate-example-metadata.mjs new file mode 100755 index 0000000..705d2a3 --- /dev/null +++ b/bin/generate-example-metadata.mjs @@ -0,0 +1,77 @@ +#!/usr/bin/env node + +import { RestParser } from "rest-cli"; +import flatten from "flat"; + +const usage = (errorNumber = 0) => { + console.error("Usage: ./bin/generate-example-metadata.mjs [requestName|requestNumber]"); + process.exit(errorNumber); +} + +const json2dotNotationLitteral = (j) => JSON.stringify(j) + .replace(/^"|"$/g, "") + .replace(/\\"/g, '"'); + +const json2dotNotation = ( + json, + prefix = "post.responses.default.content.application/json.example." +) => { + const flattened = flatten(json, { safe: false }); + const str = Object.keys(flattened) + .map(key => `${prefix + key}: ${json2dotNotationLitteral(flattened[key])}`) + .join("\n"); + return str; +}; + +/** @param {string} s */ +const isInteger = (s) => Number.isInteger(Number(s)); + +const content2json = (o) => { + const body = o.getBody(); + const contentType = o.headers.get("content-type"); + const json = contentType === "application/json" + ? JSON.parse(body) + : body.split("\n").slice(0, -1).map(s => s.replace(/\r/g, "")); + return json; +} + +///////////////////////////////////////////////////////////: + +const [, , instanceName, requestName] = process.argv; + +if (!instanceName) { + console.error("Instance name needed as a first paramater!"); + usage(1); +} + +// Get Response from examples.http file +const parser = new RestParser(); +await parser.readFile(`./${instanceName}/examples.http`); + +const requestId = isInteger(requestName) ? Number(requestName) : requestName; + +if (requestId === undefined) { + console.error("requestName needed as a second parameter (could be a string or an integer)."); + usage(2); +} + +const request = await parser.get(requestId); + +if (request) { + // request + const requestJSON = content2json(request); + console.log( + json2dotNotation( + requestJSON, + "post.requestBody.content.application/json.example.") + ); + + // response + const { response } = await request.request(); + + const responseJSON = content2json(response); + console.log(json2dotNotation(responseJSON)); +} else { + console.error(`Request "${requestId}" not found.`); + usage(3); +} diff --git a/mapping-tools/examples.http b/mapping-tools/examples.http index 8be92b6..77cd228 100644 --- a/mapping-tools/examples.http +++ b/mapping-tools/examples.http @@ -1,8 +1,13 @@ # Ces exemples peuvent être exécutés directement dans VSCode, en utilisant # l'extension REST Client (humao.rest-client) +# To test locally, replace with +# @baseUrl = http://localhost:31976 +@baseUrl = https://mapping-tools.services.inist.fr + +# @name v1RnsrInstitutsCnrs # Trouver l'Institut du CNRS associé à une structure de recherche -POST https://mapping-tools.services.inist.fr/v1/rnsr/instituts-cnrs/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/rnsr/instituts-cnrs/json?indent=true HTTP/1.1 Content-Type: application/json [ @@ -12,8 +17,7 @@ ### # Trouver l'idRef associé au halAuthorId (format LODEX) -POST https://mapping-tools.services.inist.fr/v1/halAuthorId/idRef/json?indent=true HTTP/1.1 -#POST http://localhost:31976/v1/halAuthorId/idRef/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/halAuthorId/idRef/json?indent=true HTTP/1.1 Content-Type: application/json [ @@ -30,8 +34,7 @@ ### # Trouver l'ORCID associé à l'IdRef (format LODEX) -POST https://mapping-tools.services.inist.fr/v1/idRef/orcid/json?indent=true HTTP/1.1 -# POST http://localhost:31976/v1/idRef/orcid/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/idRef/orcid/json?indent=true HTTP/1.1 Content-Type: application/json [ @@ -48,7 +51,7 @@ ### # Homogénéiser la forme d'une source de notice -POST https://mapping-tools.services.inist.fr/v1/homogenize/source/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/homogenize/source/json?indent=true HTTP/1.1 Content-Type: application/json [ @@ -61,7 +64,7 @@ ### # Homogénéiser la forme des éditeurs -POST https://mapping-tools.services.inist.fr/v1/homogenize/publisher/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/homogenize/publisher/json?indent=true HTTP/1.1 Content-Type: application/json [ @@ -75,7 +78,7 @@ ### # Homogénéiser les types de documents -POST https://mapping-tools.services.inist.fr/v1/homogenize/documentType/json?indent=true HTTP/1.1 +POST {{baseUrl}}/v1/homogenize/documentType/json?indent=true HTTP/1.1 Content-Type: application/json [ diff --git a/package.json b/package.json index 8f62892..c2c6b0a 100644 --- a/package.json +++ b/package.json @@ -18,5 +18,9 @@ "tdm" ], "author": "", - "license": "CECILL-2.1" + "license": "CECILL-2.1", + "devDependencies": { + "flat": "5.0.2", + "rest-cli": "1.8.13" + } }