Module communautaire génial

fib-app

cadre api de base de l'application fibjs

Installer

1
npm install fib-app [--save]

Tester

1
npm test

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

person est le module de définition de modèle et 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 peut également utiliser d'autres fonctions orm, telles que la vérification de type, les événements, etc.

Format de données API

Pour les demandes POST et PUT, le corps de la demande doit être au format JSON et le type de contenu 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 demande est indiqué par le code d'état HTTP. Un code d'état 2XX indique la réussite et un 4XX indique un échec de la demande. Lorsqu'une demande échoue, le corps de la réponse est toujours un objet JSON, mais il contient toujours deux champs, code et message, que vous pouvez utiliser pour déboguer. Par exemple, si une demande d'autorisation échoue, les informations suivantes seront retourné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 403 indiquent le type d'erreur, 05 indique le numéro du tableau de données et 01 indique le code d'erreur détaillé.

Pour les requêtes GET, les 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é. 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

Il y a quatre champs avec des significations spéciales dans les données d'objet, qui ne peuvent pas être modifiés via l'API. Ils sont id , updatedAt , createdAt , createdBy .

Les champs individuels id , updatedAt , createdAt seront automatiquement créés et modifiés. createdBy doit spécifier son propre type.

API d'accès aux objets de base

Après avoir terminé cette définition de données, nous avons directement un ensemble d'appels d'interface conformes à la spécification REST api:

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 un objet
/1.0/:className/:id SUPPRIMER Supprimer un objet
/1.0/:className AVOIR Liste des objets de requête

Créer un nouvel objet

Afin de créer un nouvel objet, une demande 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 décrit 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

Une fois la création réussie, la réponse HTTP est 201 Created et le corps de la réponse est un objet JSON qui contient les horodatages 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 demande GET à l'emplacement de l'en-tête retourné. 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 les keys retour de champ, le contenu personnalisé peut être renvoyé, les keys d'un contenu à , les 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 un objet

Pour modifier les données d'un objet, vous pouvez envoyer une demande PUT à l'URL correspondante de l'objet. Toute clé que vous ne spécifiez pas ne changera pas, vous ne pouvez donc mettre à jour qu'un sous-ensemble des données d'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 quand la mise à jour s'est produite:

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

Supprimer un objet

Pour supprimer un objet, vous pouvez envoyer une demande DELETE à l'URL de l'objet spécifié, telle que:

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

Liste des objets de requête

Vous pouvez obtenir plusieurs objets à la fois en envoyant une demande GET à l'URL de la classe sans aucun paramètre d'URL. Voici un moyen simple d'obtenir tous les utilisateurs:

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

La valeur renvoyée est un objet JSON qui contient 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 clés

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

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

Précisera que seuls deux champs name et age sont retournés.

où filtre

L'objet de requête peut être contraint sous la forme du paramètre where .

La valeur du paramètre where doit être codée JSON. Autrement dit, si vous regardez la demande d'URL qui a été réellement émise, elle doit d'abord être codée en JSON, puis codée dans l'URL. La façon la plus simple d'utiliser le paramètre where consiste à inclure la clé et la valeur requises. Par exemple, si nous voulons rechercher un utilisateur nommé tom, nous devons construire une requête comme celle-ci:

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

where est une chaîne JSON après le code url, 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 {"âge": {"gt": "24"}}
gte 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": {"comme": "% m"}}
pas comme Requête floue {"nom": {"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": {"dans": ["tom", "lily"]}}
pas dedans énumérer {"nom": {"not_in": ["tom", "lily"]}}
ou OU opération {"ou": [{"nom": "tom"}, {"age": 24}]}

sauter les enregistrements

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

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

limite renvoie la limite d'enregistrement

Grâce à l'option de limit , vous pouvez limiter le nombre d'enregistrements renvoyés, le nombre effectif de limit est de 1-1000, la valeur par défaut est 100.

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

l'ordre spécifie la méthode de tri

Avec l'option de order , vous pouvez définir la méthode de tri du jeu de résultats renvoyé. Lorsque le nom du champ contient- - 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 lors 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 renvoyé contiendra deux champs, count et 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 des objets étendus

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 de l'API de l'objet d'extension:

url méthode action
/1.0/:className/:id/:extendName METTRE Définir un objet étendu
/1.0/:className/:id/:extendName PUBLIER Créer un objet d'extension
/1.0/:className/:id/:extendName/:rid AVOIR Lire des objets étendus
/1.0/:className/:id/:extendName/:rid METTRE Modifier des objets étendus
/1.0/:className/:id/:extendName/:rid SUPPRIMER Supprimer un objet étendu
/1.0/:className/:id/:extendName AVOIR Interroger la liste d'objets étendue

Définir un objet étendu

La définition d'un objet étendu consiste à établir une connexion entre deux objets indépendants. Par exemple, Tom adopte un animal de compagnie nommé chat, ce qui peut être réalisé avec l'opération suivante:

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

La création directe d'objets étendus vous permet d'établir des connexions entre les objets lors de leur création. 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 sera associé à tom.

Lire des objets étendus

La lecture d'objets étendus est 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 des objets étendus

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 un objet étendu

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

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

Interroger la liste d'objets étendue

La liste d'objets étendue de requête est très similaire à la liste d'objets de base de requête et prend également en charge des options telles que les clés et le filtrage des conditions:

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

ACL

Vous pouvez contrôler les autorisations de donné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: String, note: String }, { ACL: function(session) { return { "*": { "*": false }, "57fbbdb0a2400000": { "*": true }, "roles": { "user": { "read": true } } }; } }); };

Si l'ACL n'est pas spécifié lorsque le modèle est défini, cela revient à définir les autorisations par défaut:

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

corps principal

Il existe trois types de description de corps d'ACL, l' id utilisateur, le role utilisateur et * , l' id représente un utilisateur spécifique, le role représente un utilisateur avec un certain rôle, * représente tous les utilisateurs

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

Lors de la vérification des autorisations, vous devez d'abord faire correspondre les autorisations id correspondantes, si elles ne sont pas spécifiées, le role utilisateur correspondant à l'autorité correspondante, si elle est toujours spécifiée, elle vérifie si l'autorité * , si * n'est pas également spécifiée, ne dispose pas de l'autorisation.

Par exemple, la configuration des autorisations ci-dessus spécifie que le groupe d' user utilisateur peut être lu. L'utilisateur 57fbbdb0a2400000 dispose de toutes les autorisations, tandis que les autres utilisateurs n'ont aucune autorisation.

Autorité

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

Autorité la description Types autorisés
créer Créer un objet true / false / array
lis Lire l'objet true / false / array
écrire Modifier un objet true / false / array
supprimer Supprimer un objet vrai faux
trouver Liste des objets de requête vrai faux
* Correspond à toutes les autorisations true / false / array

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

Par exemple, dans l'exemple ci-dessus, si vous devez configurer l' user autoriser uniquement la lecture du title et des detail , et que d'autres personnes puissent 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'] } } }

Autorisations d'objet

Les autorisations de la classe entière sont définies sur le modèle. Si vous devez définir des autorisations sur 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 tout accès est interdit. Les autorisations seront vérifiées selon les étapes suivantes:

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

Autorisations étendues sur les objets

Le contrôle des droits d'accès des objets étendus est similaire aux droits 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 le name et le sex informations personnelles et rechercher et rechercher librement ses pets compagnie.

Lors de la vérification des droits d'accès des objets étendus, les droits d'objet et les droits d'objet étendu sont vérifiés 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

Une fonction

Des API peuvent être définies pour les modèles. Pour les opérations de données complexes, des fonctions personnalisées peuvent être utilisées pour terminer.

La grande majorité des autorisations peut être complétée via le contrôle ACL, sans avoir besoin de compléter les autorisations basées sur les objets 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 plusieurs modifications, telles que la nécessité de modifier plusieurs enregistrements de base de données.

Tracer 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 classe au format svg du modèle de données et l'enregistrer dans un fichier pour obtenir une image similaire à la suivante: diagramme