aglioとdrakovでAPI仕様書管理ことはじめ
1. はじめに
最近では Swagger
のほうが主流なのかなと思いつつも
aglio
や drakov
とは何かや、Blueprint
によるAPI仕様の書き方については言及しない。
導入手順のみまとめる。
2. プロジェクト準備
$ mkdir aglio-sample
$ cd aglio-sample/
2.1. nodeバージョン
最新の node
のバージョンでは aglio
のインストールでエラーが出るので古いバージョン(8系)を使用する。
Macの場合
$ nodenv local 8.17.0
$ node -v
v8.17.0
$ nodenv version
8.17.0 (set by /Users/siwa32/projects/samples/aglio-sample/.node-version)
Windowsの場合
$ nodist local 8.17.0
$ node -v
v8.17.0
$ nodist
(x64)
> 8.17.0 (C:\projects\samples\aglio-demo\.node-version: 8.17.0)
10.20.1
14.3.0 (global: 14.3.0)
|
nodeの最新バージョンによるエラーの例については下記おまけ参照 |
2.2. 初期化
$ npm init
3. aglio インストール
$ npm install aglio
$ npx aglio
Usage: node_modules/.bin/aglio [options] -i infile [-o outfile -s]
オプション:
-i, --input Input file
-o, --output Output file
-t, --theme Theme name or layout file [デフォルト: "default"]
-f, --filter Sanitize input from Windows [真偽] [デフォルト: true]
-s, --server Start a local live preview server
-h, --host Address to bind local preview server to
[デフォルト: "127.0.0.1"]
-p, --port Port for local preview server [デフォルト: 3000]
-v, --version Display version number [デフォルト: false]
-c, --compile Compile the blueprint file [デフォルト: false]
-n, --include-path Base directory for relative includes
--verbose Show verbose information and stack traces
[デフォルト: false]
--theme-variables Color scheme name or path to custom variables
[デフォルト: "default"]
--theme-condense-nav Condense navigation links [真偽] [デフォルト: true]
--theme-full-width Use full window width [真偽] [デフォルト: false]
--theme-template Template name or path to custom template
[デフォルト: "default"]
--theme-style Layout style name or path to custom stylesheet
--theme-emoji Enable support for emoticons [真偽] [デフォルト: true]
例:
node_modules/.bin/aglio -i example.apib Render to HTML
-o output.html
node_modules/.bin/aglio -i example.apib Start preview server
-s
node_modules/.bin/aglio Theme colors
--theme-variables flatly -i example.apib
-s
node_modules/.bin/aglio Disable options
--no-theme-condense-nav -i example.apib
-s
See https://github.com/danielgtaylor/aglio#readme for more information
4. サンプル用意
サンプル用のAPI仕様書を用意する。
今回は API Blueprint の公式サイトからサンプル(02. Resource and Actions \| API Blueprint)をそのまま拝借した。
|
1FORMAT: 1A
2
3# Resource and Actions API
4This API example demonstrates how to define a resource with multiple actions.
5
6
7# /message
8This is our [resource](http://www.w3.org/TR/di-gloss/#def-resource). It is
9defined by its
10[URI](http://www.w3.org/TR/di-gloss/#def-uniform-resource-identifier) or, more
11precisely, by its [URI Template](http://tools.ietf.org/html/rfc6570).
12
13This resource has no actions specified but we will fix that soon.
14
15## GET
16Here we define an action using the `GET` [HTTP request method](http://www.w3schools.com/tags/ref_httpmethods.asp) for our resource `/message`.
17
18As with every good action it should return a
19[response](http://www.w3.org/TR/di-gloss/#def-http-response). A response always
20bears a status code. Code 200 is great as it means all is green. Responding
21with some data can be a great idea as well so let's add a plain text message to
22our response.
23
24+ Response 200 (text/plain)
25
26 Hello World!
27
28## PUT
29OK, let's add another action. This time to put new data to our resource
30(essentially an update action). We will need to send something in a
31[request](http://www.w3.org/TR/di-gloss/#def-http-request) and then send a
32response back confirming the posting was a success (_HTTP Status Code 204 ~
33Resource updated successfully, no content is returned_).
34
35+ Request (text/plain)
36
37 All your base are belong to us.
38
39+ Response 204
5. 表示用プレビューサーバ起動
$ npx aglio -i example.apib -s
Server started on http://127.0.0.1:3000/
Rendering example.apib
-
i
オプション : API仕様ファイル -
s
オプション : プレビューサーバー起動
サーバーが起動するので http://127.0.0.1:3000/
にアクセする。
仕様書ファイルを更新すると自動的に検知して反映してくれる。
$ npx aglio -i example.apib -s
Server started on http://127.0.0.1:3000/
Rendering example.apib
Socket connected
Refresh web page in browser
Updated example.apib
Rendering example.apib
Refresh web page in browser
サーバを終了するには Ctrl + c
6. htmlに変換
API仕様書からHTMLに変換する。
$ npx aglio -i example.apib -o example.html
-
i
オプション : API仕様ファイル -
o
オプション : 出力するhtmlファイル
$ ll example*
-rw-r--r-- 1 siwa32 staff 1.3K 5 31 02:20 example.apib
-rw-r--r-- 1 siwa32 staff 24K 5 31 02:33 example.html
7. モックサーバ
drakov
でモックサーバを立ち上げる。
drakov
をインストールする。
$ npm install drakov
$ npx drakov
[INFO] No configuration files found
[INFO] Loading configuration from CLI
Usage:
./drakov -f <path to blueprint> [-p <server port|3000>]
Example:
./drakov -f ./*.md -p 3000
オプション:
--sourceFiles, -f Glob expression to select spec files. [必須]
--serverPort, -p Specifies the port to be listened by Drakov server
[デフォルト: 3000]
--staticPaths, -s A list of comma delimited paths to use for static file
proxying
--pathDelimiter, -d Delimiter for mount point in static path (defaults is
"=")
--stealthmode Run silent (no console output)
--disableCORS Disable CORS header
--sslKeyFile Key File for SSL connections
--sslCrtFile Certificate File for SSL connections
--delay Add a delay to the response (in milliseconds)
--method Add method to Access-Control-Allow-Methods response
header
--header Add header to Access-Control-Allow-Headers response
header
--public Allow external requests [デフォルト: false]
--autoOptions Automatically respond to OPTIONS requests for routes in
spec files
--config Load configuration from a Javascript file, must export an
object
--discover, -D List all available endpoints under `/drakov`. If value of
argument is a module name, it will be required and called
to create a middleware function [デフォルト: false]
--watch Reload Drakov when change detected in list of source
files
--debugMode Enables DEBUG mode. Mismatch requests will be dumped
--ignoreHeader Ignore the HTTP header in API blueprints
必須の引数が見つかりません: f
モックサーバ起動
$ npx drakov -f "example.apib"
[INFO] No configuration files found
[INFO] Loading configuration from CLI
DRAKOV STARTED
[LOG] Setup Route: GET /message
[LOG] Setup Route: PUT /message
Drakov 1.0.4 Listening on port 3000
ブラウザで http://127.0.0.1:3000/message
にアクセスしてみる。
API仕様に定義したレスポンスが返る。
ワイルドカードを使用して複数ファイルを指定する事も可能
$ l *.apib
example.apib example2.apib
$ npx drakov -f "*.apib"
[INFO] No configuration files found
[INFO] Loading configuration from CLI
DRAKOV STARTED
[LOG] Setup Route: GET /message
[LOG] Setup Route: PUT /message
[LOG] Setup Route: GET /coupons/:id Retrieve a Coupon
Drakov 1.0.4 Listening on port 3000
""
で囲ってあげないと最初に見つけたファイルしか認識してくれないようです。
$ npx drakov -f *.apib
[INFO] No configuration files found
[INFO] Loading configuration from CLI
DRAKOV STARTED
[LOG] Setup Route: GET /message
[LOG] Setup Route: PUT /message
Drakov 1.0.4 Listening on port 3000
aglio
もポートが3000なので、ポートを変えたい場合は -p
オプションを使用してポートを指定することができる。
$ npx drakov -f "*.apib" -p 3333
localhost以外からアクセスを可能にする場合は --public
オプションを使用する。
$ npx drakov -f "*.apib" --public
--watch
オプションをつけると仕様書ファイルの変更にリアルタイムに追随してくれる。
$ npx drakov -f "*.apib" --watch
8. 【おまけ】nodeのバージョンが新しい場合
node14.3.0 で aglio をインストールしようとしたときのエラー
$ node -v
v14.3.0
$ npm init
$ npm install aglio
...(snip)...
In file included from ../src/annotation.cc:1:
../src/protagonist.h:22:43: error: no member named 'Handle' in namespace 'v8'
OptionsResult* ParseOptionsObject(v8::Handle<v8::Object>, bool);
~~~~^
../src/protagonist.h:22:60: error: expected '(' for function-style cast or type construction
OptionsResult* ParseOptionsObject(v8::Handle<v8::Object>, bool);
~~~~~~~~~~^
../src/protagonist.h:22:61: error: expected expression
OptionsResult* ParseOptionsObject(v8::Handle<v8::Object>, bool);
^
../src/protagonist.h:22:67: error: expected '(' for function-style cast or type construction
OptionsResult* ParseOptionsObject(v8::Handle<v8::Object>, bool);
~~~~^
../src/protagonist.h:29:30: error: no template named 'Handle' in namespace 'v8'
static void Init(v8::Handle<v8::Object> target);
~~~~^
../src/protagonist.h:47:30: error: no template named 'Handle' in namespace 'v8'
static void Init(v8::Handle<v8::Object> target);
~~~~^
../src/protagonist.h:68:30: error: no template named 'Handle' in namespace 'v8'
static void Init(v8::Handle<v8::Object> target);
~~~~^
../src/annotation.cc:18:29: error: no template named 'Handle'
void SourceAnnotation::Init(Handle<Object> exports)
^
../src/annotation.cc:26:38: error: too few arguments to function call, single argument 'context' was not specified
constructor.Reset(t->GetFunction());
~~~~~~~~~~~~~~ ^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8.h:6404:3: note: 'GetFunction' declared here
V8_WARN_UNUSED_RESULT MaybeLocal<Function> GetFunction(
^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8config.h:422:31: note: expanded from macro 'V8_WARN_UNUSED_RESULT'
#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
^
../src/annotation.cc:27:88: error: too few arguments to function call, single argument 'context' was not specified
exports->Set(Nan::New<String>("SourceAnnotation").ToLocalChecked(), t->GetFunction());
~~~~~~~~~~~~~~ ^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8.h:6404:3: note: 'GetFunction' declared here
V8_WARN_UNUSED_RESULT MaybeLocal<Function> GetFunction(
^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8config.h:422:31: note: expanded from macro 'V8_WARN_UNUSED_RESULT'
#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
^
../src/annotation.cc:44:48: error: too few arguments to function call, single argument 'context' was not specified
return v8_wrap(annotationObject)->ToObject();
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8.h:2819:3: note: 'ToObject' declared here
V8_WARN_UNUSED_RESULT MaybeLocal<Object> ToObject(
^
/Users/siwa32/Library/Caches/node-gyp/14.3.0/include/node/v8config.h:422:31: note: expanded from macro 'V8_WARN_UNUSED_RESULT'
#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
^
4 warnings and 11 errors generated.
make: *** [Release/obj.target/protagonist/src/annotation.o] Error 1
gyp ERR! build error
gyp ERR! stack Error: `make` failed with exit code: 2
gyp ERR! stack at ChildProcess.onExit (/usr/local/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:194:23)
gyp ERR! stack at ChildProcess.emit (events.js:315:20)
gyp ERR! stack at Process.ChildProcess._handle.onexit (internal/child_process.js:276:12)
gyp ERR! System Darwin 19.4.0
gyp ERR! command "/usr/local/Cellar/node/14.3.0/bin/node" "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild"
gyp ERR! cwd /Users/siwa32/projects/samples/aglio-error/node_modules/protagonist
gyp ERR! node -v v14.3.0
gyp ERR! node-gyp -v v5.1.0
gyp ERR! not ok
> aglio-theme-olio@1.6.3 postinstall /Users/siwa32/projects/samples/aglio-error/node_modules/aglio-theme-olio
> node scripts/setup-cache.js
...(snip)...