Vue d’ensemble sur les connecteurs
Les connecteurs sont ce qui va permettre à Publik d'échanger des informations par le biais de webservices avec une application métier ou même simplement d'aller récupérer données dans un fichier tableur (CSV ou ODS).
Nous avons une liste (pas forcément très à jour, n'hésitez pas à nous contacter) des connecteurs existants.
Aller chercher des informations dans un fichier tableur est relativement aisé, vous pouvez construire une source de données et élaborer ensuite des requêtes avancées.
Enfin, il est possible de développer de nouveaux connecteurs webservices, mais la tâche est nettement plus ardue et dépend des webservices offerts par l'application en face.
Introduction
La connexion de Publik avec des systèmes tiers permet des échanges d'informations de diverse nature, à des endroits et des moments différents. Cette documentation présente les principes généraux de ces échanges, d'un point de vue technique.
Les natures, lieux et moments d'interconnexion étant nombreux dans Publik, définir un connecteur commence par une description des fonctionnalités attendues, en terme de service à rendre aux utilisateurs, qu'ils soient usagers (aspects frontoffice) ou agents (aspects backoffice).
Une fois établies ces spécifications fonctionnelles générales, on étudie comment le connecteur peut être créé : quelles seront les informations à échanger, à quel moment, où les afficher, etc. À cet instant de l'étude, il est nécessaire de disposer des éléments techniques concernant le ou les systèmes tiers, voire d'un contact avec un technicien ou un développeur chez ce tiers.
Cette documentation détaille les différentes possibilités des connexion à l'heure actuelle (bien que Publik dispose de systèmes génériques à de nombreux endroits, de nouvelles peuvent être imaginées). À la fin du document sont présentés quelques formats de connecteurs habituels pour des domaines métier déjà couverts par Publik.
Lieux et moments de connexion
Sur les portails
Comme dans de nombreux CMS, les pages sont composées de «cellule» d'informations. C'est dans ces cellules qu'il est possible d'afficher des informations provenant de systèmes tiers. On distingue principalement deux type d'informations :
- les informations générales au site, par exemple les actualités du lieu ou la liste des arrêts de bus ;
- les informations liées à l'utilisateur connecté, par exemple la liste des livres empruntés à la médiathèque, ou la liste des factures de cantine à payer.
Ces informations sont obtenues à travers des connecteurs, qui vont chercher l'information dans les logiciels tiers « en temps réel », c'est-à-dire au moment de l'affichage de la page.
À noter que Publik utilise ce principe en interne : quand un usager se connecte, on lui affiche une cellule contenant la liste de ses demandes en cours. Celles-ci sont obtenues par Combo depuis la brique w.c.s. (qui gère les démarches dans Publik).
Lors de la saisie des demandes (formulaires)
Lors de l'affichage d'un formulaire, Publik peut afficher des données provenant d'un système tiers, par exemple la liste des rues de la ville ou la liste des enfants de la famille de l'usager.
Publik va interroger le système tiers au moment de l'affichage du formulaire. Il peut récupérer des informations générales (la liste de rues) ou liées à l'usager (la liste des enfants). Cela peut aussi être des informations liées à un choix précédent dans le formulaire, par exemple la liste des associations liées au domaine du sport (ce domaine ayant été choisi par l'usager préalablement dans le formulaire).
Les informations ainsi remontées peuvent être affichées sous forme de liste de choix (système "select" en HTML). Si la liste est trop longue, Publik (w.c.s.) peut n'afficher qu'une partie de la liste en fonction des lettres tapées au clavier par l'usager ("typeahead").
Une fois que l'usager a choisi la valeur, toutes les données relatives provenant du logiciel tiers sont disponibles dans le formulaire, au même titre que les autres informations saisies librement.
Lors du traitement des demandes (workflows)
- récupérer des informations (par exemple le secteur scolaire correspondant à la rue indiquée par l'usager) ;
- récupérer un document (par exemple l'attestation de scolarité de son enfant) ;
- envoyer des informations (par exemple une demande d'inscription à la médiathèque) et récupérer le résultat (numéro de la demande dans le logiciel tiers)
- appel webservice « envoi d'une demande de badge de parking » : récupération du numéro de la demande "N" ;
- appel webservice « récupération de l'état de la demande "N" » : faire avancer la demande selon que le badge a bien été émis ou est refusé (et dans les autres cas, tenter à nouveau l'appel 12h plus tard)
Pilotage des demandes depuis un logiciel tiers
Dans le workflow de traitement d'une demande, il est également possible de configurer des déclencheurs (triggers) qui sont autant de webservices rendus disponibles à une application tierce. Celle-ci peut appeler le webservice déclencheur et Publik va alors faire avancer la demande vers le statut cible. Au passage, l'application tierce peut envoyer des données qui seront alors ajoutées au formulaire.
Ce système est notamment utilisé en interne par Publik pour gérer le paiement lié à une demande, et la faire passer d'un statut "à payer" à un statut "payé", ou "refusé" ou "annulé" selon le déclencheur appelé par le système de paiement de Publik.
Dans le code des conditions et des expressions
Dans les formulaires et dans les workflows, des conditions sont utilisables, écrites sous forme d'expressions en langage Python ou en langage de gabarits Django. À cet instant il est aussi possible de faire appel à un connecteur pour récupérer une valeur et l'inclure à la condition.
On peut ainsi, par exemple :
- sur un formulaire, décider d'afficher une page seulement si un connecteur répond "OK" ;
- sur un formulaire, refuser de passer à la page suivante tant qu'un connecteur n'accepte pas les valeur saisies sur la page actuelle ;
- dans un workflow, décider de passer dans un certain statut seulement si le connecteur a répondu une certaine valeur ;
- etc.
Lors du paiement
Aspect moins générique que les précédents, Publik dispose d'un module de paiement (nommé "lingo"). Il est connectable d'un côté avec les principaux systèmes de paiement en ligne du marché, de l'autre avec un logiciel tiers quand on doit informer ce dernier qu'un paiement a eu lieu, ou a échoué.
Lorsqu'il est connecté avec un logiciel tiers, cela permet d'informer immédiatement du paiement d'une facture ; celle-ci ne sera alors plus visible parmi la liste des factures à payer qui seront remontées depuis le même logiciel.
Géocodage et base d'adresses
Publik peut effectuer géocodage et géocodage inversé.
Plus tard dans le workflow, il est possible de (re)géolocaliser la demande en interrogeant un connecteur de géocodage, sur l'adresse indiquée par l'usager. On peut alors ensuite rappeler un géocodage inverse pour trouver l'adresse normée selon le référentiel tiers. Cela permet aussi de remonter d'autres informations liées à un SIG (Système d'Information Géographique), comme le bureau de vote ou le secteur scolaire.
Par ailleurs Publik peut utiliser une base d'adresse, typiquement la liste des rues, pour aider à la saisie. Un connecteur de type "base adresse" renvoie la liste des voies de la ville (voir plus haut les possibilités d'affichage de liste dans les formulaires).
Lors de l'authentification
Pour éviter une gestion manuelle de l'accès au backoffice, Publik peut se connecter à un annuaire LDAP (ou Active Directory). Cela permet de retrouver dans Publik l'ensemble des agents de la ville, en leur permettant d'utiliser leurs identifiant et mot de passe habituels. L'authentification est faite au moment de la connexion, et elle s'effectue en interrogeant l'annuaire (aucun code d'authentification, aucun mot de passe n'est copié sur Publik).
Il est aussi possible de fédérer les comptes de Publik avec des systèmes SSO tiers, tels que FranceConnect, un compte métropolitain ou tout autre fournisseur d'identité local, tant qu'il suit un protocole de fédération standard comme OpenID Connect ou SAML.
Single Sign On (SSO)
Nature des informations échangées
Format général
En entrée comme en sortie, les webservices de Publik utilisent des messages au format JSON (http://json.org/).
En entrée, quand il s'agit d'un GET, les éventuelles données sont dans les arguments de l'URL (query string). Quand il s'agit d'un POST, le format des données à envoyer (payload) à un webservice dépend de ce que celui-ci attend ; il s'agit en général d'un dictionnaire, simple liste de clé-valeur. Il peut également y avoir aussi des informations dans les arguments de l'URL (query string).
En sortie, sauf exception, le format est le suivant :
{
"err": 0,
"data": ...
}
Les deux clés sont obligatoires. La valeur de "err" est 0 quand il n'y a pas eu d'erreur. Dans ce cas, "data" contient les données demandées.
En cas d'erreur, "err" est différent de 0 et il peut exister deux clés "err_class" et "err_desc", qui sont respectivement la classe et une description de l'erreur :
{
"err": 1, # différent de zéro
"err_class": "TypeError", # le nom de la classe d'erreur (optionnel)
"err_desc": "name must be a string", # une description de l'erreur (optionnel)
"data": null # il peut y avoir des données
}
Référentiels
id | text
1 | rue du Château
2 | avenue du Maine
3 | place Denfert-Rochereau
GET /liste-des-rues/
{
"err": 0,
"data": [
{"id": "1", "text": "rue du Château"},
{"id": "2", "text": "avenue du Maine"},
{"id": "3", "text": "place Denfert-Rochereau"}
]
}
Dans un formulaire, c'est la liste des "text" qui est présentée à l'usager, dans l'ordre reçu. Le "id" est conservé dans les données raw du formulaire. Typiquement, si le champ a « rue » comme identifiant, alors on aura deux variables disponibles dans le formulaire : « form_var_rue » (text) et « form_var_rue_raw » (id).
Les services qui renvoient un référentiel peuvent gérer un argument "q" pour filtrer les résultats. Cela permet de présenter des formulaires où l'usager doit saisir quelques caractères pour voir les possibiltés disponibles. Par exemple :
GET /liste-des-rues/?q=eau
{
"err": 0,
"data": [
{"id": "1", "text": "rue du Château"},
{"id": "3", "text": "place Denfert-Rochereau"}
]
}
GET /liste-des-rues/
{
"err": 0,
"data": [
{"id": "1", "text": "rue du Château", "type": "rue", "arr": "14"},
{"id": "2", "text": "avenue du Maine", "type", "avenue", "arr": "14"},
{"id": "4", "text": "place de la Concorde", "type": "place", "arr": "8"}
]
}
- form_var_rue : "rue du Château"
- form_var_rue_raw : "1"
- form_var_rue_type : "rue"
- form_var_rue_arr : "14"
Géocodage (inverse)
{
...
"display_name": "169, Rue du Château, Quartier de Plaisance, Paris 14e Arrondissement, Paris, Île-de-France, France métropolitaine, 75014, France",
"address": {
"house": "169",
"road": "Rue du Château",
"suburb": "Quartier de Plaisance",
"city_district": "Paris 14e Arrondissement",
"city": "Paris",
"county": "Paris",
"state": "Île-de-France",
"country": "France",
"postcode": "75014",
"country_code": "fr"
},
...
}
Remontée d'informations génériques
GET /foo/
{
"err": 0,
"data": ... # ici un objet JSON
}
- dans une cellule du CMS Combo de type « Cellule JSON » : le résultat du webservice est envoyé au moteur de Django. Il faut écrire le gabarit correspondant (https://docs.djangoproject.com/fr/3.2/ref/templates/) pour que la cellule affiche les données selon le format désiré ;
- dans un appel webservice de traitement d'une demande : le résultat « data » est alors enregistré en tant qu'objet dans les données du formulaire. Si l'appel webservice a pour identifiant « ws » et que data contient {"cle": "valeur", "cle2": "valeur2"} alors le formulaire aura deux variables « ws_response_data_cle » ("valeur") et « ws_response_data_valeur2 » ("valeur2") ;
- au niveau de w.c.s. dans des gabarits avec la syntaxe « {{ webservice.slug_du_webservice.data.cle }} » où « slug_du_webservice » est déclaré dans les paramètres.
- https://logiciel/school/{{ form_var_school_raw }}/{% if form_var_details %}?details=on{% endif %}
RSS / Atom
Appairage avec un compte tiers
Un mécanisme important dans un portail usager est de pouvoir connecter son compte usager avec des systèmes tiers, tels que son « compte famille » ou son « compte médiathèque ».
Pour cela, on doit disposer d'un webservice permettant de relier le compte Publik, déterminé par un NameID (une chaîne de caractères aléatoires, parfois appelée « pseudonyme ») avec le compte tiers, décrit par des données d'identification et souvent d'authentification, c'est un dire en général un nom d'utilisateur, ou un numéro de dossier, et un mot de passe ou code d'accès.
L'appel au système d'appairage est effectué ainsi par Publik :
POST /link
{
"name_id": "abc123def987",
"login": "user42", # exemple de credentials ; ça pourrait être
"password": "pass" # par exemple un code d'activation unique
}
{
"err": 0, # appairage effectué
"data": "ok" # (optionnel, sans effet)
}
Remontée d'informations liées
GET /children?name_id=abc123def987
Host: logiciel-enfance
{"err": 0, "data": [{"id": "42-1", "text": "enfant1" },
{"id": "42-2", "text": "enfant2" }]}
GET /asso/informations/?name_id=abc123def987
Host: logiciel-associations
{
"err": 0,
"data": {
"nom": "April",
"siret": "...",
"adresse": {...},
"president": "..."
}
}
Dés-appairage
GET /unlink?name_id=abc123def987
{"err": 0, "data": "ok"}
Injection de données vers un logiciel tiers
POST /inscription/centre-aere?
Host: logiciel-enfance
{
"name_id": "abc123def987",
"enfant_id": "42-2",
"centre_id": "67",
"date-debut": "2018-01-01",
"date_fin": "2018-12-31"
}
{
"err": 0, # injection réussie
"data": "ok" # sans signification
}
éférentiels
Lors de l'injection vers un logiciel tiers, il peut être nécessaire de suivre les référentiels de celui-ci, par exemple la liste des centres de loisirs pour y gérer les inscriptions : le centre choisi devra être envoyé sous forme d'un identifiant connu par le logiciel tiers ("centre_id" dans l'exemple ci-dessus).
Pour cela, on aura pris soin d'utiliser au préalable un webservice de référentiels (cf supra) lors de l'affichage du choix du centre dans le formulaire présenté à l'usager.
Il est donc important de noter que dans la très grande majorité des cas, un système d'injection de données de Publik vers un tiers nécessite que ce dernier ait d'abord mis à disposition l'ensemble de ces référentiels.
Suivi des données injectées
Un cas d'usage fréquent de l'injection de données est l'injection d'une demande, validée par un agent dans Publik, vers le logiciel tiers. La demande va être traitée dans le logiciel tiers, et devra être suivie par Publik.
Pour cela, lors de l'injection, le logiciel tiers renvoie le numéro de la demande créée :
POST /demande-inscription/
{ ... }
{
"err": 0, # réponse : demande créée
"data": {
"id": "7834" # et correspondance dans le logiciel tiers
}
}
Si l'action d'appel webservice a comme identifiant "demande_inscription" alors la demande dans Publik dispose d'une variable « demande_inscription_response_data_id » égale à "7834".
Ensuite, dans le workflow, Publik est programmé pour venir interroger régulièrement (ou manuellement) une URL de suivi de cette demande, par exemple configurée à https://logiciel-scolaire/demande/[demande_inscription_response_data_id]/status. L'action d'appel du webservice sera donc :
GET /demande/7834/status
{
"err": 0,
"data": {
"status_id": "4",
"status": "instruction",
"status_long": "instruction de la demande en cours"
}
}
Pilotage d'une demande Publik par un système tiers
Dans le cas où le logiciel tiers veut directement faire avancer une demande dans Publik, la communication se déroule dans l'autre sens : c'est le logiciel tiers qui appelle un webservice mis à disposition par Publik. Ces webservices sont nommés déclencheurs (triggers) et sont paramétrés dans les workflows de traitement d'une demande, au travers des sauts automatiques (cf https://doc-publik.entrouvert.com/admin-fonctionnel/fabrique-de-workflows/les-actions-de-workflow/actions_transition-automatique/)
La demande d'un changement d'état se fait par une requête POST à l'adresse du formulaire en question, suivi de « /jump/trigger/ » et de l'identifiant du déclencheur, par exemple :
POST /inscriptions/newsletter/14/jump/trigger/validate
Host: demarches.example.net
Accept: application/json
{"err": 0, "url": null}
POST /inscriptions/newsletter/14/jump/trigger/validate
Host: demarches.example.net
Accept: application/json
Content-Type: application/json
{"donnee1": "valeur1", "donnee2": "valeur2", ... }
Paiement
Lorsqu'un logiciel dispose de factures, il les met à disposition via des webservices : Publik les affiche à l'utilisateur et lui permet de les payer en ligne. Un autre webservice disponible sur le logiciel tiers permet à Publik de l'informer des paiements effectués.
S'agissant de données liées à un usager, le système de facturation nécessite un appairage préalable, cf supra.
Liste des factures
GET /invoices/?NameID=123abc987fed
{
"err": 0,
"data": [
{
"id": "934395",
"label": "restauration août 2015",
"amount": "37.26", # note : pas de float, toujours des string
"total_amount": "37.26",
"online_payment": true,
"created": "2015-08-01T00:00:00",
"pay_limit_date": "2015-09-29T00:00:00",
"has_pdf": true, # si un PDF est disponible, cf plus bas
"paid": false,
... (autres informations si le logiciel en dispose)
},
...
],
}
Détails d'une facture — Version PDF
GET /invoice/934395/?NameID=123abd987fed
{"err": 0, "data": { ... } }
GET /invoice/934395/pdf?NameID=123abd987fed
Content-Type: application/pdf
<stream du PDF>
Paiement d'une facture
POST /invoice/934395/pay/?NameID=123abc987fed
{
"transaction_id": "<identifiant de la transaction>",
"transaction_date": "2016-01-05T12:00:00"
}
{"err": 0, "data": true}
Notification des factures à payer
Annexes sur le paiement
Autres documentations liées au paiement dans Publik :
Annuaire LDAP
Publik peut se connecter à un annuaire LDAP, généralement pour se synchroniser avec la liste des utilisateurs backoffice (agents). Les modalités de configuration sont habituelles, il faut configurer la brique Authentic de la solution avec les paramètres LDAP/ActiveDirectory cibles.
Lorsqu'un utilisateur se connecte, Publik tente de l'authentifier via LDAP. Si l'authentification réussie, le compte Publik de l'agent est alors créé ou mis à jour avec les données disponibles dans l'annuaire.
Par ailleurs, Publik vient régulièrement interroger l'annuaire pour construire la liste des comptes agents (provisionning). Cela permet d'avoir cette liste exhaustive visible dans Publik et par exemple d'attribuer les rôles aux agents sans qu'ils aient besoin de se connecter auparavant.
Single Sign On (SSO)
Publik dispose d'un fournisseur d'identité (brique Authentic de la solution) versatile : il peut fournir des identités selon les protocoles standards du marché, à savoir OpenID Connect et SAML.
La documentation pour établir une telle connexion est ici : Mise en place d'un SSO avec un portail métier
Ci-dessous un résumé rapide de ce que le service à connecter doit fournir, et ce que Authentic fourni, afin d'établir au final la "confiance" entre les deux entités.
Connexion OpenID Connect
- redirect_url
- post_logout_redirect_uri
- client_id
- client_secret
- authorization_url
- token_url
Connexion SAML
Connexion CAS
API Génériques
Connecteur « famille »
Un connecteur générique « famille » existe dans Publik, qui propose un ensemble de webservice permettant de construire un portail famille minimal, permettant notamment de payer les factures : https://dev.entrouvert.org/projects/passerelle/wiki/Connecteur_famille
Si un logiciel tiers de gestion de l'enfance (scolaire, péri-scolaire, etc.) désire s'intégrer à Publik, il doit suivre les API décrites.
Connecteur « facturier »
Géocodage & SIG
Publik peut suivre tout connecteur de géocodage suivant l'API de Nominatim (cf supra). Notez qu'un tel connecteur avec la BAN existe déjà (Base Adresse Nationale [française], https://adresse.data.gouv.fr/).
Gestion des agendas & rendez-vous
Publik dispose d'un logiciel interne de gestion des agendas et rendez-vous, dont l'usage technique est décrit dans la documentation officielle de Publik : https://doc-publik.entrouvert.com/admin-fonctionnel/prises-de-rendez-vous
Si un logiciel tiers veut proposer ce même service et s'intégrer « naturellement » à Publik, il doit suivre les API décrites.
Développement d'un connecteur
Ajouter un connecteur compatible Publik dans un logiciel tiers revient donc à proposer un ensemble de webservices suivant les modèles proposés ci-dessus, selon les fonctionnalités demandées.
Il s'agit donc de mettre en place des « endpoints » accessibles en GET ou en POST, échangeant des données au format JSON. Sauf exception le format de réponse est toujours de la forme {"err": 0, "data": ...}.
En cas d'appairage d'un compte Publik avec un compte sur le logiciel, Publik enverra en argument, ou dans le payload, le NameID du compte Publik. Le logiciel tiers doit maintenir une table de fédération entre ce pseudonyme et le compte local dans l'application.
En terme de sécurité d'accès au webservice, il convient de mettre en place :
- un chiffrage par SSL/TLS, c'est-à-dire en HTTPS pour un webservice, avec un certificat reconnu
- un filtrage par adresse IP (pour ne permettre que les accès par Publik) le cas échéant
Pour renforcer la partie sécurité, il est possible d'utiliser le système de signature de Publik, documenté ici : https://doc-publik.entrouvert.com/tech/wcs/api-webservices/authentification/. Cela permet au logiciel tiers d'être sûr que c'est bien Publik qui l'interroge, et d'éviter les rejeux.
Passerelle
Quand des webservices existent déjà, ou qu'un framework permet de créer des webservices sur le logiciel tiers, alors ils peuvent ne pas être compatibles avec Publik. Dans ce cas, on ajoute dans Passerelle un "traducteur" capable de passer du langage de Publik à celui du logiciel tiers.
Passerelle est un logiciel en Python/Django qui propose quelques outils pour aider à développer un tel connecteur. Il est particulièrement efficace quand le logiciel en face parle déjà en JSON, mais il peut gérer n'importe quel protocole accessible en Python, tel que SOAP.
Voici un exemple d'un code connecteur, qui va chercher une liste dans le logiciel tiers, et la propose à Publik sous la forme d'un référentiel selon l'API Publik :
@endpoint()
def classes(self, request):
# lire la liste des classes sur le logiciel tiers :
response = requests('https://logicielenfance/referentiel/classes').json()
# construire la réponse à renvoyer selon l'API Publik
data = []
for item in response:
# le "code" renvoyé par le logiciel tiers est le "id" dans l'API Publik
# le "label" renvoyé par le logiciel tiers s'appelle "text" dans l'API Publik
data.append({ "id": item["code"], "text": item["label"] })
return data
Si le webservice tiers était en SOAP, c'est la ligne "response = ..." qui ferait une requête SOAP au lieu d'un simple accès REST/JSON ici.
Pour en savoir plus et s'essayer au développements de connecteur dans Passerelle, lire :
Il est utile de consulter le code des connecteurs existants :
- ://git.entrouvert.org/passerelle.git/tree/passerelle/apps/ : les connecteurs "officiels" qui couvrent des logiciels ou des principes transversaux
- ://git.entrouvert.org/passerelle.git/tree/passerelle/contrib/ : les connecteurs "spécifiques" qui couvrent des besoins locaux à un client
Tous les connecteurs ne sont pas simples, ni toujours écrits dans les règles de l'art ; parfois les webservices proposés en natif sont éloignés des besoins fonctionnels, ou ne sont pas homogènes, et il ne suffit pas de faire une simple passerelle d'un webservice tiers vers une API Publik. Nous conseillons de regarder d'abord les "petits" connecteurs avec un ou deux enpoints, et parmi ceux-là de prendre ceux qui ont été codé le plus récemment.