фиб-приложение
Базовая платформа API приложения fibjs
Установить
1npm install fib-app [--save]
Тест
1npm test
Создать базовый сценарий
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();
Там , где person
находится модуль определения модели, его содержимое следующее:
1
2
3
4
5
6
7module.exports = db => {
db.define('person', {
name: String,
sex: ["male", "female"],
age: Number
});
};
Это стандартное определение ORM, и вы также можете использовать другие функции ORM, такие как проверка типов, события и т. д.
Формат данных API
Для запросов POST и PUT тело запроса должно быть в формате JSON, а для Content-Type заголовка HTTP должно быть установлено значение 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
Для всех запросов формат ответа — объект JSON.
Был ли запрос успешным или нет, указывается кодом состояния HTTP. Код состояния 2XX указывает на успех, а код состояния 4XX указывает на то, что запрос не выполнен. В случае сбоя запроса тело ответа по-прежнему является объектом JSON, но оно всегда содержит поля кода и сообщения, которые можно использовать для отладки. Например, если запрос на аутентификацию разрешений завершается неудачно, будет возвращена следующая информация:
1
2
3
4{
"code": 4030501,
"message": "The operation isn’t allowed for clients due to class-level permissions."
}
Код кода разделен на три части: первые три цифры 403 обозначают тип ошибки, 05 представляет номер паспорта и 01 представляет подробный код ошибки.
Для запросов GET обычно возвращаются данные объекта.В зависимости от адреса запроса GET может быть возвращен объект или массив. например:
1
2
3
4
5{
"name": "tom",
"sex": "male",
"age": 23
}
или:
1
2
3
4
5
6
7
8
9
10
11
12[
{
"name": "tom",
"sex": "male",
"age": 23
},
{
"name": "lily",
"sex": "female",
"age": 22
}
]
специальные поля
В данных объекта есть четыре поля со специальным значением, которые нельзя изменять через API. id
Они , updatedAt
, createdAt
, соответственно createdBy
.
id
Среди них будут автоматически создаваться и изменяться отдельные поля updatedAt
. Тип необходимо указать самостоятельно.createdAt
createdBy
Базовый API доступа к объектам
После завершения такого определения данных вы сразу получите набор интерфейсных вызовов, соответствующих спецификации REST API:
URL | метод | действие |
---|---|---|
/1.0/:имякласса | ПОЧТА | Создать новый объект |
/1.0/:имякласса/:id | ПОЛУЧАТЬ | Чтение объекта |
/1.0/:имякласса/:id | ПОМЕЩАТЬ | Изменить объект |
/1.0/:имякласса/:id | УДАЛИТЬ | Удалить объект |
/1.0/:имякласса | ПОЛУЧАТЬ | Список объектов запроса |
Создать новый объект
Чтобы создать новый объект, необходимо отправить запрос POST на URL-адрес класса, который должен включать сам объект. Например, чтобы создать объект, показанный выше:
1
2
3
4curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "tom","sex":"male","age":23}' \
http://localhost/1.0/person
В случае успешного создания HTTP-возврат имеет значение 201 Created, а тело ответа представляет собой объект JSON, содержащий objectId и временную метку CreateAt нового объекта:
1
2
3
4{
"createdAt": "2017-11-25T01:39:35.931Z",
"id": "57fbbdb0a2400000"
}
Чтение объекта
Когда вы создаете объект, вы можете получить его содержимое, отправив запрос GET в Location в возвращенном заголовке. Например, чтобы получить объект, который мы создали выше:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000
Возвращаемое тело представляет собой объект JSON, содержащий все поля, предоставленные пользователем createdAt
, а также поля updatedAt
и 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"
}
Установив поле возврата keys
, вы можете настроить возвращаемый контент, keys
который представляет собой ,
строку имен полей, разделенных:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000?keys=name%2Csex
вернется:
1
2
3
4{
"name": "tom",
"sex": "male"
}
Изменить объект
Чтобы изменить существующие данные объекта, вы можете отправить запрос PUT на соответствующий URL-адрес объекта. Любые ключи, которые вы не укажете, не будут изменены, поэтому вы можете обновить только подмножество данных объекта. Например, изменим поле возраста нашего объекта:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"age": 25}' \
http://localhost/1.0/person/57fbbdb0a2400000
Возвращенный объект JSON будет содержать updatedAt
поля id
, указывающие, когда произошло обновление:
1
2
3
4{
"updatedAt": "2017-11-25T01:39:35.931Z",
"id": "57fbbdb0a2400000"
}
Удалить объект
Чтобы удалить объект, вы можете отправить запрос DELETE на URL-адрес указанного объекта, например:
1curl -X DELETE http://localhost/1.0/person/57fbbdb0a2400000
Список объектов запроса
Вы можете получить несколько объектов одновременно, отправив запрос GET на URL-адрес класса без каких-либо параметров URL-адреса. Вот как просто получить всех пользователей:
1curl -X GET http://localhost/1.0/person
Возвращаемое значение — это объект JSON, содержащий поле результатов, значение которого представляет собой список объектов:
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"
}
]
настройка поля ключей
Как и в случае с запросом объекта, вы можете keys
настроить поля, включенные в возвращаемые результаты, задав их при запросе списка. keys
Содержимое представляет собой ,
строку имен полей, разделенных , например:
1curl -X GET http://localhost/1.0/person?keys=name%2Cage
Укажем, что будут возвращены только поля name
и .age
где состояние фильтра
where
Объект запроса может быть ограничен в форме параметров.
where
Значение параметра должно быть закодировано в формате JSON. То есть, если вы посмотрите на фактический запрос URL-адреса, он должен сначала быть закодирован в формате JSON, а затем в кодировке URL-адреса. Самый простой where
способ использования параметров — включить соответствующий ключ и значение. Например, если бы мы хотели найти пользователей по имени Том, мы бы построили запрос следующим образом:
1curl -X GET http://localhost/1.0/person?where=%7B%22name%22%3A%22tom%22%7D
where
Значение представляет собой строку JSON в кодировке urlencode, содержимое:{"name":"tom"}
Помимо точного сопоставления заданного значения, where
также поддерживаются такие методы сравнения, как включение. where
Параметры поддерживают следующие параметры:
ключ | операция | образец |
---|---|---|
экв. | равный | {"name":{"eq":"tom"}} или {"name":"tom"} |
пе | не равен | {"имя":{"не":"том"}} |
гт | больше, чем | {"возраст":{"gt":"24"}} |
гте | больше или равно | {"возраст":{"gte":"24"}} |
лт | меньше, чем | {"возраст":{"lt":"24"}} |
лте | меньше или равно | {"возраст":{"lte":"24"}} |
нравиться | нечеткий запрос | {"имя":{"нравится":"%m"}} |
не как | нечеткий запрос | {"name":{"not_like":"%m"}} |
между | Сравнение интервалов | {"возраст":{"между":[22,25]}} |
не_между | Сравнение интервалов | {"возраст":{"not_between":[22,25]}} |
в | перечислять | {"name":{"in":["том","лилия"]}} |
не в | перечислять | {"name":{"not_in":["том","лилия"]}} |
или | операция ИЛИ | {"или":[{"имя":"том"},{"возраст":24}]} |
пропустить пропустить записи
Благодаря skip
опции вы можете пропустить указанное количество записей, чтобы добиться эффекта перелистывания страниц.
1curl -X GET http://localhost/1.0/person?skip=100
лимит возвращает лимит записи
С помощью limit
этой опции вы можете ограничить количество возвращаемых записей. limit
Допустимые числа: 1–1000, значение по умолчанию — 100.
1curl -X GET http://localhost/1.0/person?limit=100
order определяет метод сортировки
Используйте order
эту опцию, чтобы установить метод сортировки возвращаемого набора результатов. Если перед ним указано имя поля, -
оно находится в обратном порядке.
1curl -X GET http://localhost/1.0/person?order=-id
count возвращает общее количество результатов
Увеличивается по запросу count
Общее количество наборов результатов, которые могут быть возвращены при возврате указанного содержимого.
1curl -X GET http://localhost/1.0/person?count=1&limit=1
На этот раз возвращаемый результат будет содержать два поля: count
и results
, содержащие общее количество и результат соответственно:
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"
}
]
}
Создать объект расширения
Определив hasOne и hasMany через ORM, вы можете определить связь между объектами и отразить ее в API, например:
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 доступа к объектам
Ниже приведено определение API объекта расширения:
URL | метод | действие |
---|---|---|
/1.0/:имякласса/:id/:extendName | ПОМЕЩАТЬ | Установить объект расширения |
/1.0/:имякласса/:id/:extendName | ПОЧТА | Создать объект расширения |
/1.0/:имякласса/:id/:extendName/:rid | ПОЛУЧАТЬ | Чтение объекта расширения |
/1.0/:имякласса/:id/:extendName/:rid | ПОМЕЩАТЬ | Изменить объект расширения |
/1.0/:имякласса/:id/:extendName/:rid | УДАЛИТЬ | Удалить расширенный объект |
/1.0/:имякласса/:id/:extendName | ПОЛУЧАТЬ | Запросить расширенный список объектов |
Установить объект расширения
Установка объекта расширения означает установление связи между двумя независимыми объектами. Например, если Том заведет домашнее животное по имени Кот, для этого он может использовать следующие операции:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"id": "57fbbdb0a2400007"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets
В вызове в теле нужно указать идентификатор кота.
Создать объект расширения
Непосредственное создание расширенных объектов позволяет устанавливать связи между объектами при создании объектов. например:
1
2
3
4curl -X POST \
-H "Content-Type: application/json" \
-d '{"name": "cat"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets
Домашнее животное по имени Кот будет создано и связано с Томом.
Чтение объекта расширения
Чтение расширенных объектов очень похоже на чтение базовых объектов, а также поддерживает опцию ключей:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Изменить объект расширения
Чтение расширенных объектов очень похоже на чтение базовых объектов:
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"name": "cat 1"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Удалить расширенный объект
Удаление расширенного объекта не удаляет сам объект, а только разрушает связь между объектами:
1curl -X DETELE http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Запросить расширенный список объектов
Запрос расширенного списка объектов очень похож на запрос основного списка объектов и также поддерживает такие параметры, как ключи и условную фильтрацию:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets
список управления доступом
Разрешениями на данные можно управлять путем определения 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
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
}
}
};
}
});
};
Если при определении модели не указан ACL, это эквивалентно установке разрешений по умолчанию:
1
2
3
4
5{
"*": {
"*": true
}
}
основная часть
Существует три типа описаний субъектов ACL: user id
, user role
и *
, id
которые представляют конкретного пользователя, role
представляют пользователей с определенной ролью и *
представляют всех пользователей:
основная часть | описывать | приоритет |
---|---|---|
ИДЕНТИФИКАТОР | конкретный идентификатор пользователя | 1 |
роль | Имя группы пользователей | 2 |
* | Все | 3 |
При проверке разрешений оно сначала будет соответствовать id
соответствующим разрешениям. Если не указано, то соответствует role
соответствующим разрешениям пользователя. Если оно все еще указано, проверьте, *
указаны ли разрешения. Если *
не указано, разрешения нет.
Например, в приведенной выше конфигурации разрешений user
группа пользователей указана с возможностью чтения. Пользователь 57fbbdb0a2400000
имеет все разрешения, но другие пользователи не имеют никаких разрешений.
Разрешения
ACL классифицирует разрешения на пять категорий в зависимости от поведения API:
Разрешения | описывать | разрешенные типы |
---|---|---|
создавать | Создать объект | правда/ложь/массив |
читать | Чтение объекта | правда/ложь/массив |
писать | Изменить объект | правда/ложь/массив |
удалить | Удалить объект | правда/ложь |
находить | Список объектов запроса | правда/ложь |
* | Соответствовать всем разрешениям | правда/ложь/массив |
Разрешения настроены так true
, чтобы разрешить доступ false
, запретить доступ и array
разрешить доступ только к указанным полям. delete
и find
не принимаются и обрабатываются одинаково, array
если установлены . Если указанное разрешение не существует, будут сопоставлены разрешения для того же субъекта. Если ни один из них не существует, снова запросите субъект следующего уровня приоритета.array
true
*
Например, в приведенном выше примере, если вам нужно установить user
только чтение title
и detail
разрешить чтение другим title
, вы можете установить это следующим образом:
1
2
3
4
5
6
7
8
9
10
11
12
13
14{
"*": {
"*": false,
"read": ['title']
},
"57fbbdb0a2400000": {
"*": true
},
"roles": {
"user": {
"read": ['title', 'detail']
}
}
}
Разрешения объекта
Разрешения, установленные для модели, являются разрешениями всего класса. Если вам нужно установить разрешения для определенных объектов, вы можете сделать это, установив 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;
}
});
};
В этом примере, когда посетителем является сам объект, все операции будут разрешены, в противном случае любой доступ будет запрещен. Разрешения проверяются следующим образом:
person[57fbbdb0a2400000]
=>OACL
person
=>ACL
Расширенные права доступа к объектам
Управление правами доступа расширенных объектов аналогично правам доступа базовых объектов, с той лишь разницей, что 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);
};
В этом определении каждый может проверить name
сумму личной информации sex
, а также свободно проверять и искать ее.Пользователь pets
сам может управлять всеми своими данными и иметь полные разрешения на информацию о своих домашних животных.
При проверке прав доступа к расширенным объектам права доступа к объектам и разрешения расширенных объектов проверяются отдельно. Например, следующий запрос:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007
Разрешения проверяются следующим образом:
pets[57fbbdb0a2400007]
=>OACL
person[57fbbdb0a2400000]
=>OACL
=>extends
=>pets
person
=>ACL
=>extends
=>pets
pets
=>ACL
Функция
Для модели можно определить API, а сложные операции с данными можно выполнять с помощью пользовательских функций.
Большинством разрешений можно управлять с помощью ACL, а разрешения на основе объектов не обязательно реализовывать с помощью Function. Функцию можно использовать для предоставления разрешений на основе данных, например предоставления разрешений различным группам пользователей на основе статуса утверждения. И многочисленные модификации, такие как необходимость изменения нескольких записей базы данных.
Нарисовать модель данных
После завершения определения данных вы можете использовать для app.diagram()
рисования диаграмму классов формата модели данных.При svg
сохранении в файл вы получите изображение, подобное следующему: