Module communautaire génial

fib-app

framework api de base de l'application fibjs

Installer

1
npm install fib-app [--save]

Test

1
npm test

Construire 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();

Où se persontrouve le module de définition de modèle, comme suit :

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 standard d'orm, et d'autres fonctions d'orm peuvent également être utilisées, telles que la vérification de type, les événements, etc.

Format de 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 succès d'une requête est indiqué par le code d'état HTTP. Un code d'état 2XX indique la réussite et un 4XX indique l'échec de la demande. Lorsqu'une requête échoue, le corps de la réponse est toujours un objet JSON, mais il contiendra toujours les deux 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 est divisé en trois parties : les trois premiers chiffres 403 indiquent le type d'erreur, 05 indiquent le numéro de la table de données et 01 indiquent le code d'erreur détaillé.

Pour une requête GET, les données de l'objet sont généralement renvoyées. Selon l'adresse de la requête GET, un objet ou un tableau peut être renvoyé. tel que:

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

ou alors:

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

Domaine spécial

Dans les données d'objet, il y a quatre champs avec une signification particulière, qui ne peuvent pas être modifiés via l'API. Respectivement id, updatedAt, createdAt, createdBy.

id, updatedAt, createdAtdes champs individuels seront automatiquement créés et modifiés. createdByVous devez spécifier le type vous-même.

API d'accès aux objets de base

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

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

Créer un nouvel objet

Afin de créer un nouvel objet, une requête POST doit être envoyée à l'URL de la classe, qui doit contenir l'objet lui-même. Par exemple, pour créer l'objet comme mentionné 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 est réussie, la réponse HTTP est 201 Created et le corps de la réponse est un objet JSON, comprenant 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 obtenir son contenu en envoyant une requête GET à l'emplacement de l'en-tête renvoyé. Par exemple, pour obtenir l'objet que nous avons créé ci-dessus :

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

Le corps renvoie un objet JSON contenant tous les éléments fournis par l'utilisateur avec field createdAt, updatedAtet les idchamps :

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" }

Renvoie le champ en fournissant keys, le contenu personnalisé peut être renvoyé. Le keyscontenu est dans des ,chaînes de nom de champ divisées :

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

Reviendra :

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

Modifier l'objet

Afin de modifier les données existantes d'un objet, vous pouvez envoyer une requête PUT à l'URL correspondante de l'objet. Toute clé que vous n'avez pas spécifiée ne sera pas modifiée, vous ne pouvez donc mettre à jour qu'un sous-ensemble des données de l'objet. Par exemple, modifions un champ d'âge de notre objet :

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

JSON objet retourné contiendra updatedAtet idchamp indiquant la mise à jour a eu lieu à la fois:

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

Supprimer l'objet

Pour supprimer un objet, vous pouvez envoyer une demande 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

En envoyant une requête GET à l'URL de la classe, vous pouvez obtenir plusieurs objets à la fois sans aucun paramètre d'URL. Ce qui suit consiste simplement à obtenir 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, et sa 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 définir le keyschamp personnalisé de la liste de requêtes qui renvoie le résultat à contenir. keysLe contenu est dans une ,chaîne de nom de champ divisé, par exemple :

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

Le retour spécifié uniquement nameet agedeux champs.

où condition de filtre

By wherepeut créer des contraintes sur l'objet de requête en tant que paramètre.

whereLa valeur du paramètre doit être encodée JSON. En d'autres termes, si vous regardez la demande d'URL qui est réellement envoyée, elle doit d'abord être codée en JSON, puis en URL. Le plus simple à utiliser wherecomme arguments est d'inclure la clé et la valeur appropriées. Par exemple, si nous voulons rechercher des utilisateurs dont le nom est tom, nous devons construire la requête comme ceci :

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

where La valeur est une chaîne JSON après urlencode, le contenu est :{"name":"tom"}

En plus de correspondre exactement à une valeur donnée, whereles 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 goûter
éq égal {"name":{"eq":"tom"}} ou {"name":"tom"}
ne pas égal à {"nom":{"ne":"tom"}}
gt plus que le {"age":{"gt":"24"}}
gte supérieur ou égal à {"age":{"gte":"24"}}
ll Moins que {"age":{"lt":"24"}}
lte Inférieur ou égal à {"age":{"lte":"24"}}
aimer Requête floue {"nom":{"like":"%m"}}
pas comme Requête floue {"name":{"not_like":"%m"}}
entre Comparaison d'intervalles {"âge":{"entre":[22,25]}}
pas entre Comparaison d'intervalles {"age":{"not_between":[22,25]}}
dans énumérer {"nom":{"in":["tom","lily"]}}
pas dedans énumérer {"name":{"not_in":["tom","lily"]}}
ou alors OU opération {"ou":[{"name":"tom"},{"age":24}]}

ignorer les enregistrements

Par skipoption, vous pouvez spécifier le nombre d'enregistrements à ignorer, pour obtenir un effet de retournement.

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

limit renvoie la limite d'enregistrement

Par limitoption, vous pouvez limiter le nombre d'enregistrements renvoyés, limitles chiffres significatifs de 1 à 1000 et les valeurs par défaut à 100.

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

ordre spécifie la méthode de tri

Par orderjeu d'options pour renvoyer le jeu de résultats de tri, avant que le nom du champ ne contienne -l'heure inverse.

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

count renvoie le nombre total de résultats

Lorsqu'il est demandé d'augmenter countle nombre total, il peut renvoyer un ensemble de résultats du contenu spécifié en même temps.

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

A ce stade, les résultats de retour contenant countet resultsdeux champs, et comprenant chacun un nombre total de résultats :

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, la relation d'association entre les objets peut être définie et reflétée dans 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 étendu aux objets

Voici la définition de l'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 PUBLIER Créer un objet d'extension
/1.0/:className/:id/:extendName/:rid OBTENIR Lire l'objet étendu
/1.0/:className/:id/:extendName/:rid METTRE Modifier l'objet d'extension
/1.0/:className/:id/:extendName/:rid EFFACER Supprimer l'objet d'extension
/1.0/:className/:id/:extendName OBTENIR Interroger la liste des objets étendus

Définir l'objet d'extension

Définir un objet étendu consiste à établir une connexion entre deux objets indépendants. Par exemple, Tom a adopté un animal de compagnie nommé chat, ce qui peut être réalisé avec les opérations suivantes :

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

Dans l'appel, l'identifiant du chat doit être spécifié dans le corps.

Créer un objet d'extension

En créant directement des objets étendus, vous pouvez établir des connexions entre les objets tout en créant des objets. tel que:

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

Un animal de compagnie nommé chat sera créé et une relation d'association avec Tom sera établie.

Lire l'objet étendu

La lecture d'objets étendus est très similaire à la lecture d'objets de base et prend également en charge l'option de 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 d'extension

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

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

Interroger la liste des objets étendus

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

LCA

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

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 lorsque le modèle est défini, cela équivaut à définir les autorisations par défaut :

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

corps principal

Il existe trois descriptions principales d'ACL, user id, user roleet *, idreprésentent un utilisateur spécifique, roleindiquant que l'utilisateur a un rôle, *ce qui signifie que tous les utilisateurs :

corps principal la description priorité
identifiant L'identifiant de l'utilisateur spécifique 1
rôle Nom du groupe d'utilisateurs 2
* Tout 3

Lors de la vérification des privilèges, le premier idcorrespondra aux droits correspondants, s'ils ne sont pas spécifiés, les roleautorisations d' utilisateur correspondantes correspondant toujours si spécifiées, pour voir si l' *autorité désignée , si *elle n'est pas non plus spécifiée, n'a pas d'autorisation.

Par exemple, la configuration d'autorisation ci-dessus, spécifiez que le usergroupe d'utilisateurs peut lire, l'utilisateur 57fbbdb0a2400000a tous les droits, tandis que les autres utilisateurs sans aucune autorisation.

Autorité

ACL classe cinq types d'autorisations en fonction du comportement de l'API :

Autorité la description Type autorisé
créer Créer un objet vrai / faux / tableau
lis Lire l'objet vrai / faux / tableau
écrivez Modifier l'objet vrai / faux / tableau
effacer Supprimer l'objet vrai faux
trouve Liste d'objets de requête vrai faux
* Faire correspondre toutes les autorisations vrai / faux / tableau

Autorisations développées truepour autoriser l'accès, falseinterdire l'accès pour arrayautoriser uniquement les champs d'accès spécifiés. deleteEt findn'accepte pas array, si vous définissez arrayalors considéré comme true. Si l'autorisation spécifiée n'existe pas, alors la prochaine correspondance avec l' *autorité principale . S'il n'en existe aucun, interrogez à nouveau le sujet de la priorité suivante.

Exemples de l'exemple ci-dessus, s'il est nécessaire de définir userautorise uniquement la lecture titleet d' detailautres peuvent être lus title, il peut être défini de telle sorte que :

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 de l'ensemble de la classe sont définies sur le modèle. Si vous devez définir des autorisations pour des objets spécifiques, vous pouvez définir OACL pour obtenir :

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 le sujet, toutes les opérations seront autorisées, sinon toutes les visites seront interdites. Les autorisations seront vérifiées selon les étapes suivantes :

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

Autorisations d'objet étendues

Le contrôle d'autorisation d'accès de l'objet étendu est similaire à l'autorisation d'objet de base, la seule différence est qu'il doit être spécifié séparément dans l'ACL :

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); };

Cette définition, n'importe qui peut accéder aux informations personnelles nameet sex, et accéder librement et le rechercher pets, je suis l'utilisateur peut exploiter toutes leurs données, et tous les droits d'avoir leurs propres informations sur l'animal de compagnie.

Lors de la vérification de l'autorité d'accès de l'objet étendu, l'autorité d'objet et l'autorité d'objet étendue 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 seront vérifiées selon les étapes suivantes :

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

Une fonction

Des API peuvent être définies pour le modèle et des opérations de données complexes peuvent être effectuées en personnalisant la fonction.

La grande majorité des autorisations peuvent être contrôlées par ACL et aucune fonction n'est requise pour compléter les autorisations basées sur les objets. 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 de l'état d'approbation. Et plusieurs modifications, telles que la nécessité de modifier plusieurs enregistrements de base de données.

Dessiner le modèle de données

Une fois que la définition des données peut être utilisée app.diagram()pour dessiner un svgdiagramme de classe de format de modèle de données , les fichiers seront enregistrés dans une image similaire à la suivante : diagramme