Module communautaire génial

fib-app

framework API de base de l'application fibjs

Installer

1
npm install fib-app [--save]

Tester

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

Parmi eux, person est le module de définition de 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 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 demandes, 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 le succès et un 4XX indique l'échec de la demande. Lorsqu'une demande échoue, le corps de la réponse est toujours un objet JSON, mais il contiendra toujours deux champs, code et message, que vous pouvez utiliser pour le débogage. Par exemple, si une demande d'authentification par 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 indique le code d'erreur détaillé.

Pour une requête GET, les données de l'objet sont généralement renvoyées. En fonction de 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:

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 spéciale, qui ne peuvent pas être modifiés via l'API. Ils sont id , updatedAt , createdAt , createdBy .

Les champs uniques id , updatedAt , createdAt seront automatiquement créés et modifiés. createdBy doit spécifier le type par lui-même.

API d'accès aux objets de base

Après avoir terminé cette définition de données, vous aurez directement 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 AVOIR Lire l'objet
/1.0/:className/:id METTRE Modifier l'objet
/1.0/:className/:id SUPPRIMER Supprimer l'objet
/1.0/:className AVOIR Liste des 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, y compris l'horodatage objectId et 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 renvoyé est un objet JSON contenant tous les champs fournis par l'utilisateur ainsi que les champs createdAt , updatedAt et id :

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 champ renvoie des keys , un contenu personnalisé peut être renvoyé, des keys vers un contenu à , des chaînes de nom de champ de segmentation:

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

Pour 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

L'objet JSON retourné contiendra les champs updatedAt et id , indiquant l'heure à laquelle la mise à jour s'est produite:

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 des 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 est simplement pour 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 du champ de clés

Comme la requête d'objet, vous pouvez personnaliser les champs contenus dans le résultat renvoyé en définissant des keys lors de l'interrogation de la liste. keys d'un contenu vers , chaînes de nom de champ de segmentation, par exemple:

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

Spécifiera de ne renvoyer que les deux champs name et age .

où condition de filtre

L'objet de requête peut être restreint sous la forme d'un paramètre where .

La valeur du paramètre where doit être encodée en JSON. En d'autres termes, si vous regardez la demande d'URL qui a été réellement envoyée, elle doit d'abord être encodée en JSON, puis encodée en URL. Le moyen le plus simple d'utiliser le paramètre where consiste à 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

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

En plus de correspondre exactement à une valeur donnée, where prend également en charge les méthodes de comparaison, telles que l'inclusion. where paramètre where prend en charge les options suivantes:

clé opération échantillon
eq é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"}}
lt Moins que {"age": {"lt": "24"}}
lte Inférieur ou égal à {"age": {"lte": "24"}}
comme Requête floue {"name": {"like": "% m"}}
pas comme Requête floue {"name": {"not_like": "% m"}}
entre Comparaison d'intervalle {"age": {"between": [22,25]}}
pas entre Comparaison d'intervalle {"age": {"not_between": [22,25]}}
dans énumérer {"name": {"in": ["tom", "lily"]}}
pas dedans énumérer {"nom": {"not_in": ["tom", "lily"]}}
ou Opération OU {"ou": [{"name": "tom"}, {"age": 24}]}

sauter sauter l'enregistrement

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

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

limit renvoie la limite d'enregistrement

L'option de limit vous permet de limiter le nombre d'enregistrements renvoyés. Le nombre de limit valide est de 1 à 1 000 et la valeur par défaut est 100.

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

order spécifie la méthode de tri

Utilisez l'option order pour définir la méthode de tri du jeu de résultats renvoyé. Si 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

L'augmentation du count au moment de la demande peut renvoyer le nombre total d'ensembles de résultats tout en renvoyant le contenu spécifié.

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

À ce stade, le résultat retourné contiendra deux champs, count et results , qui contiennent respectivement le 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 des objets d'extension

En définissant hasOne et hasMany via orm, la relation 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 aux objets étendu

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

Définir l'objet d'extension

La définition d'un objet étendu consiste à établir une connexion entre deux objets indépendants. Par exemple, Tom a adopté un animal de compagnie nommé chat, 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 des objets étendus est très similaire à la lecture des 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 des objets étendus est très similaire à la lecture des 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

ACL

Vous pouvez contrôler les autorisations de données en définissant des ACL de 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 lors de la définition du modèle, cela revient à définir les autorisations par défaut:

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

corps principal

Il existe trois types de descriptions d'objet ACL: l' id utilisateur, le role utilisateur et * . id indique un utilisateur spécifique, le role indique un utilisateur avec un certain rôle et * indique tous les utilisateurs:

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

Lors de la vérification des autorisations, vous allez d'abord faire correspondre les autorisations d' id correspondent, si elles ne sont pas spécifiées, à l'autorité correspondante du role utilisateur, si elle est toujours spécifiée, il vérifie si l'autorité * , si * n'est pas non plus spécifiée, n'a pas l'autorisation.

Par exemple, les Précise de configuration d'autorisation ci - dessus que l' user groupe d'utilisateurs peut lire, l' utilisateur 57fbbdb0a2400000 a toutes les autorisations, alors que d' autres utilisateurs ne disposent pas des autorisations.

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
écrire Modifier l'objet vrai / faux / tableau
supprimer Supprimer l'objet vrai faux
trouver Liste des objets de requête vrai faux
* Faire correspondre toutes les autorisations vrai / faux / tableau

Les autorisations sont définies sur true pour autoriser l'accès, false pour interdire l'accès et array pour autoriser l'accès uniquement aux champs spécifiés. delete et find n'acceptent pas de array , si array est défini, il est considéré comme true . Si l'autorité spécifiée n'existe pas, elle correspond à l'autorité * sous le même principal. S'il n'y en a pas, interrogez à nouveau le sujet avec la priorité suivante.

Par exemple, dans l'exemple ci-dessus, si vous devez définir l' user soit uniquement autorisé à lire le title et les detail , et que d'autres personnes peuvent lire le 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'] } } }

Droits sur les objets

Les autorisations pour 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 l'objet lui-même, toutes les opérations sont autorisées, sinon toutes les visites sont 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 à celui de l'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); };

Dans cette définition, n'importe qui peut vérifier le name et le sex informations personnelles, vérifier et rechercher librement ses pets lui-même peut manipuler toutes ses propres données et a tous les droits sur les informations de son 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 étendu sont vérifiées séparément. Par exemple, la demande 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

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.

Dessinez le modèle de données

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