フィブアプリ
fibjs アプリケーションの基本的な API フレームワーク
インストール
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 形式である必要があり、HTTP ヘッダーの Content-Type は 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."
}
コードコードは 3 つの部分に分かれており、最初の 3 桁 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 を介して変更することができない特別な意味を持つ 4 つのフィールドがあります。それぞれ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 で、応答の本文は、新しいオブジェクトの objectId と createdAt タイムスタンプを含む JSON オブジェクトです。
1
2
3
4{
"createdAt": "2017-11-25T01:39:35.931Z",
"id": "57fbbdb0a2400000"
}
オブジェクトの読み取り
オブジェクトを作成するとき、返されたヘッダーの Location に GET リクエストを送信することで、そのコンテンツを取得できます。たとえば、上で作成したオブジェクトを取得するには:
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000
createdAt
返される本文は、ユーザー指定のすべてのフィールドに加えて、updatedAt
およびフィールドを含む JSON オブジェクトです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"
}
return field を設定するとkeys
、返されるコンテンツkeys
(以下,
で区切られたフィールド名の文字列) をカスタマイズできます。
1curl -X GET http://localhost/1.0/person/57fbbdb0a2400000?keys=name%2Csex
戻ります:
1
2
3
4{
"name": "tom",
"sex": "male"
}
オブジェクトの変更
オブジェクトの既存のデータを変更するには、オブジェクトの対応する URL に PUT リクエストを送信します。指定しないキーは変更されないため、オブジェクトのデータのサブセットのみを更新できます。たとえば、オブジェクトの age フィールドを変更してみましょう。
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"
}
オブジェクトの削除
オブジェクトを削除するには、指定したオブジェクトの URL に DELETE リクエストを送信します。次に例を示します。
1curl -X DELETE http://localhost/1.0/person/57fbbdb0a2400000
クエリオブジェクトリスト
URL パラメーターを指定せずに、クラスの URL に GET リクエストを送信することで、複数のオブジェクトを一度に取得できます。すべてのユーザーを簡単に取得する方法は次のとおりです。
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
方法は、適切なキーと値を含めることです。たとえば、tom という名前のユーザーを検索したい場合は、次のようなクエリを作成します。
1curl -X GET http://localhost/1.0/person?where=%7B%22name%22%3A%22tom%22%7D
where
値は URL エンコードされた JSON 文字列で、内容は次のとおりです。{"name":"tom"}
指定された値を正確に一致させるだけでなく、where
包含などの比較方法もサポートされています。where
パラメータは次のオプションをサポートしています。
鍵 | 手術 | サンプル |
---|---|---|
等価 | 等しい | {"名前":{"eq":"トム"}} または {"名前":"トム"} |
ね | 等しくない | {"名前":{"ネ":"トム"}} |
GT | 以上 | {"年齢":{"GT":"24"}} |
ジーテ | 以上 | {"年齢":{"GTE":"24"}} |
それ | 未満 | {"年齢":{"lt":"24"}} |
LTE | 以下 | {"年齢":{"LTE":"24"}} |
のように | ファジークエリ | {"名前":{"好き":"%m"}} |
みたいではなく | ファジークエリ | {"名前":{"似ていない":"%m"}} |
間 | 間隔の比較 | {"年齢":{"間":[22,25]}} |
中間ではない | 間隔の比較 | {"年齢":{"22,25 歳未満":[22,25]}} |
で | 列挙する | {"名前":{"で":["トム"、"リリー"]}} |
ありませんで | 列挙する | {"名前":{"not_in":["トム","リリー"]}} |
または | OR演算 | {"または":[{"名前":"トム"},{"年齢":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
この時点で、返される結果には と の 2 つのフィールドが含まれ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"
}
]
}
拡張オブジェクトの作成
ORM を介して hasOne と hasMany を定義すると、オブジェクト間の関連付けを定義し、それを 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/:拡張名 | 置く | 拡張オブジェクトを設定する |
/1.0/:クラス名/:id/:拡張名 | 役職 | 拡張オブジェクトの作成 |
/1.0/:クラス名/:id/:extendName/:rid | 得る | 拡張オブジェクトの読み取り |
/1.0/:クラス名/:id/:extendName/:rid | 置く | 拡張オブジェクトを変更する |
/1.0/:クラス名/:id/:extendName/:rid | 消去 | 拡張オブジェクトの削除 |
/1.0/:クラス名/:id/:拡張名 | 得る | 拡張オブジェクトリストのクエリ |
拡張オブジェクトを設定する
拡張オブジェクトを設定すると、2 つの独立したオブジェクト間の関係が確立されます。たとえば、トムが猫という名前のペットを引き取った場合、次の操作を使用してこれを実現できます。
1
2
3
4curl -X PUT \
-H "Content-Type: application/json" \
-d '{"id": "57fbbdb0a2400007"}' \
http://localhost/1.0/person/57fbbdb0a2400000/pets
呼び出しでは、本文で猫の ID を指定する必要があります。
拡張オブジェクトの作成
拡張オブジェクトを直接作成すると、オブジェクトの作成中にオブジェクト間の接続を確立できます。例えば:
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
データのアクセス許可は、モデルの 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 サブジェクトの説明には 3 つのタイプがあります。 user id
、 userrole
およびは*
、id
特定のユーザーを表し、role
特定のロールを持つユーザーを表し、*
すべてのユーザーを表します。
本体 | 説明する | 優先度 |
---|---|---|
ID | 特定のユーザーID | 1 |
役割 | ユーザーグループ名 | 2 |
* | 全て | 3 |
id
権限をチェックする場合、最初に対応する権限と一致します。指定されていない場合は、ユーザーの対応する権限と一致します。まだ指定されている場合は、の権限が指定されているrole
かどうかを確認します。指定されていない場合は、権限がありません。*
*
たとえば、上記の権限設定では、user
ユーザー グループが読み取り可能に指定されており、そのユーザーには57fbbdb0a2400000
すべての権限が与えられていますが、他のユーザーには権限がありません。
権限
ACL は、API の動作に基づいて権限を 5 つのカテゴリに分類します。
権限 | 説明する | 許可されるタイプ |
---|---|---|
作成する | オブジェクトの作成 | 真/偽/配列 |
読む | オブジェクトの読み取り | 真/偽/配列 |
書く | オブジェクトの変更 | 真/偽/配列 |
消去 | オブジェクトの削除 | 真/偽 |
探す | クエリオブジェクトリスト | 真/偽 |
* | すべての権限を一致させる | 真/偽/配列 |
アクセス許可はtrue
、アクセスを許可するか、false
アクセスを拒否するか、array
指定されたフィールドへのアクセスのみを許可するように設定されます。delete
および はfind
受け入れられず、array
設定されている場合はarray
同じように扱われますtrue
。指定された権限が存在しない場合は、*
同じ件名の権限が照合されます。どちらも存在しない場合は、次の優先レベルのサブジェクトを再度クエリします。
たとえば、上記の例で、user
read のみを設定しtitle
、detail
他のユーザーの read を許可する 必要がある場合は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
。ファイルに保存すると、次のようなイメージが得られます。