Les web services de l'Inist

.vscode chore: Set vscode markdownlint options 5 months ago
address-kit docs(address-kit): Use a lodex-workers-python@4.0.11 2 months ago
affiliation-rnsr feat(affiliation-rnsr): Add swagger.json 2 months ago
affiliations-tools use domain to ensure the proxy is not used 3 months ago
ark-tools use domain to ensure the proxy is not used 3 months ago
authors-tools use domain to ensure the proxy is not used 3 months ago
base-line change server 3 months ago
base-line-nodejs fix: Fix swagger's duplicated operationId 8 months ago
base-line-python fix: Fix swagger's duplicated operationId 8 months ago
biblio-tools use domain to ensure the proxy is not used 3 months ago
bin add prometheus 3 months ago
co-deduplicate new automatic publishing system 3 months ago
data-computer data-computer@1.1.0 2 months ago
data-wrapper use domain to ensure the proxy is not used 3 months ago
domains-classifier 003 1 year ago
geo-tagger feat(get-tagger): create astroTagger 2 months ago
hal-classifier use domain to ensure the proxy is not used 3 months ago
kos2vec new automatic publishing system 3 months ago
loterre-resolvers loterre-resolvers@6.2.3 2 months ago
loterre-xslt/ v1 add WS to register all concepts of a collection with ARK identifers 2 years ago
mapping-tools use domain to ensure the proxy is not used 3 months ago
nlp-tools use domain to ensure the proxy is not used 3 months ago
nlp-tools2 use domain to ensure the proxy is not used 3 months ago
pdf-tools use domain to ensure the proxy is not used 3 months ago
terms-extraction use domain to ensure the proxy is not used 3 months ago
www-home new automatic publishing system 3 months ago
.gitignore feat(affiliation-rnsr): Add swagger.json 2 months ago
.npmignore import loterre resolver 2 years ago
.npmrc import loterre resolver 2 years ago
CHANGELOG.md add changelog 2 years ago
Makefile new automatic publishing system 3 months ago
README.md feat(affiliation-rnsr): Add swagger.json 2 months ago
address-kit-conf.json build(address-kit): Fix ezs/basics version in conf 2 months ago
docker-compose.yml Update: Update lodex-workers python and lodex-workers versions 8 months ago
loterre-resolvers-conf.json last config 5 months ago
package.json 2.1.0 4 months ago
pdf-tools-conf.json prototype 5 months ago
README.md

Les web services TDM de l'Inist

Web services en Python

Créer un web service en Python consiste à créer un script Python capable de traiter un fichier JSON fourni via l'entrée standard (sdtin) et de produire un fichier JSON similaire dans la sortie standard (stdout).

Exemple de fichier python

#!/usr/bin/python3
import sys
import json

for line in sys.stdin:
   data = json.loads(line)
   data['value'] = data['value'].upper() # YOUR STATEMENT HERE
   sys.stdout.write(json.dumps(data))
   sys.stdout.write('\n')

Pour transformer un programme Python en web service, il est nécessaire de déclarer un point d’entrée (entrypoint) via la création d’un fichier .ini dans une arborescence spécifique (cf . Convention de nommage).

Ce fichier contiendra la documentation au format OpenAPI, et une référence au fichier python a exécuter.

NB : Pensez à vérifier les permissions d'éxecution du fichier python. Pour rendre un fichier python éxecutable : chmod +x nom-du-fichier.py

Exemple de fichier .ini

# OpenAPI Documentation - JSON format (dot notation)
mimeType = application/json

post.responses.default.description = Return all objects with enrich fields
post.responses.default.content.application/json.schema.$ref =  #/components/schemas/JSONStream
post.summary = Enrich one field of each Object with a Python function
post.requestBody.required = true
post.requestBody.content.application/json.schema.$ref = #/components/schemas/JSONStream
post.parameters.0.in = query
post.parameters.0.in = query
post.parameters.0.name = indent
post.parameters.0.schema.type = boolean
post.parameters.0.description = Indent or not the JSON Result

[use]
plugin = @ezs/local
plugin = @ezs/basics
plugin = @ezs/storage
plugin = @ezs/analytics

[JSONParse]
separator = *

[expand]
path = value
size = 100

[expand/exec]
# command should be executable !
# Use absolute path
command = ./v1/strings/uppercase.py

[dump]
indent = env('indent', false)

L'installation de paquet Python spécifique est possible en déclarant les paquets à installer à la racine de son web service dans un ficher requirements.txt.

Exemple de fichier requirements.txt

spacy==2.3.5
pytextrank==2.0.1
pycld3
en-core-web-sm @ https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-2.3.1/en_core_web_sm-2.3.1.tar.gz
fr-core-news-sm @ https://github.com/explosion/spacy-models/releases/download/fr_core_news_sm-2.3.0/fr_core_news_sm-2.3.0.tar.gz

Développer

Il est possible de tester localement (sur son poste) son webservice, dans un environnement identique à celui de production, pour cela :

en Python

make python ./mon_repertoire

en NodeJS

make nodejs ./base-line
# ou
cd base-line && ezs -v -d .

Ensuite, le webservice est accessible à cette adresse http://localhost:31976.

WARNING: Docker modifie le propriétaire des fichiers. Pour restaurer les permissions:

make reset

Tester

Des exemples de requêtes sont disponibles dans des fichers examples.http.
Ceux-ci peuvent être utilisés directement dans VSCode, avec l'extension REST Client (humao.rest-client).
Ils peuvent également être lancés en ligne de commande via rest-cli ou via dot-http.

Exemple 1 : lancement des exemples sans affichage

$ restcli  ./biblio-tools/examples.http
examples:1 [1] POST https://biblio-tools.services.inist.fr/v1/unpaywall/is_oa?indent=true
examples:2 [1] POST https://biblio-tools.services.inist.fr/v1/crossref/prefixes/expand?indent=true

Exemple 2 : lancement des exemples avec affichage

$ restcli --full  ./affiliations-libpostal/examples.http
examples:1 [1] POST https://affiliations-libpostal.services.inist.fr/v1/parse?indent=true
POST https://affiliations-libpostal.services.inist.fr/v1/parse?indent=true
Content-Type: application/json

[
    {
        "value": "Barboncino 781 Franklin Ave, Crown Heights, Brooklyn, NY 11238"
    }
]

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Connection: close
Content-Disposition: inline
Content-Encoding: gzip
Content-Type: application/octet-stream
Date: Fri, 23 Jul 2021 09:00:14 GMT
Server: nginx/1.15.10
Transfer-Encoding: chunked

[{
    "value": {
        "id": "Barboncino 781 Franklin Ave, Crown Heights, Brooklyn, NY 11238",
        "value": {
            "house": "barboncino",
            "house_number": "781",
            "road": "franklin ave",
            "suburb": "crown heights",
            "city_district": "brooklyn",
            "state": "ny",
            "postcode": "11238"
        }
    }
}]

Documenter

Documentation OpenAPI

Chaque service, chaque route, doit être documenté en respectant la norme OpenAPI 3.0 (swagger).

La documentation de chaque route doit être placée dans le fichier .ini correspondant à sa route API.

Pour placer la document openapi dans les fichiers .ini, la syntaxe Swagger au format JSON doit être convertie au format "dot notation"

Exemple :

post.responses.default.description = Return a JSON as received JSON.
post.responses.default.content.application/json.schema.$ref = #/components/schemas/anyValue
post.summary = Parse and split JSON and return it.
post.requestBody.required = true
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.
Le serveur prendra en compte tout le fichier SAUF ce qui correspond aux 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:

$ 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).

Note 3: vous pouvez nommer les exemples, en ajoutant # @name identifiant sur une ligne avant la requête (en remplaçant identifiant par une valeur unique).
Ainsi vous pouvez appeler la commande make example-metadata terms-extraction v1TeeftWithNumbersEn.

Déclarer la documentation Swagger

Le répertoire www-home contient le HTML de la page de documentation OpenAPI https://openapi.services.inist.fr.

Pour ajouter une instance dans le menu déroulant (en haut à droite), il vous suffit de la déclarer dans www-home/index.html pour qu'elle soit prise en compte.

Convention de nommage

Chaque instance sur l'ezmaster de la machine aura un nom en trois parties:

  1. texte (domaine)
  2. texte (spécialité)
  3. numéro (version)

La troisième partie du champ ne doit pas être communiquée à l'extérieur, c'est un numéro de version (si plusieurs instances ont les mêmes deux premiers champs, c'est la dernière version qui est exposée quand on n'utilise pas de numéro de version, ce qui sera le cas).

Le numéro de version permet la mise à jour de l'image docker associée au webservice.

Nom de l'instance

Les champs textuels sont obligatoirement en minuscules, et sans accent (mais peuvent contenir des chiffres) et donc de préférence en anglais. Ils ne doivent pas contenir un nom de personne.

La première partie décrit le domaine d'application du webservice. Exemple : affiliation, text, classification, nlp, etc.

La seconde partie décrit une spécialité du domaine. Cette spécificité est principalement liée à une image docker différente, comme c'est le cas si les différents web services d'un domaine utilisent des langages différents (C++, python, nodejs, etc.).

Nom des répertoires

Chaque instance donne accès à une arborescence de webservices.
Le nom de route dépend du nom des répertoires.
Les noms des répertoires doivent donc être choisis dans cette optique.

Il convient donc de respecter les pratiques communément admises dans la définition d'API de type REST.
En utilisant des noms de répertoires en minuscules, sans accent (mais pouvant contenir des chiffres) et de préférence en anglais.

Si le premier niveau caractérise obligatoirement la version, les suivants peuvent être adaptés selon le besoin.
On veillera à créer un répertoire si et seulement si il propose plusieurs sous-répertoire ou fichiers.

  1. Version des APIs (v1, v2, v3, etc.)
  2. Nom de l'algorithme ou de la ressource utilisés ou de la langue
  3. Nom de l'action ou de l'algorithme caractérisant le traitement
  4. (...)

Exemples :

  • /v1/test/analyse
  • /v2/istex/expand
  • /v1/en/stemmer/analyse

Fichier d'exemple

Chaque répertoire dédié à une instance contiendra au moins un fichier examples.http.
Ce fichier permet d'exécuter rapidement et simplement des exemples simples d'utilisation des webservices à travers VSCode ou restcli (en ligne de commande).
Le format du fichier est celui précisé dans la documentation vscode https://github.com/Huachao/vscode-restclient#usage.

Voir aussi Tester.

Créer une version

Afin de faciliter le déploiement (et de le limiter à un répertoire), on peut utiliser les helpers du Makefile (make version-major, make version-minor, make version-patch).

Ils se chargent de mettre un tag git sur répertoire et de le pousser sur le dépôt. Leur seul paramètre est le nom du répertoire.

Exemple:

$ make version-major terms-extraction
Décompte des objets: 1, fait.
Écriture des objets: 100% (1/1), 185 bytes | 185.00 KiB/s, fait.
Total 1 (delta 0), reused 0 (delta 0)
remote: Updating references: 100% (1/1)
To ssh://gitbucket.inist.fr:22222/tdm/web-services.git
 * [new tag]         terms-extraction@1.0.0 -> terms-extraction@1.0.0
Nouvelle version créée: terms-extraction@1.0.0
URL à utiliser: https://gitbucket.inist.fr/tdm/web-services/archive/terms-extraction/terms-extraction@1.0.0.zip

L'URL fournie sert à la configuration de l'instance, et permet la mise à jour du programme.

Publication d'une instance

Pour configurer Prometheus (monitoring interne) et le reverse proxy automatiquement, il faut avoir renseigné le fichier swagger.json dans le répertoire de l'instance et lancé make publish (avec le répertoire comme paramètre).

Ex de swagger.json:

{
    "info": {
        "title": "ark-tools - Génération des identifiants ARK",
        "summary": "Permet la génération d'identifiants ARK uniques et pérennes.",
        "version": "1.0.0",
        "termsOfService": "https://objectif-tdm.inist.fr/",
        "contact": {
            "name": "Inist-CNRS",
            "url": "https://www.inist.fr/nous-contacter/"
        }
    },
    "servers": [
        {
            "x-comment": "Will be automatically completed by the ezs server."
        },
        {
            "url": "http://vptdmservices.intra.inist.fr:49194/",
            "description": "Latest version for production",
            "x-profil": "Standard"
        }
    ],
    "tags": [
        {
            "name": "ark-tools",
            "description": "Génération des identifiants ARK",
            "externalDocs": {
                "description": "Plus de documentation",
                "url": "https://gitbucket.inist.fr/tdm/web-services/tree/master/ark-tools"
            }
        }
    ]
}

Champs importants: dans servers, champ url.

Lancer avec:

make publish <nom de l'instance>