application fib
cadre API de base de l'application fibjs
Installer
1npm install fib-app [--save]
Test
1npm 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
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ù person
se trouve le module Définition du modèle, le contenu est le suivant :
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 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
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 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.createdAt
createdBy
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
4curl -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 :
1curl -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 createdAt
champs updatedAt
etid
:
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é, keys
qui est une ,
chaîne de noms de champs séparés par :
1curl -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
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"age": 25}' \
http://localhost/1.0/person/57fbbdb0a2400000
L'objet JSON renvoyé contiendra updatedAt
des id
champs 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 :
1curl -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 :
1curl -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 keys
personnaliser les champs inclus dans les résultats renvoyés en les définissant lors de l'interrogation de la liste. keys
Le contenu est une ,
chaîne de noms de champs séparés par , par exemple :
1curl -X GET http://localhost/1.0/person?keys=name%2Cage
Précisera que seuls les champs name
et age
seront renvoyés.
où état du filtre
where
L'objet requête peut être contraint sous forme de paramètres.
where
La 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 where
maniè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 :
1curl -X GET http://localhost/1.0/person?where=%7B%22name%22%3A%22tom%22%7D
where
La 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, where
des 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 |
---|---|---|
é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.
1curl -X GET http://localhost/1.0/person?skip=100
limit renvoie la limite d'enregistrement
Grâce à limit
cette option, vous pouvez limiter le nombre d'enregistrements renvoyés. limit
Les nombres valides sont de 1 à 1 000 et la valeur par défaut est 100.
1curl -X GET http://localhost/1.0/person?limit=100
order précise la méthode de tri
Utilisez order
l'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.
1curl -X GET http://localhost/1.0/person?order=-id
count renvoie le nombre total de résultats
Incrémenté sur demande count
Nombre total d'ensembles de résultats pouvant être renvoyés lors du renvoi du contenu spécifié.
1curl -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 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
9module.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
4curl -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
4curl -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 :
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 étendu
La suppression d'un objet étendu ne supprime pas l'objet lui-même, elle dissout uniquement la relation entre les objets :
1curl -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 :
1curl -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
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 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 role
et *
, id
qui représentent un utilisateur spécifique, role
repré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 id
aux autorisations correspondantes. S'il n'est pas spécifié, correspondra role
aux 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, user
le groupe d'utilisateurs est spécifié pour pouvoir lire. L'utilisateur 57fbbdb0a2400000
dispose 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 true
pour autoriser l'accès, false
pour refuser l'accès et array
pour autoriser uniquement l'accès aux champs spécifiés. delete
et find
ne sont pas acceptés et sont traités de la même manière array
s'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.array
true
*
Par exemple, dans l'exemple ci-dessus, si vous devez définir user
uniquement read title
et detail
autoriser 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
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 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
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);
};
Dans cette définition, n'importe qui peut vérifier la name
somme 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 :
1curl -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 :