Module communautaire génial

application fib

cadre API de base de l'application fibjs

Installer

1
npm install fib-app [--save]

Test

1
npm test

Créer un script de base

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const http = require('http'); const util = require('util') const Session = require('fib-session') const App = require('../'); var app = new App('sqlite:test.db', { uuid: true }); app.db.use(require('./defs/person')); var session = new Session(new util.LruCache(20000), { timeout: 60 * 1000 }); var svr = new http.Server(8080, [ session.cookie_filter, { '/1.0': app } ]); svr.run();

personse trouve le module Définition du modèle, le contenu est le suivant :

1 2 3 4 5 6 7
module.exports = db => { db.define('person', { name: String, sex: ["male", "female"], age: Number }); };

Il s'agit d'une définition ORM standard et vous pouvez également utiliser d'autres fonctions ORM, telles que la vérification de type, les événements, etc.

Format des données API

Pour les requêtes POST et PUT, le corps de la requête doit être au format JSON et le Content-Type de l'en-tête HTTP doit être défini sur application/json.

1 2 3 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"name": "tom","sex":"male","age":23}' \ http://localhost/1.0/person/57fbbdb0a2400000

Pour toutes les requêtes, le format de réponse est un objet JSON.

Le fait qu'une requête ait abouti ou non est indiqué par le code d'état HTTP. Un code d'état 2XX indique le succès, tandis qu'un code d'état 4XX indique que la demande a échoué. Lorsqu'une requête échoue, le corps de la réponse est toujours un objet JSON, mais il contient toujours les champs de code et de message, que vous pouvez utiliser pour le débogage. Par exemple, si une demande d'authentification d'autorisation échoue, les informations suivantes seront renvoyées :

1 2 3 4
{ "code": 4030501, "message": "The operation isn’t allowed for clients due to class-level permissions." }

Le code de code est divisé en trois parties. Les trois premiers chiffres 403 représentent le type d'erreur, 05 représente le numéro de la fiche technique et 01 représente le code d'erreur détaillé.

Pour les requêtes GET, des données d'objet sont généralement renvoyées. Selon l'adresse de la requête GET, un objet ou un tableau peut être renvoyé. Par exemple:

1 2 3 4 5
{ "name": "tom", "sex": "male", "age": 23 }

ou:

1 2 3 4 5 6 7 8 9 10 11 12
[ { "name": "tom", "sex": "male", "age": 23 }, { "name": "lily", "sex": "female", "age": 22 } ]

champs spéciaux

Dans les données d'objet, il existe quatre champs ayant des significations particulières qui ne peuvent pas être modifiés via l'API. Ce sont respectivement id, updatedAt, createdAt.createdBy

Parmi eux id, des champs uniques seront automatiquement créés et modifiés updatedAt. Vous devez spécifier le type vous-même.createdAtcreatedBy

API d'accès aux objets de base

Après avoir terminé cette définition de données, vous disposerez directement d'un ensemble d'appels d'interface conformes à la spécification de l'API REST :

URL méthode action
/1.0/:nom de classe POSTE Créer un nouvel objet
/1.0/:nom de classe/:id OBTENIR Lire l'objet
/1.0/:nom de classe/:id METTRE Modifier un objet
/1.0/:nom de classe/:id SUPPRIMER Supprimer l'objet
/1.0/:nom de classe OBTENIR Liste d'objets de requête

Créer un nouvel objet

Pour créer un nouvel objet, une requête POST doit être envoyée à l'URL de la classe, qui doit inclure l'objet lui-même. Par exemple, pour créer l'objet illustré ci-dessus :

1 2 3 4
curl -X POST \ -H "Content-Type: application/json" \ -d '{"name": "tom","sex":"male","age":23}' \ http://localhost/1.0/person

Lorsque la création réussit, le retour HTTP est 201 Created et le corps de la réponse est un objet JSON contenant l'objectId et l'horodatage CreatedAt du nouvel objet :

1 2 3 4
{ "createdAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400000" }

Lire l'objet

Lorsque vous créez un objet, vous pouvez récupérer son contenu en envoyant une requête GET à l'emplacement dans l'en-tête renvoyé. Par exemple, pour récupérer l'objet que nous avons créé ci-dessus :

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000

Le corps renvoyé est un objet JSON contenant tous les champs fournis par l'utilisateur ainsi que les createdAtchamps updatedAtetid :

1 2 3 4 5 6 7 8
{ "name": "tom", "sex": "male", "age": 23, "createdAt": "2017-11-25T01:39:35.931Z", "updatedAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400000" }

En définissant le return field keys, vous pouvez personnaliser le contenu renvoyé, keysqui est une ,chaîne de noms de champs séparés par :

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000?keys=name%2Csex

reviendra:

1 2 3 4
{ "name": "tom", "sex": "male" }

Modifier un objet

Afin de modifier les données existantes d'un objet, vous pouvez envoyer une requête PUT à l'URL correspondante de l'objet. Toutes les clés que vous ne spécifiez pas ne seront pas modifiées, vous ne pouvez donc mettre à jour qu'un sous-ensemble des données de l'objet. Par exemple, modifions un champ age de notre objet :

1 2 3 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"age": 25}' \ http://localhost/1.0/person/57fbbdb0a2400000

L'objet JSON renvoyé contiendra updatedAtdes idchamps indiquant quand la mise à jour a eu lieu :

1 2 3 4
{ "updatedAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400000" }

Supprimer l'objet

Pour supprimer un objet, vous pouvez envoyer une requête DELETE à l'URL de l'objet spécifié, par exemple :

1
curl -X DELETE http://localhost/1.0/person/57fbbdb0a2400000

Liste d'objets de requête

Vous pouvez obtenir plusieurs objets à la fois en envoyant une requête GET à l'URL de la classe, sans aucun paramètre d'URL. Voici comment obtenir simplement tous les utilisateurs :

1
curl -X GET http://localhost/1.0/person

La valeur renvoyée est un objet JSON contenant le champ de résultats, dont la valeur est une liste d'objets :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[ { "name": "tom", "sex": "male", "age": 23, "createdAt": "2017-11-25T01:39:35.931Z", "updatedAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400000" }, { "name": "lily", "sex": "female", "age": 22, "createdAt": "2017-11-25T01:39:35.931Z", "updatedAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400001" } ]

personnalisation des champs de clés

Comme pour la requête d'objet, vous pouvez keyspersonnaliser les champs inclus dans les résultats renvoyés en les définissant lors de l'interrogation de la liste. keysLe contenu est une ,chaîne de noms de champs séparés par , par exemple :

1
curl -X GET http://localhost/1.0/person?keys=name%2Cage

Précisera que seuls les champs nameet ageseront renvoyés.

où état du filtre

whereL'objet requête peut être contraint sous forme de paramètres.

whereLa valeur du paramètre doit être codée en JSON. Autrement dit, si vous examinez la demande d'URL réelle effectuée, elle doit d'abord être codée en JSON, puis encodée en URL. La wheremanière la plus simple d’utiliser les paramètres consiste à inclure la clé et la valeur appropriées. Par exemple, si nous voulions rechercher des utilisateurs nommés tom, nous construirions la requête comme ceci :

1
curl -X GET http://localhost/1.0/person?where=%7B%22name%22%3A%22tom%22%7D

whereLa valeur est une chaîne JSON codée en urlen, le contenu est :{"name":"tom"}

En plus de faire correspondre exactement une valeur donnée, wheredes méthodes de comparaison telles que l'inclusion sont également prises en charge. whereLes paramètres prennent en charge les options suivantes :

clé opération échantillon
équip égal {"name":{"eq":"tom"}} ou {"name":"tom"}
ne pas égal à {"name":{"ne": "tom"}}
GT plus que le {"âge":{"gt":"24"}}
gite supérieur ou égal à {"âge":{"gte":"24"}}
lt moins que {"âge":{"lt":"24"}}
LTE inférieur ou égal à {"âge":{"lte":"24"}}
comme requête floue {"nom":{"like":%m"}}
pas comme requête floue {"nom":{"not_like":"%m"}}
entre Comparaison d'intervalle {"âge":{"entre":[22,25]}}
pas entre Comparaison d'intervalle {"âge":{"not_between":[22,25]}}
dans énumérer {"name":{"in":["tom","lily"]}}
pas dedans énumérer {"name":{"not_in":["tom","lily"]}}
ou Opération OU {"ou":[{"name":"tom"},{"age":24}]}

sauter sauter les enregistrements

Grâce skipà l'option, vous pouvez ignorer le nombre d'enregistrements spécifié pour obtenir l'effet de tourner la page.

1
curl -X GET http://localhost/1.0/person?skip=100

limit renvoie la limite d'enregistrement

Grâce à limitcette option, vous pouvez limiter le nombre d'enregistrements renvoyés. limitLes nombres valides sont de 1 à 1 000 et la valeur par défaut est 100.

1
curl -X GET http://localhost/1.0/person?limit=100

order précise la méthode de tri

Utilisez orderl'option pour définir la méthode de tri du jeu de résultats renvoyé. Lorsque le nom du champ contient avant lui, -il est dans l'ordre inverse.

1
curl -X GET http://localhost/1.0/person?order=-id

count renvoie le nombre total de résultats

Incrémenté sur demande countNombre total d'ensembles de résultats pouvant être renvoyés lors du renvoi du contenu spécifié.

1
curl -X GET http://localhost/1.0/person?count=1&limit=1

À ce stade, le résultat renvoyé contiendra deux champs : countet results, contenant respectivement le nombre total et le résultat :

1 2 3 4 5 6 7 8 9 10 11 12 13
{ "count": 2, "results": [ { "name": "tom", "sex": "male", "age": 23, "createdAt": "2017-11-25T01:39:35.931Z", "updatedAt": "2017-11-25T01:39:35.931Z", "id": "57fbbdb0a2400000" } ] }

Créer un objet d'extension

En définissant hasOne et hasMany via ORM, vous pouvez définir l'association entre les objets et la refléter sur l'API, par exemple :

1 2 3 4 5 6 7 8 9
module.exports = db => { var Person = db.models.person; var Pet = db.define('pet', { name: String }); Person.hasMany('pets', Pet); };

API d'accès aux objets étendus

Voici la définition API de l'objet d'extension :

URL méthode action
/1.0/:className/:id/:extendName METTRE Définir l'objet d'extension
/1.0/:className/:id/:extendName POSTE Créer un objet d'extension
/1.0/:className/:id/:extendName/:rid OBTENIR Lire l'objet d'extension
/1.0/:className/:id/:extendName/:rid METTRE Modifier l'objet d'extension
/1.0/:className/:id/:extendName/:rid SUPPRIMER Supprimer l'objet étendu
/1.0/:className/:id/:extendName OBTENIR Interroger la liste d'objets étendue

Définir l'objet d'extension

Définir un objet d'extension consiste à établir une relation entre deux objets indépendants. Par exemple, si Tom adopte un animal nommé chat, il peut utiliser les opérations suivantes pour y parvenir :

1 2 3 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"id": "57fbbdb0a2400007"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets

Lors de l'appel, l'identifiant du chat doit être précisé dans le corps.

Créer un objet d'extension

La création directe d'objets étendus peut établir des connexions entre les objets lors de la création d'objets. Par exemple:

1 2 3 4
curl -X POST \ -H "Content-Type: application/json" \ -d '{"name": "cat"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets

Un animal nommé chat sera créé et associé à Tom.

Lire l'objet d'extension

La lecture d'objets étendus est très similaire à la lecture d'objets de base et prend également en charge l'option clés :

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

Modifier l'objet d'extension

La lecture d'objets étendus est très similaire à la lecture d'objets de base :

1 2 3 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"name": "cat 1"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

Supprimer l'objet étendu

La suppression d'un objet étendu ne supprime pas l'objet lui-même, elle dissout uniquement la relation entre les objets :

1
curl -X DETELE http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

Interroger la liste d'objets étendue

L'interrogation de la liste d'objets étendue est très similaire à l'interrogation de la liste d'objets de base et prend également en charge des options telles que les clés et le filtrage conditionnel :

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets

Liste de contrôle d'accès

Les autorisations de données peuvent être contrôlées en définissant l'ACL du modèle. Par exemple:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
const orm = require('fib-orm'); module.exports = db => { db.define('blog', { title: String, detail: Stringnote: String }, { ACL: function(session) { return { "*": { "*": false }, "57fbbdb0a2400000": { "*": true }, "roles": { "user": { "read": true } } }; } }); };

Si aucune ACL n'est spécifiée lors de la définition du Modèle, cela équivaut à définir les autorisations par défaut :

1 2 3 4 5
{ "*": { "*": true } }

corps principal

Il existe trois types de descriptions de sujet ACL : user id, user roleet *, idqui représentent un utilisateur spécifique, rolereprésentent les utilisateurs avec un certain rôle et *représentent tous les utilisateurs :

corps principal décrire priorité
IDENTIFIANT identifiant d'utilisateur spécifique 1
rôle Nom du groupe d'utilisateurs 2
* Tous 3

Lors de la vérification des autorisations, il correspondra d'abord idaux autorisations correspondantes. S'il n'est pas spécifié, correspondra roleaux autorisations correspondantes de l'utilisateur. S'il est toujours spécifié, vérifiez si *les autorisations de sont spécifiées. S'il *n'est pas spécifié, il n'y a aucune autorisation.

Par exemple, dans la configuration des autorisations ci-dessus, userle groupe d'utilisateurs est spécifié pour pouvoir lire. L'utilisateur 57fbbdb0a2400000dispose de toutes les autorisations, mais les autres utilisateurs n'ont aucune autorisation.

Autorisations

ACL classe les autorisations en cinq catégories en fonction du comportement de l'API :

Autorisations décrire types autorisés
créer Créer un objet vrai/faux/tableau
lire Lire l'objet vrai/faux/tableau
écrire Modifier un objet vrai/faux/tableau
supprimer Supprimer l'objet vrai faux
trouver Liste d'objets de requête vrai faux
* Faire correspondre toutes les autorisations vrai/faux/tableau

Les autorisations sont définies truepour autoriser l'accès, falsepour refuser l'accès et arraypour autoriser uniquement l'accès aux champs spécifiés. deleteet findne sont pas acceptés et sont traités de la même manière arrays'ils sont définis . Si l'autorisation spécifiée n'existe pas, les autorisations sous le même sujet seront mises en correspondance. Si aucun des deux n'existe, interrogez à nouveau le sujet du niveau de priorité suivant.arraytrue*

Par exemple, dans l'exemple ci-dessus, si vous devez définir useruniquement read titleet detailautoriser les autres à read title, vous pouvez le définir comme ceci :

1 2 3 4 5 6 7 8 9 10 11 12 13 14
{ "*": { "*": false, "read": ['title'] }, "57fbbdb0a2400000": { "*": true }, "roles": { "user": { "read": ['title', 'detail'] } } }

Autorisations d'objet

Les autorisations définies sur le modèle sont les autorisations de la classe entière. Si vous devez définir des autorisations sur des objets spécifiques, vous pouvez le faire en définissant OACL :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
module.exports = db => { db.define('person', { name: String, sex: ["male", "female"], age: Number }, { ACL: function(session) { return { "*": { "*": false } } }, OACL: function(session) { var _acl = {}; if(this.id === session.id) _acl[session.id] = { "*": true }; return _acl; } }); };

Dans cet exemple, lorsque le visiteur est lui-même l'objet, toutes les opérations seront autorisées, sinon tout accès sera interdit. Les autorisations sont vérifiées comme suit :

  • person[57fbbdb0a2400000]=>OACL
  • person=>ACL

Autorisations d'objet étendues

Le contrôle des autorisations d'accès des objets étendus est similaire aux autorisations des objets de base. La seule différence est que l'ACL doit être spécifiée séparément :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
module.exports = db => { var Person = db.define('person', { name: String, sex: ["male", "female"], age: Number },{ ACL: function(session) { return { "*": { "read": ['name', 'sex'], "extends": { "pets": { "read": true, "find": true } } } } }, OACL: function(session) { var _acl = {}; if(this.id === session.id) _acl[session.id] = { "*": true, "extends": { "pets": { "*": true } } }; return _acl; } }); var Pet = db.define('pet', { name: String }); Person.hasMany('pets', Pet); };

Dans cette définition, n'importe qui peut vérifier la namesomme des informations personnelles sex, les vérifier et les rechercher librement pets. L'utilisateur lui-même peut exploiter toutes ses propres données et disposer d'autorisations complètes pour les informations sur ses propres animaux de compagnie.

Lors de la vérification des autorisations d'accès aux objets étendus, les autorisations d'objet et les autorisations d'objet étendues sont vérifiées séparément. Par exemple, la requête suivante :

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

Les autorisations sont vérifiées comme suit :

  • pets[57fbbdb0a2400007]=>OACL
  • person[57fbbdb0a2400000]=> OACL=> extends=>pets
  • person=> ACL=> extends=>pets
  • pets=>ACL

Fonction

Des API peuvent être définies pour le modèle et des opérations de données complexes peuvent être effectuées via des fonctions personnalisées.

La plupart des autorisations peuvent être contrôlées via ACL, et les autorisations basées sur les objets n'ont pas besoin d'être implémentées via Function. La fonction peut être utilisée pour compléter les autorisations basées sur les données, telles que l'octroi d'autorisations à différents groupes d'utilisateurs en fonction du statut d'approbation. Et de multiples modifications, comme la nécessité de modifier plusieurs enregistrements de base de données.

Dessiner un modèle de données

Après avoir terminé la définition des données, vous pouvez utiliser pour app.diagram()dessiner le diagramme de classes de format du modèle de données svg. Lors de l'enregistrement dans un fichier, vous obtiendrez une image similaire à la suivante : diagramme