Ajouter une vue
Les fichiers de configuration yaml des vues se trouvent dans le dossier viewsConfig à la racine. Un fichier de configuration définit une vue. Lors de l'exécution de la commande du build des vues, un dossier relatif à chaque vue est généré dans le dossier views à la racine ainsi que tous les fichiers client / server qui composent la vue.
Le fichier de configuration d'une vue
start:
viewId: start
pathname: /start
directory: start
graphql:
queries:
- type: Customer
fields:
firstName: String
lastName: String
resolver: getCustomer
mutations:
- type: Customer
inputs:
firstName: String
lastName: String
resolver: createCustomer- viewId définit l'identifiant unique de la vue
- pathname définit l'URL de la vue
- directory définit le nom du dossier de la vue dans le dossier views
- graphql définit les queries et mutations gql qui seront utilisées par la vue
Le layer GraphQL
- queries contient les différentes queries gql qui seront utilisées par la vue
Exemple de définition d'une query gql de type Customer :
...
graphql:
queries:
- type: Customer # le type attendu en réponse de la query
fields: # les fields du type attendus en réponse
firstName: String
lastName: String
resolver: getCustomer # le nom du resolver relatif Ă la query
- mutations contient les différentes mutations gql qui seront utilisée par la vue
Exemple de définition d'une mutation gql de type Customer :
...
mutations:
- type: Customer # le type attendu en réponse de la mutation
inputs: # les arguments attendus en input
firstName: String
lastName: String
resolver: createCustomer # le nom du resolver relatif Ă la mutation
Ajouter une vue
Ajoutez le fichier de configuration de la nouvelle vue Ă la racine du dossier viewsConfig
Par convention le nom du fichier correspond à l'identifiant unique de la vue ainsi qu'au numéro de l'ordre de transition de la vue dans votre OAV. Exemple pour la vue start : 02_start.yml
Une fois le fichier de configuration édité et terminé n'oubliez pas de lancer la commande responsable du build des vues pour générer les fichiers de la nouvelle vue
npm run views:buildPour terminer l'ajout de votre nouvelle vue, il vous faut également définir ses transitions. Se référer à ce chapitre
Modifier une vue
Ăditez selon vos besoin le fichier de configuration d'une vue puis relancez la commande du build des vues
npm run views:buildLes fichiers générés d'une vue
Les informations données par ce chapitre sont relatives à une version 3 de la dépendance @fasstech/oip-tools
Prenons comme exemple ce fichier de configuration pour la vue home :
home:
viewId: home
pathname: /
directory: home
graphql:
queries:
- type: Customer
fields:
firstName: String
lastName: String
resolver: getCustomer
mutations:
- type: Customer
inputs:
firstName: String
lastName: String
resolver: createCustomerCette vue est définie comme suit :
- id de la vue : home
- url de la vue : /
- dossier qui contiendra les fichiers de la vue : home
- définit une query gql de type Customer dont le nom du resolver associé sera getCustomer
- définit une mutation gql de type Customer dont le nom du resolver associé sera createCustomer
AprÚs génération des vues grùce à la commande npm run views:build, les fichiers client et server de la vue home sont générés dans le dossier views/home comme suit :
home/
ââ client/
â ââ graphql/
â â ââ mutations/
â â â ââ CreateCustomerMutation.js
â â ââ queries/
â â ââ GetCustomerQuery.js
â ââ hooks/
â â ââ useCreateCustomerMutation.js
â â ââ useGetCustomerQuery.js
â ââ Home.inte.test.jsx
â ââ Home.jsx
ââ server/
ââ graphql/
ââ resolver/
â ââ createCustomer.mjs
â ââ createCustomer.test.js
â ââ getCustomer.mjs
â ââ getCustomer.test.js
â ââ index.mjs
ââ type/
ââ MutationType.mjs
ââ QueryType.mjs
ââ queryTypeResolvers.mjsCĂŽtĂ© server
Deux dossiers sont générés dans le dossier server de la vue :
- graphql/type
- graphql/resolver
graphql/type contient la dĂ©claration des types graphQL de la vue. Ces fichiers ne doivent pas ĂȘtre modifiĂ©s. Ils sont gĂ©nĂ©rĂ©s Ă chaque build des vues.
graphql/resolver contient le squelette de chaque resolver gql déclarés dans le fichier de configuration de la vue. Pour chaque resolver généré, un exemple de fichier de test est généré également. Il vous appartient d'éditer ces resolvers afin de résoudre les champs attendus de la query ou de la mutation gql relative.
Les resolvers
Un resolver généré a pour signature : (args, context) => ExpectedType
- args contient les paramĂštres de la query ou de la mutation ou un objet vide
- context contient un objet process qui contient par défaut l'id de l'entité Project actuelle ainsi que l'id de la vue actuelle { process: { projectId, viewId } }
Un resolver doit toujours retourner un objet qui contient les champs résolus demandés par la query ou la mutation relative.
Exemple du resolver getCustomer :
export const getCustomer = (args, context) => {
const { projectId } = context.process;
// résolvez vos champs ici
// retourne les champs attendus par la query
return {
firstName: 'John',
lastName: 'Doe'
};
};
export default getCustomer;Sécuriser les resolvers
à partir de la version v3.4.1 de la dépendance @fasstech/oip-tools il est possible de générer les resolvers des vues de maniÚre sécurisée.
Un resolver sĂ©curisĂ© ne peut ĂȘtre appelĂ© que depuis le contexte de sa vue relative sinon une erreur est retournĂ©e dans la rĂ©ponse de la query / mutation.
Pour activer cette fonctionnalité, vous devez ajouter l'option --gen-secure-resolvers true à la commande views:build du fichier package.json de votre projet.
Puis veuillez exécuter la commande du build des vues :
npm run views:buildGrùce à l'option --gen-secure-resolvers true, un helper qui permet de valider le contexte d'un resolver est généré dans le dossier views/_common/server/helpers/ fichier validateResolverContext.js
Signature : validateResolverContext = (expectedViewId, currentViewId) => boolean
L'helper prend en 1er paramÚtre l'id attendu de la vue relative et en 2nd paramÚtre l'id de la vue actuelle. L'helper retourne true si les deux identifiants correspondent sinon une erreur est jetée.
Les resolvers générés lors du build des vues avec l'option --gen-secure-resolvers à true appellent l'handler validateResolverContext pour valider ou non le contexte et ainsi sécuriser le resolver par rapport à sa vue relative. Si le resolver est appelé en dehors du contexte de sa vue relative, une erreur est retournée dans la réponse de la query / mutation.
Pour sécuriser les resolvers déjà existants de votre projet (les resolvers générés avant la mise à jour de @fasstech/oip-tools), veuillez suivre ces étapes :
1- ajouter l'option --gen-secure-resolvers true à la commande views:build puis run la commande pour générer l'helper
2- au niveau du fichier du resolver à sécuriser, importer l'helper validateResolverContext depuis le fichier views/_common/server/helpers/validateResolverContext.js (named export)
3- implémenter l'appel à l'helper dans le corps du resolver, ex. :
import { validateResolverContext } from '[relative-path]/_common/server/helpers/validateResolverContext.js';
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('expected-view-id', process.viewId);
// ...
};
export default myResolver;CÎté client
CÎté client, le squelette du composant principal de la vue est généré ainsi que son fichier de test. Dans notre exemple on retrouve donc à la racine du dossier client les fichiers :
- Home.jsx
- Home.inte.test.jsx
Il vous appartient d'éditer ces fichiers en fonction de vos besoins. Libre à vous de créer un sous-dossier components par exemple à la racine du dossier client qui contiendra les composants de votre vue.
En plus du composant principal, un dossier graphql et un dossier hooks sont également générés.
Le dossier graphql contient la dĂ©claration client des queries et des mutations gql de la vue. Ces fichiers sont utilisĂ©s par les hooks gĂ©nĂ©rĂ©s. Ces fichiers ne doivent pas ĂȘtre modifiĂ©s. Ils sont gĂ©nĂ©rĂ©s Ă chaque build des vues.
Le dossier hooks contient un hook react pour chaque query ou mutation dĂ©clarĂ©e. Ils vous sont utiles pour consommer une query ou une mutation gql depuis les composants de votre vue. Les hooks gĂ©nĂ©rĂ©s ne doivent pas ĂȘtre modifiĂ©s. Ils sont gĂ©nĂ©rĂ©s Ă chaque build des vues. Mais libre Ă vous d'ajouter vos propres hooks personnalisĂ©s dans le dossier hooks
Deux types de hooks sont générés : les hooks pour gérer les queries et les hooks pour gérer les mutations.
Hook d'une query
Un hook généré pour une query aura pour nom use<nom-du-resolver-relatif>Query
Exemple pour notre query de type Customer avec comme resolver associé GetCustomer : useGetCustomerQuery
Signature : (args) => Result
Les paramĂštres acceptĂ©s sont les mĂȘmes que les options possibles du hook useQuery de la lib Apollo Client. Documentation de useQuery. Par exemple, pour passer les variables de la query au hook, passer en paramĂštre un objet de la forme { variables: { message: 'hello world!' } }
Les variables exposées par le hook sont :
- error contient une ou des erreurs gql si elles existent ou est undefined
- loading (boolean) indique si la query est en cours de chargement ou non
- refetch méthode qui permet de relancer la query, prend les variables de la query en paramÚtres (optionnel)
- <nom-du-resolver-relatif> le nom de cette variable correspond au nom du resolver relatif de la query. Contient la data demandée ou un objet vide
Exemple d'utilisation du hook useGetCustomerQuery dans le composant Home :
// import du hook depuis le dossier hooks
import useGetCustomerQuery from './hooks/useGetCustomerQuery.js';
const Home = () => {
// appel au hook
const { getCustomer, loading } = useGetCustomerQuery();
return (
<div className="t-home">
...
<div>
<p>Is loaded GetCustomer: {loading ? 'no' : 'yes'}</p>
<div>
<pre>{JSON.stringify(getCustomer, null, 2)}</pre>
</div>
</div>
</div>
);
};
export default Home;Hook d'une mutation
Un hook généré pour une mutation aura pour nom use<nom-du-resolver-relatif>Mutation
Exemple pour notre mutation de type Customer avec comme resolver associé createCustomer : useCreateCustomerMutation
Signature : () => Result
Un hook généré d'une mutation ne prend aucun paramÚtre.
Les variables exposées par le hook sont :
- loading (boolean) indique si la mutation est en cours de chargement ou non
- called (boolean) indique si la mutation a été appelée on non
- onFormSubmit méthode qui permet de déclencher la mutation
Signature de la méthode onFormSubmit : (input, done, options) => void
Détail des paramÚtres :
- input les variables de la mutations
- done callback qui reçoit en paramÚtres ok, error et data (la donnée demandée) une fois l'exécution de la mutation terminée
- options (optionnel) les options à passer à la fonction mutate (hook useMutation de la lib Apollo Client) utilisée par onFormSubmit. Pour la liste des options possibles, se référer à cette documentation
Exemple d'utilisation du hook useCreateCustomerMutation dans le composant Home :
// import du hook depuis le dossier hooks
import useCreateCustomerMutation from './hooks/useCreateCustomerMutation.js';
const Home = () => {
// appel au hook
const { onFormSubmit, loading } = useCreateCustomerMutation();
const onSubmit = () => {
// skip du submit si la mutation est en chargement
if (loading) {
return;
}
// appel à la méthode onFormSubmit pour déclencher la mutation
onFormSubmit(
// les variables de la mutation (input)
{
firstName: 'John',
lastName: 'Doe'
},
// la callback qui sera appelée une fois la mutation terminée
(ok, error) => {
if (!ok && error) {
console.error('Unexpected error');
return;
}
console.log('Saved successfully');
}
);
}
return (
<div className="t-home">
...
<button className="f-button" onClick={onSubmit}>
SUBMIT
</button>
</div>
);
};
export default Home;