素晴らしいコミュニティモジュール

フィブアプリ

fibjs アプリケーションの基本的な API フレームワーク

インストール

1
npm install fib-app [--save]

テスト

1
npm test

基本的なスクリプトを作成する

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
const 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 7
module.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 4
curl -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 つのフィールドがあります。それぞれidupdatedAtcreatedAt、ですcreatedBy

その中でidupdatedAt、 、createdAt単一フィールドは自動的に作成および変更されます。createdByタイプを自分で指定する必要があります。

基本的なオブジェクトアクセスAPI

このようなデータ定義を完了すると、REST API 仕様に準拠した一連のインターフェイス呼び出しが直接作成されます。

URL 方法 アクション
/1.0/:クラス名 役職 新しいオブジェクトを作成する
/1.0/:クラス名/:id 得る オブジェクトの読み取り
/1.0/:クラス名/:id 置く オブジェクトの変更
/1.0/:クラス名/:id 消去 オブジェクトの削除
/1.0/:クラス名 得る クエリオブジェクトリスト

新しいオブジェクトを作成する

新しいオブジェクトを作成するには、オブジェクト自体を含む POST リクエストをクラスの URL に送信する必要があります。たとえば、上に示したオブジェクトを作成するには、次のようにします。

1 2 3 4
curl -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 リクエストを送信することで、そのコンテンツを取得できます。たとえば、上で作成したオブジェクトを取得するには:

1
curl -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(以下,で区切られたフィールド名の文字列) をカスタマイズできます。

1
curl -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 4
curl -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 リクエストを送信します。次に例を示します。

1
curl -X DELETE http://localhost/1.0/person/57fbbdb0a2400000

クエリオブジェクトリスト

URL パラメーターを指定せずに、クラスの URL に GET リクエストを送信することで、複数のオブジェクトを一度に取得できます。すべてのユーザーを簡単に取得する方法は次のとおりです。

1
curl -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内容は、,で区切られたフィールド名の文字列です。次に例を示します。

1
curl -X GET http://localhost/1.0/person?keys=name%2Cage

nameおよびageフィールドのみが返されることを指定します。

ここでフィルタ条件

whereクエリ オブジェクトはパラメータの形式で制約できます。

whereパラメータ値は JSON でエンコードされている必要があります。つまり、実行されている実際の URL リクエストを見ると、最初に JSON エンコードされ、次に URL エンコードされている必要があります。パラメーターを使用する最も簡単なwhere方法は、適切なキーと値を含めることです。たとえば、tom という名前のユーザーを検索したい場合は、次のようなクエリを作成します。

1
curl -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、指定した数のレコードをスキップして、ページめくりの効果を得ることができます。

1
curl -X GET http://localhost/1.0/person?skip=100

制限はレコード制限を返します

このオプションを使用するとlimit、返されるレコードの数を制限できます。limit有効な数値は 1 ~ 1000 で、デフォルトは 100 です。

1
curl -X GET http://localhost/1.0/person?limit=100

order は並べ替え方法を指定します

このオプションを使用してorder、返される結果セットの並べ替え方法を設定します。フィールド名の前に が含まれている場合は、-逆順になります。

1
curl -X GET http://localhost/1.0/person?order=-id

count は結果の合計数を返します

リクエストに応じて増分されますcount。指定されたコンテンツを返すときに返される結果セットの総数。

1
curl -X GET http://localhost/1.0/person?count=1&limit=1

この時点で、返される結果には と の 2 つのフィールドが含まれcountresultsそれぞれ合計数と結果が含まれます。

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 9
module.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 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"id": "57fbbdb0a2400007"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets

呼び出しでは、本文で猫の ID を指定する必要があります。

拡張オブジェクトの作成

拡張オブジェクトを直接作成すると、オブジェクトの作成中にオブジェクト間の接続を確立できます。例えば:

1 2 3 4
curl -X POST \ -H "Content-Type: application/json" \ -d '{"name": "cat"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets

猫という名前のペットが作成され、トムに関連付けられます。

拡張オブジェクトの読み取り

拡張オブジェクトの読み取りは、基本オブジェクトの読み取りと非常に似ており、キー オプションもサポートしています。

1
curl -X GET http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

拡張オブジェクトを変更する

拡張オブジェクトの読み取りは、基本オブジェクトの読み取りと非常に似ています。

1 2 3 4
curl -X PUT \ -H "Content-Type: application/json" \ -d '{"name": "cat 1"}' \ http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

拡張オブジェクトの削除

拡張オブジェクトを削除してもオブジェクト自体は削除されず、オブジェクト間の関係が解消されるだけです。

1
curl -X DETELE http://localhost/1.0/person/57fbbdb0a2400000/pets/57fbbdb0a2400007

拡張オブジェクトリストのクエリ

拡張オブジェクト リストのクエリは、基本オブジェクト リストのクエリと非常に似ており、キーや条件付きフィルタリングなどのオプションもサポートしています。

1
curl -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 25
const orm = require('fib-orm'); module.exports = db => { db.define('blog', { title: String, detail: Stringnote: 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指定された権限が存在しない場合は、*同じ件名の権限が照合されます。どちらも存在しない場合は、次の優先レベルのサブジェクトを再度クエリします。

たとえば、上記の例で、userread のみを設定しtitledetail他のユーザーの 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 24
module.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 41
module.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でき、ユーザー自身が自分のデータをすべて操作でき、自分のペット情報に対して完全な権限を持つことができます。

拡張オブジェクトのアクセス権限をチェックする場合、オブジェクトの権限と拡張オブジェクトの権限は別々にチェックされます。たとえば、次のようなリクエストです。

1
curl -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。ファイルに保存すると、次のようなイメージが得られます。 図