API Server
Présentation
L'API server expose les éléments suivants (named exports) :
- la méthode start qui permet d'initialiser l'application Express ;
- la méthode getPubSub qui permet de récupérer l'instance PubSub pour la gestion des subscriptions graphQL ;
- les utilitaires des resolvers graphQL OK et KO ;
- la méthode handleTask nécessaire à l'éxecution des tùches ;
- l'utilitaire getEnv qui permet de résoudre la valeur d'une variable d'environnement ;
- l'utilitaire validateResolverContext qui permet de valider le contexte d'appel d'un resolver d'une vue.
Les imports depuis l'OAV :
import {
start,
getPubSub,
OK,
KO,
handleTask,
getEnv,
validateResolverContext,
} from '@fasstech/oip-starter-utils/server';Méthode start
La méthode start initialise l'application Express de l'OAV. Elle prend en paramÚtre un objet de configuration. La méthode retourne l'application Express app
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
// options
};
const { app } = await start(serverCfg);
// init your business logic here
void app;Propriétés requises
graphql
Initialise le schéma graphQL de l'OAV et permet la configuration de seuils de sécurité du server graphQL.
graphql.resolvers
La liste des resolvers graphQL de l'OAV est attendue en valeur.
graphql.typeDefs
La liste des définitions des types graphQL de l'OAV est attendue en valeur.
graphql.security
Cette propriété accepte les sous-propriétés optionnelles suivantes :
- payloadLimit => permet de dĂ©finir la taille maximale autorisĂ©e de la payload des requĂȘtes graphQL entrantes. Par dĂ©faut, la limite est dĂ©finie sur 50kb
- maxCoercionErrors => permet de configurer le nombre maximal d'erreurs de coercition de variables (variable coercion errors) qu'Apollo Server acceptera avant de rejeter une requĂȘte avec un code d'Ă©tat 400. Limite dĂ©finie Ă 50 par dĂ©faut.
- maxErrors => permet de limiter le nombre maximal d'erreurs de validation GraphQL accumulĂ©es avant qu'Apollo Server n'arrĂȘte le processus de validation et ne rejette la requĂȘte. Limite dĂ©finie Ă 10 par dĂ©faut.
- armorConfig => permet de configurer les valeurs des seuils de sécurité gérés par la lib graphql-armor. Les rÚgles de validation suivantes sont configurables :
Par défaut, les valeurs par défaut de la lib graphql-armor sont utilisées pour la configuration de la propriété graphql.security.armorConfig
Se référer à la documentation de la lib graphql-armor pour connaitre le type attendu des objets de configuration acceptés et leurs valeurs par défaut.
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
graphql: {
resolvers: [/* ...resolvers */],
typeDefs: [/* ...typeDefs */],
security: {
payloadLimit: '1kb',
armorConfig: {
maxDepth: {
n: 3,
},
costLimit: {
maxCost: 20,
},
maxTokens: {
n: 100,
},
},
},
},
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;process
Permet la configuration de l'objet Process.
process.resolveFirstView
La callback de la résolution conditionnelle de la premiÚre vue du parcours est attendue en valeur.
Signature : *({ projectId: string; viewId?: string; metadata?: object }) => *Promise<string>
Cette callback a pour but de résoudre l'id de la premiÚre vue du parcours. Le corps de la fonction doit impérativement retourner l'id d'une vue. La callback reçoit en paramÚtre l'id de l'entité Project actuelle projectId. Si l'entité Project est liée à une session précédente, la callback reçoit également viewId qui identifie la derniÚre vue active du parcours ainsi que ses metadonnées metadata si elles existent.
process.extendWith
La callback qui permet de résoudre les propriétés personnalisées de l'objet Process est attendue en valeur. Elle reçoit en paramÚtre l'objet Process.
Signature : *(process: Process) => *Promise<ExtendedProcess>
L'objet qui reprĂ©sente le Process Ă©tendu doit ĂȘtre rĂ©solu et retournĂ©. Le type de l'objet doit correspondre au type graphQL ExtendedProcess dĂ©finit dans le code de l'OAV.
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
import { resolveFirstView } from './resolve-first-view.mjs'
import { extendWith } from './extend-with.mjs'
const serverCfg = {
process: {
resolveFirstView,
extendWith,
},
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;session
Permet de configurer la résolution du contexte client et de l'entité Project relative lors du décrochage.
session.validateProjectId
Cette callback permet de vérifier la validité de projectId lors d'un décrochage avec le paramÚtre projectId au lieu de token.
Signature : ({ projectId: string; sessionId?: string; clientId?: string }) => Promise<boolean>
Elle reçoit en paramÚtre projectId et sessionId. Le corps de la fonction doit retourner un boolean, true si projectId est valide, false le cas contraire.
à partir de la version 4.3.0 de la bibliothÚque, l'identifiant unique de la connexion client clientId est également reçu en paramÚtre.
session.resolveProjectFromContext
Cette callback permet de résoudre l'id de l'entité Project projectId lors du décrochage sur l'OAV à partir du contexte client.
Signature : ({ *...context**, sessionId: string, clientId: string }) => *Promise<string>
- Dans un environnement de production ou en mode développement avec la variable SECURE_SESSION définie à true, la callback reçoit en paramÚtre un objet qui représente le contexte client résolu ainsi que la propriété sessionId.
- En mode développement avec la variable SECURE_SESSION définie à false, la callback reçoit uniquement la propriété sessionId. Vous pouvez alors définir et consommer un mock du contexte client dans le corps de la fonction pour résoudre l'id de l'entité Project.
Le corps de la fonction doit retourner l'id de l'entité Project relative au contexte client dans tous les cas.
à partir de la version 4.3.0 de la bibliothÚque, l'identifiant unique de la connexion client clientId est également reçu en paramÚtre.
session.resolveContext
Si définie, cette callback permet de définir la callback de résolution du contexte client à partir du token lors du décrochage sur l'OAV.
Par défaut, la lib résout le contexte client grùce à un appel au service Fasst Sessions ou équivalent avec le token passé en paramÚtre. L'URL du service est résolu grùce à la variable d'environnement SESSIONS_SERVICE_URL
Si vous souhaitez implémenter votre logique personnalisée de résolution du contexte client à partir du token de décrochage, vous devez utiliser la propriété session.resolveContext pour définir la callback de résolution du contexte client.
Signature : *(token: string) => *Promise<object>
La callback reçoit en paramÚtre le token de décrochage et doit impérativement retournée un objet représentant le contexte client résolu.
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
session: {
validateProjectId,
resolveProjectFromContext,
resolveContext,
},
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;session.resolveMetadata
Si définie, cette fonction de rappel permet de résoudre les métadonnées qui seront injectées dans l'objet session (gérer par la dépendance express-session) pour le projet en cours.
Signature : async ({ projectId: string, sessionId: string, clientId: string }) => Promise<object>
La fonction de rappel reçoit en paramÚtre un objet qui contient projectId et sessionId et doit retourner un objet qui représente les métadonnées de la session.
à partir de la version 4.3.0 de la bibliothÚque, l'identifiant unique de la connexion client clientId est également reçu en paramÚtre.
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
import { resolveMetadata } from './resolve-metadata.mjs';
const serverCfg = {
session: {
// ...
resolveMetadata,
},
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;session.clientSync.enabled
Type boolean, false par défaut.
Permet d'activer la fonctionnalité de la synchronisation des connexions clientes. Si activée, le serveur instancie un serveur WebSocket qui garantie le contrÎle d'un projet (identifié par projectId) par un seul client à la fois.
Exemple :
import { start } from "@fasstech/oip-starter-utils/server";
let serverConfig = {
session: {
// ...
clientSync: { enabled: true }
}
};
const { app } = await start(serverConfig);
// init your business logic here
void app;logger
L'instance d'un logger est attendu en valeur.
Exemple :
import { logger } from '@fasstech/logger';
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
logger,
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;Propriétés optionnelles
basePath
Une chaßne de caractÚres qui définit le préfixe des URLs exposées par le serveur :
- /u/token
- /session
- /ws-config
- /graphql
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
// ...
basePath: '/api'
};
// /u/token -> /api/u/token
// /session -> /api/session
// /ws-config -> /api/ws-config
// /graphql -> /api/graphql
const { app } = await start(serverCfg);
// init your business logic here
void app;cookieOptions
Un objet permettant la configuration des attributs du cookie de session est attendu en valeur. La dépendance npm express-session est utilisée. Pour la liste complÚte et le détail des options de configuration acceptÚes, veuillez vous référer à la documentation des options liées au cookie de la dépendance.
Configuration par défaut :
- maxAge défini par la var d'env SESSION_COOKIE_MAX_AGE ou 60 minutes par défaut
- secret défini par la var d'env SESSION_SECRET (requise)
- secure défini par la var d'env SECURE_COOKIE ou false par défaut
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
// ...
cookieOptions: {
secure: process.env.NODE_ENV === 'production',
httpOnly: process.env.NODE_ENV === 'production',
sameSite: process.env.NODE_ENV === 'production' ? 'none' : false
}
};
const { app } = await start(serverCfg);
// init your business logic here
void app;corsOptions
Un objet permettant la configuration de la mécanique CORS est attendu en valeur. La dépendance npm cors est utilisée. Pour la liste complÚte et le détail des options de configuration acceptÚes, veuillez vous référer à la documentation des options de configuration de la dépendance.
Configuration par défaut : { origin: '*', allowedHeaders: '*' }
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
// ...
corsOptions: {
origin: (origin, callback) => {
if (!origin || WHITE_LIST.includes(origin)) {
callback(null, true);
} else {
callback(new Error('Origin not allowed!'));
}
},
credentials: true,
methods: 'GET,HEAD,OPTIONS,PUT,PATCH,POST,DELETE',
allowedHeaders: ['Origin', 'Content-Type', 'Accept', 'Authorization'],
preflightContinue: false
}
};
const { app } = await start(serverCfg);
// init your business logic here
void app;routes
Une instance d'un router Express est attendu en valeur. Les routes et les fonctions middleware spécifiques à l'OAV seront alors chargées et initialisées par l'application Express.
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
import routes from './routes.mjs';
const serverCfg = {
routes
// ...
};
const { app } = await start(serverCfg);
// init your business logic here
void app;securityHeadersOptions
Un objet permettant la configuration des headers de sécurité est attendu en valeur. La dépendance npm helmet est utilisée. Pour la liste complÚte et le détail des options de configuration acceptÚes, veuillez vous référer à la documentation de la dépendance.
Configuration par défaut : { xPoweredBy: false }
Exemple :
import { start } from '@fasstech/oip-starter-utils/server';
const serverCfg = {
// ...
securityHeadersOptions: {
crossOriginResourcePolicy: {
policy: "same-site",
},
},
};
const { app } = await start(serverCfg);
// init your business logic here
void app;Méthode getPubSub
La méthode getPubSub permet de récupérer l'instance PubSub. Elle est initialisée grùce à la dépendance @fasstech/rabbitmq-helper qui nécessite un service RabbitMQ.
Signature : *() => *PubSub
Exemple :
import { getPubSub } from '@fasstech/oip-starter-utils/server';
const pubsub = getPubSub();Les utilitaires graphQL OK et KO
Les utilitaires OK et KO permettent de standardiser les réponses des resolvers graphQL de l'OAV.
Signature des fonctions :
- OK = (additionalFields = {}) => ({ ok: true, ...additionalFields })
- KO = (error, additionalFields = {}) => ({ error, ok: false, ...additionalFields })
Exemple :
import { OK, KO } from '@fasstech/oip-starter-utils/server';
export const getCustomer = (args, context) => {
if (/* something */) {
const error = new Error('Something goes wrong!');
return KO(error, {
firstName: null,
lastName: null,
});
}
return OK({
firstName: 'John',
lastName: 'Doe',
});
};Méthode handleTask
La fonction handleTask est chargée de récupérer les messages liés aux tùches sur la queue RabbitMQ adéquate. Pour chaque message valide, elle démarre un nouveau processus enfant qui va exécuter le code de la tùche.
Il est nécessaire d'importer et de définir cette méthode comme event consumer dans l'index du server de votre projet. Ex. :
import { handleTask, start } from '@fasstech/oip-starter-utils/server';
import { queueService } from '@fasstech/rabbitmq-helper';
await start({ /* ... */ });
// Register a consumer to handle `events` messages
queueService.consumeMessage(`${process.env.OAV_ID}.events`, 0, handleTask);L'utilitaire getEnv
La fonction getEnv permet de résoudre la valeur d'une variable d'environnement depuis le code serveur de l'OAV.
Exemple :
import { getEnv } from '@fasstech/oip-starter-utils/server';
const myVar = getEnv(MY_VAR);L'utilitaire validateResolverContext
[info] Il est possible de générer les resolvers des vues protégés par défaut en spécifiant l'option --gen-secure-resolvers à la commande du build des vues de l'OAV.Ex. : npx oip-tools views generate --gen-secure-resolvers
La fonction validateResolverContext permet de valider le contexte d'appel d'un resolver d'une vue avant son exécution.
Une query ou une mutation graphQL d'une vue est protégée si le resolver associé implémente et appelle validateResolverContext.
Dans ce cas, si la query ou la mutation relative au resolver est appelée en dehors du contexte de la vue associée, une erreur est jetée.
Signature : *(expectedViewId: string, actualViewId: string) => *boolean
Exemple d'un resolver protégé d'une vue :
import { validateResolverContext } from '@fasstech/oip-starter-utils/server';
export const myResolver = (args, context) => {
const { process } = context;
// protected resolver, an error will be thrown if the resolver is called from outside the view
validateResolverContext('expectedViewId', process.viewId);
return {
// ... resolved fields
};
};
export default myResolver;