fib-app
framework api de base de l'application fibjs
Installer
1npm install fib-app [--save]
Test
1npm 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
21const 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 person
trouve le module de définition de modèle, comme suit :
1
2
3
4
5
6
7module.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
4curl -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é. 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
}
]
Domaine spécial
Dans les données d'objet, il y a quatre champs avec des significations spéciales, qui ne peuvent pas être modifiés via l'API. Respectivement id
, updatedAt
, createdAt
, createdBy
.
Où id
, updatedAt
, createdAt
des champs individuels seront automatiquement créés et modifiés. createdBy
Vous 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 | AVOIR | Lire l'objet |
/1.0/:className/:id | METTRE | Modifier l'objet |
/1.0/:className/:id | EFFACER | Supprimer l'objet |
/1.0/:className | AVOIR | 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
4curl -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 :
1curl -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
, updatedAt
et les id
champs :
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 keys
contenu est dans des ,
chaînes de nom de champ divisées :
1curl -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
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"age": 25}' \
http://localhost/1.0/person/57fbbdb0a2400000
JSON objet retourné contiendra updatedAt
et id
champ 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 :
1curl -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 :
1curl -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 keys
champ personnalisé de la liste de requêtes qui renvoie le résultat à contenir. keys
Le contenu est dans une ,
chaîne de nom de champ divisé, par exemple :
1curl -X GET http://localhost/1.0/person?keys=name%2Cage
Le retour spécifié uniquement name
et age
deux champs.
où condition de filtre
By where
peut créer des contraintes sur l'objet de requête en tant que paramètre.
where
La valeur du paramètre doit être encodée JSON. En d'autres termes, si vous regardez la demande d'URL qui a été réellement envoyée, elle doit d'abord être codée JSON, puis codée URL. Le plus simple à utiliser where
comme 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 :
1curl -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, where
les méthodes de comparaison telles que l'inclusion sont également prises en charge. where
Les paramètres prennent en charge les options suivantes :
clé | opération | échantillon |
---|---|---|
é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"}} |
Comme | 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 | OU opération | {"ou":[{"name":"tom"},{"age":24}]} |
ignorer les enregistrements
Par skip
option, vous pouvez spécifier le nombre d'enregistrements à ignorer, pour obtenir un effet de retournement.
1curl -X GET http://localhost/1.0/person?skip=100
limit renvoie la limite d'enregistrement
Par limit
option, vous pouvez limiter le nombre d'enregistrements renvoyés, limit
les chiffres significatifs de 1 à 1000 et les valeurs par défaut à 100.
1curl -X GET http://localhost/1.0/person?limit=100
ordre spécifie la méthode de tri
Par order
jeu d'options pour renvoyer le jeu de résultats de tri, avant que le nom du champ ne contienne -
l'heure inverse.
1curl -X GET http://localhost/1.0/person?order=-id
count renvoie le nombre total de résultats
Lorsqu'il est demandé d'augmenter count
le nombre total, il peut renvoyer un ensemble de résultats du contenu spécifié en même temps.
1curl -X GET http://localhost/1.0/person?count=1&limit=1
A ce stade, les résultats de retour contenant count
et results
deux 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
9module.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 | AVOIR | 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 | AVOIR | 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
4curl -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. par exemple:
1
2
3
4curl -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 :
1curl -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
4curl -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 :
1curl -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 :
1curl -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. 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
25const 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 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 role
et *
, id
représentent un utilisateur spécifique, role
indiquant que l'utilisateur a un rôle, *
ce qui signifie que tous les utilisateurs :
corps principal | décris | priorité |
---|---|---|
identifiant | L'identifiant de l'utilisateur spécifique | 1 |
rôle | Nom du groupe d'utilisateurs | 2 |
* | Tous | 3 |
Lors de la vérification des privilèges, le premier id
correspondra aux droits correspondants, s'ils ne sont pas spécifiés, les role
autorisations 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 user
groupe d'utilisateurs peut lire, l'utilisateur 57fbbdb0a2400000
a 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é | décris | Type autorisé |
---|---|---|
créer | Créer un objet | vrai / faux / tableau |
lire | 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 true
pour autoriser l'accès, false
interdire l'accès pour array
autoriser uniquement les champs d'accès spécifiés. delete
Et find
n'accepte pas array
, si vous définissez array
alors considéré comme true
. Si l'autorisation spécifiée n'existe pas, alors la prochaine correspondance avec l' *
autorité principale . Si aucun n'existe, interrogez à nouveau le sujet de la priorité suivante.
Exemples de l'exemple ci-dessus, s'il est nécessaire de définir user
autorise uniquement la lecture title
et d' detail
autres 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
24module.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
41module.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 name
et 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é de l'objet et l'autorité de l'objet étendu sont vérifiées séparément. Par exemple, la requête suivante :
1curl -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.
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 svg
diagramme de classe de format de modèle de données , les fichiers seront enregistrés dans une image similaire à la suivante :