aplicación fib
marco básico de api da aplicación fibjs
Instalar
1npm install fib-app [--save]
Proba
1npm test
Crear guión básico
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();
Onde person
está o módulo de definición do modelo, o contido é o seguinte:
1
2
3
4
5
6
7module.exports = db => {
db.define('person', {
name: String,
sex: ["male", "female"],
age: Number
});
};
Esta é unha definición ORM estándar, e tamén pode usar outras funcións ORM, como a verificación de tipos, eventos, etc.
Formato de datos API
Para as solicitudes POST e PUT, o corpo da solicitude debe estar en formato JSON e o tipo de contido da cabeceira HTTP debe configurarse en 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
Para todas as solicitudes, o formato de resposta é un obxecto JSON.
O código de estado HTTP indica se unha solicitude foi exitosa ou non. Un código de estado 2XX indica éxito, mentres que un código de estado 4XX indica que a solicitude fallou. Cando unha solicitude falla, o corpo da resposta segue sendo un obxecto JSON, pero sempre contén os campos de código e mensaxe, que podes usar para depurar. Por exemplo, se falla unha solicitude de autenticación de permisos, devolverase a seguinte información:
1
2
3
4{
"code": 4030501,
"message": "The operation isn’t allowed for clients due to class-level permissions."
}
O código de código divídese en tres partes: os tres primeiros díxitos 403 representan o tipo de erro, 05 o número da folla de datos e 01 o código de erro detallado.
Para as solicitudes GET, adoitan devolverse os datos do obxecto. Segundo o enderezo da solicitude GET, pódese devolver un obxecto ou unha matriz. por exemplo:
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
}
]
campos especiais
Nos datos do obxecto, hai catro campos con significados especiais que non se permiten cambiar a través da API. Son id
, updatedAt
, createdAt
, respectivamente createdBy
.
Entre eles id
, updatedAt
, createdAt
crearanse e modificaranse automaticamente campos únicos. createdBy
Debe especificar o tipo vostede mesmo.
API básica de acceso a obxectos
Despois de completar esta definición de datos, terá directamente un conxunto de chamadas de interface que cumpran coa especificación da API REST:
url | método | acción |
---|---|---|
/1.0/:className | POST | Crea un novo obxecto |
/1.0/:className/:id | CONSEGUIR | Ler obxecto |
/1.0/:className/:id | POÑER | Modificar obxecto |
/1.0/:className/:id | ELIMINAR | Eliminar obxecto |
/1.0/:className | CONSEGUIR | Consulta a lista de obxectos |
Crea un novo obxecto
Para crear un novo obxecto, debe enviarse unha solicitude POST ao URL da clase, que debe incluír o propio obxecto. Por exemplo, para crear o obxecto mostrado arriba:
1
2
3
4curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "tom","sex":"male","age":23}' \
http://localhost/1.0/person
Cando a creación é exitosa, o retorno HTTP é 201 Created, e o corpo da resposta é un obxecto JSON que contén o objectId e createdAt timestamp do novo obxecto:
1
2
3
4{
"createdAt": "2017-11-25T01:39:35.931Z",
"id": "57fbbdb0a2400000"
}
Ler obxecto
Cando creas un obxecto, podes recuperar o seu contido enviando unha solicitude GET á localización da cabeceira devolta. Por exemplo, para obter o obxecto que creamos anteriormente:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000
O corpo devolto é un obxecto JSON que contén todos os campos proporcionados polo usuario máis os campos createdAt
, updatedAt
e 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"
}
Ao configurar o campo de devolución keys
, pode personalizar o contido devolto, keys
que é unha ,
cadea de nomes de campo separados por:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000?keys=name%2Csex
volverá:
1
2
3
4{
"name": "tom",
"sex": "male"
}
Modificar obxecto
Para cambiar os datos existentes dun obxecto, pode enviar unha solicitude PUT ao URL correspondente do obxecto. As claves que non especifiquen non se modificarán, polo que só pode actualizar un subconxunto dos datos do obxecto. Por exemplo, imos cambiar un campo de idade do noso obxecto:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"age": 25}' \
http://localhost/1.0/person/57fbbdb0a2400000
O obxecto JSON devolto conterá updatedAt
e id
campos que indican cando se produciu a actualización:
1
2
3
4{
"updatedAt": "2017-11-25T01:39:35.931Z",
"id": "57fbbdb0a2400000"
}
Eliminar obxecto
Para eliminar un obxecto, pode enviar unha solicitude DELETE ao URL do obxecto especificado, por exemplo:
1curl -X DELETE http://localhost/1.0/person/57fbbdb0a2400000
Consulta a lista de obxectos
Podes obter varios obxectos á vez enviando unha solicitude GET ao URL da clase, sen ningún parámetro de URL. Aquí tes como conseguir simplemente todos os usuarios:
1curl -X GET http://localhost/1.0/person
O valor devolto é un obxecto JSON que contén o campo de resultados, cuxo valor é unha lista de obxectos:
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"
}
]
personalización do campo de claves
Do mesmo xeito que a consulta de obxectos, pode keys
personalizar os campos incluídos nos resultados devoltos configurando cando se consulta a lista. keys
O contido é unha ,
cadea de nomes de campo separados por , por exemplo:
1curl -X GET http://localhost/1.0/person?keys=name%2Cage
Especificará que só se devolverán os campos name
e .age
onde condición do filtro
where
O obxecto de consulta pódese restrinxir en forma de parámetros.
where
O valor do parámetro debe estar codificado en JSON. É dicir, se observas a solicitude de URL real que se fai, primeiro debería codificarse en JSON e despois codificarse en URL. O where
xeito máis sinxelo de usar os parámetros é incluír a clave e o valor axeitados. Por exemplo, se quixeramos buscar usuarios chamados tom, construíriamos a consulta así:
1curl -X GET http://localhost/1.0/person?where=%7B%22name%22%3A%22tom%22%7D
where
O valor é unha cadea JSON codificada en url, o contido é:{"name":"tom"}
Ademais de facer coincidir exactamente un valor determinado, where
tamén se admiten métodos de comparación como a inclusión. where
Os parámetros admiten as seguintes opcións:
chave | operación | mostra |
---|---|---|
eq | iguais | {"name":{"eq":"tom"}} ou {"name":"tom"} |
ne | non igual a | {"name":{"ne":"tom"}} |
gt | máis que o | {"age":{"gt":"24"}} |
gte | maior ou igual a | {"age":{"gte":"24"}} |
lt | menos que | {"age":{"lt":"24"}} |
lte | menor ou igual a | {"age":{"lte":"24"}} |
como | consulta difusa | {"name":{"gústame":"%m"}} |
non_gústame | consulta difusa | {"name":{"not_like":"%m"}} |
entre | Comparación de intervalos | {"idade":{"entre":[22,25]}} |
non_entre | Comparación de intervalos | {"idade":{"non_entre":[22,25]}} |
en | enumerar | {"nome":{"en":["tom","lirio"]}} |
non_en | enumerar | {"name":{"not_in":["tom","lirio"]}} |
ou | OR operación | {"ou":[{"nome":"tom"},{"idade":24}]} |
saltar rexistros
A través skip
da opción, pode saltar o número especificado de rexistros para lograr o efecto de pasar páxina.
1curl -X GET http://localhost/1.0/person?skip=100
límite devolve o límite de rexistro
A través limit
da opción, pode limitar o número de rexistros devoltos. limit
Os números válidos son 1-1000 e o predeterminado é 100.
1curl -X GET http://localhost/1.0/person?limit=100
orde especifica o método de clasificación
Use order
a opción para establecer o método de ordenación do conxunto de resultados devolto. Cando o nome do campo contén antes, -
faise en orde inversa.
1curl -X GET http://localhost/1.0/person?order=-id
count devolve o número total de resultados
Incrementado a petición count
O número total de conxuntos de resultados que se poden devolver mentres se devolve o contido especificado.
1curl -X GET http://localhost/1.0/person?count=1&limit=1
Neste momento, o resultado devolto conterá dous campos: count
e results
, que conteñen o número total e o resultado respectivamente:
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"
}
]
}
Crear obxecto de extensión
Ao definir hasOne e hasMany mediante ORM, pode definir a asociación entre obxectos e reflectila na API, por exemplo:
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 de acceso a obxectos estendido
A seguinte é a definición da API do obxecto de extensión:
url | método | acción |
---|---|---|
/1.0/:className/:id/:extendName | POÑER | Establecer o obxecto de extensión |
/1.0/:className/:id/:extendName | POST | Crear obxecto de extensión |
/1.0/:className/:id/:extendName/:rid | CONSEGUIR | Ler obxecto de extensión |
/1.0/:className/:id/:extendName/:rid | POÑER | Modificar o obxecto de extensión |
/1.0/:className/:id/:extendName/:rid | ELIMINAR | Eliminar obxecto estendido |
/1.0/:className/:id/:extendName | CONSEGUIR | Consulta a lista de obxectos estendida |
Establecer o obxecto de extensión
Establecer un obxecto de extensión é establecer unha relación entre dous obxectos independentes. Por exemplo, se Tom adopta unha mascota chamada gato, pode usar as seguintes operacións para conseguilo:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"id": "57fbbdb0a2400007"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets
Na chamada, o ID do gato debe especificarse no corpo.
Crear obxecto de extensión
A creación directa de obxectos estendidos pode establecer conexións entre obxectos mentres se crean. por exemplo:
1
2
3
4curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "cat"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets
Crearase unha mascota chamada gato e asociarase a Tom.
Ler obxecto de extensión
A lectura de obxectos estendidos é moi semellante á lectura de obxectos base e tamén admite a opción de teclas:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Modificar o obxecto de extensión
A lectura de obxectos estendidos é moi semellante á lectura de obxectos base:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"name": "cat 1"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Eliminar obxecto estendido
A eliminación dun obxecto estendido non elimina o propio obxecto, só disolve a relación entre os obxectos:
1curl -X DETELE http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Consulta a lista de obxectos estendida
Consultar a lista de obxectos estendida é moi semellante á consulta da lista básica de obxectos e tamén admite opcións como claves e filtrado condicional:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets
ACL
Os permisos de datos pódense controlar definindo a ACL do modelo. por exemplo:
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
}
}
};
}
});
};
Se non se especifica ningunha ACL ao definir o modelo, equivale a establecer os permisos predeterminados:
1
2
3
4
5{
"*": {
"*": true
}
}
corpo principal
Hai tres tipos de descricións de asuntos ACL: usuario id
, usuario role
e *
, id
que representan un usuario específico, role
representan usuarios cun determinado rol e *
representan a todos os usuarios:
corpo principal | describir | prioridade |
---|---|---|
ID | ID de usuario específico | 1 |
papel | Nome do grupo de usuarios | 2 |
* | Todos | 3 |
Ao comprobar os permisos, primeiro coincidirá id
cos permisos correspondentes. Se non se especifica, entón coincidirá role
cos permisos correspondentes do usuario. Se aínda se especifica, comprobe se *
os permisos de están especificados. Se *
non se especifica, non hai ningún permiso.
Por exemplo, na configuración de permisos anterior, user
especifícase o grupo de usuarios para poder ler. O usuario 57fbbdb0a2400000
ten todos os permisos, pero os demais usuarios non teñen ningún permiso.
Permisos
ACL clasifica os permisos en cinco categorías en función do comportamento da API:
Permisos | describir | tipos permitidos |
---|---|---|
crear | Crear obxecto | verdadeiro/falso/matriz |
ler | Ler obxecto | verdadeiro/falso/matriz |
escribir | Modificar obxecto | verdadeiro/falso/matriz |
eliminar | Eliminar obxecto | verdadeiro/falso |
atopar | Consulta a lista de obxectos | verdadeiro/falso |
* | Coincide todos os permisos | verdadeiro/falso/matriz |
Os permisos están configurados true
para permitir o acceso, false
para denegar o acceso e array
só para permitir o acceso a campos especificados. delete
e find
non se aceptan e trátanse igual array
se se establecen . Se o permiso especificado non existe, coincidirán os permisos do mesmo asunto. Se non existe ningunha das dúas, consulta de novo o asunto do seguinte nivel de prioridade.array
true
*
Por exemplo, no exemplo anterior, se precisa configurar user
só a lectura title
e detail
permitir que outros lean title
, pode configuralo así:
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"*": {
"*": false,
"read": ['title']
},
"57fbbdb0a2400000": {
"*": true
},
"roles": {
"user": {
"read": ['title', 'detail']
}
}
}
Permisos de obxectos
Os permisos establecidos no Modelo son os permisos de toda a clase. Se precisas establecer permisos en obxectos específicos, podes facelo configurando 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;
}
});
};
Neste exemplo, cando o visitante é o propio obxecto, permitiranse todas as operacións, en caso contrario prohibirase todo o acceso. Os permisos compróbanse do seguinte xeito:
person[57fbbdb0a2400000]
=>OACL
person
=>ACL
Permisos de obxectos estendidos
O control de permisos de acceso dos obxectos estendidos é similar aos permisos dos obxectos básicos. A única diferenza é que a ACL debe especificarse por separado:
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);
};
Nesta definición, calquera pode comprobar a name
suma da información persoal sex
, e libremente consultala e buscala.O pets
propio usuario pode operar todos os seus propios datos e ter permisos completos para a información da súa propia mascota.
Ao comprobar os permisos de acceso para obxectos estendidos, compróbanse por separado os permisos de obxecto e os permisos de obxecto estendidos. Por exemplo, a seguinte solicitude:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Os permisos compróbanse do seguinte xeito:
pets[57fbbdb0a2400007]
=>OACL
person[57fbbdb0a2400000]
=>OACL
=>extends
=>pets
person
=>ACL
=>extends
=>pets
pets
=>ACL
Función
As API pódense definir para o modelo e as operacións de datos complexas pódense completar mediante funcións personalizadas.
A maioría dos permisos pódense controlar mediante ACL, e os permisos baseados en obxectos non precisan implementarse mediante Function. A función pódese usar para completar permisos baseados en datos, como conceder permisos a diferentes grupos de usuarios en función do estado de aprobación. E múltiples modificacións, como a necesidade de modificar varios rexistros de bases de datos.
Debuxar modelo de datos
Despois de completar a definición de datos, pode usar para app.diagram()
debuxar o diagrama de clases de formato do modelo de datos svg
. Cando garde nun ficheiro, obterá unha imaxe similar á seguinte: