RAML是Restful API Modeling Language的縮寫,是用來描述API信息的文檔。 創建一個.raml尾碼的文件,用Atom打開。 基本用法 #%RAML 0.8 title: Book API baseUri: http://api.book.com/{version} ve
RAML是Restful API Modeling Language的縮寫,是用來描述API信息的文檔。
創建一個.raml尾碼的文件,用Atom打開。
基本用法
#%RAML 0.8 title: Book API baseUri: http://api.book.com/{version} version: v1 /users: /authors: /{authorname}: /books: get: queryParameters: author: displayName: Author type: string description: An author's full name example: Mary required: false publicationYear: displayName: Pub Year type: number description: The year released for the first time example: 1984 required: false rating: displayName: Rating type: number description: Average rating required: false isBn: displayName: ISBN type: string minLength: 10 example: 0321736079 put: queryParameters: access_token: displayName: Access Token type: string description: Token giving you permission to make call required: true post: /{bookTitle}: get: description: Retrieve a specific book title responses: 200: body: application/json: example: | { "data":{ "id": "SbBGk", "title": "its the title", "descritpion": null }, "success": true, "status": 200 } put: delete: /author: get: /publiser: get:
以上,
● 類型/users:看作是resource,也就是以/開始,:結尾,而且resource是嵌套存在的
● queryParameters描述查詢字元串
接下來把.raml轉換成html格式,有一個開源的項目。
→ 參考:https://github.com/raml2html/raml2html
→ 全局安裝:npm i -g raml2html
→ .raml文件所在文件夾內打開命令視窗,輸入:raml2html example.raml > example.html
就是這麼個效果:
Body Parameters
POST請求,通常把參數放到body中傳遞,在RAML中如何描述呢?
在Body中的參數傳遞有很多方式,需要在Headers下的Content-Type中設置。Content-Type這個key可能的值包括:multipart/form-data, application/json, application/x-www-form-urlencoded等等。
1、通過multipart/form-data
/file-content: description: The file to be reproduced by the client get: description: Get the file content responses: 200: body: binary/octet-stream: example: !include heybulldog.mp3 post: description: | Enters the file content for an existing song entity. Use the "binary/octet-stream" content type to specify the content from any consumer (excepting web-browsers). Use the "multipart-form/data" content type to upload a file which content will become the file-content body: binary/octet-stream: multipart/form-data: formParameters: file: description: The file to be uploaded required: true type: file
以上,
● Content-Type能接受的類型是binary/octet-stream或multipart/form-data
● 對於multipart/form-data類型,鍵值數據放在了formParameters中
● !include heybulldog.mp3表示把heybulldog.mp3文件引入進來
2、通過JSON Shema
JSON Shema用來描述JSON格式。
為什麼需要JSON Schema呢?
舉個例子:
{ "id":1, "name":"a green door", "price":12.50, "tags":["home", "green"] }
我們可能會問:
● 什麼是id
● name欄位必須嗎
● price的值可以是0嗎
● tags所代表的數組元素是string類型嗎?
JSON Schema就是解決這些問題的。
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object" }
以上,
● $schema表示當前JSON Shema所採用的版本
● type欄位是必須的,是object類型
接著,對id欄位約束。
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" } }, "required": ["id"] }
對name欄位約束。
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" } }, "required": ["id", "name"] }
對price欄位約束。
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true } }, "required": ["id", "name", "price"] }
對tags欄位約束。
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "integer" }, "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "required": ["id", "name", "price"] }
數組如何用JSON Schema描述呢?
[ { "id": 2, "name": "An ice sculpture", "price": 12.50, "tags": ["cold", "ice"], "dimensions": { "length": 7.0, "width": 12.0, "height": 9.5 }, "warehouseLocation": { "latitude": -78.75, "longitude": 20.4 } }, { "id": 3, "name": "A blue mouse", "price": 25.50, "dimensions": { "length": 3.1, "width": 1.0, "height": 1.0 }, "warehouseLocation": { "latitude": 54.4, "longitude": -32.7 } } ]
用JSON Shema描述就是這樣:
{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product set", "type": "array", "items": { "title": "Product", "type": "object", "properties": { "id": { "description": "The unique identifier for a product", "type": "number" }, "name": { "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true }, "dimensions": { "type": "object", "properties": { "length": {"type": "number"}, "width": {"type": "number"}, "height": {"type": "number"} }, "required": ["length", "width", "height"] }, "warehouseLocation": { "description": "Coordinates of the warehouse with the product", "$ref": "http://json-schema.org/geo" } }, "required": ["id", "name", "price"] } }
RAML也用到了JSON Shema,就像這樣:
body: application/json: schema: | { "type": "object", "$schema": "http://json-schema.org/draft-03/schema", "id": "http://jsonschema.net", "required": true, "properties": { "songTitle": { "type": "string", "required": true }, "albumId": { "type": "string", "required": true, "minLength": 36, "maxLength": 36 } } } example: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "albumId": "183100e3-0e2b-4404-a716-66104d440550" }
schemas
每個資源都有自己的schema,是否可以把所有資源的schema合併到同一個地方呢?
RAML提供了schemas欄位。
schemas: - song: | { "type": "object", "$schema": "http://json-schema.org/draft-03/schema", "id": "http://jsonschema.net", "required": true, "properties": { "songTitle": { "type": "string", "required": true }, "albumId": { "type": "string", "required": true, "minLength": 36, "maxLength": 36 } } }
按如下引用:
body: application/json: schema: song example: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "albumId": "183100e3-0e2b-4404-a716-66104d440550" }
Resource Types資源類型
每個資源通有相似的部分,能否把這些相似的部分提取抽象出來呢?
假設有2個資源:/resources和/{resourceId}
#%RAML 0.8 title: /resources: get: post: /{resourceId}: get: put: delete:
以上,resource大致可以分成針對集合和針對個體的,所以,在RAML中通過resourceTypes對資源進行分類,有這樣的表達方式:
resourceTypes: - collection: get: post: - collection-item: get:
於是collection類型可以寫成這樣:
resourceTypes: - collection: description: Collection of available <<resourcePathName>> in Jukebox. get: description: Get a list of <<resourcePathName>>. responses: 200: body: application/json: post: description: | Add a new <<resourcePathName|!singularize>> to Jukebox. queryParameters: access_token: description: "The access token provided by the authentication application" example: AABBCCDD required: true type: string body: application/json: schema: <<resourcePathName|!singularize>> responses: 200: body: application/json: example: | { "message": "The <<resourcePathName|!singularize>> has been properly entered" }
以上,
● <<resourcePathName>>是占位符,類似表示songs
● 另外<<resourcePath>>是占位符,類似表示/songs
● <<resourcePathName|!singularize>>是占位符,類似表示song
● <<resourcePathName|!pluralize>>是占位符,類似表示songs
然後這樣使用:
/songs: type: collection get: queryParameters: songTitle: description: "The title of the song to search (it is case insensitive and doesn't need to match the whole title)" required: true minLength: 3 type: string example: "Get L" responses: 200: body: application/json: example: | "songs": [ { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky" }, { "songId": "550e8400-e29b-41d4-a716-446655440111", "songTitle": "Loose yourself to dance" }, { "songId": "550e8400-e29b-41d4-a716-446655440222", "songTitle": "Gio sorgio by Moroder" } ] post: body: application/json: example: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "albumId": "183100e3-0e2b-4404-a716-66104d440550" }
collection-item類型可以寫成這樣:
resourceTypes: - collection: ... - collection-item: description: Entity representing a <<resourcePathName|!singularize>> get: description: | Get the <<resourcePathName|!singularize>> with <<resourcePathName|!singularize>>Id = {<<resourcePathName|!singularize>>Id} responses: 200: body: application/json: 404: body: application/json: example: | {"message": "<<resourcePathName|!singularize>> not found" }
然後這樣使用:
/songs: ... /{songId}: type: collection-item get: responses: 200: body: application/json: example: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "duration": "6:07", "artist": { "artistId": "110e8300-e32b-41d4-a716-664400445500" "artistName": "Daft Punk", "imageURL": "http://travelhymns.com/wp-content/uploads/2013/06/random-access-memories1.jpg" }, "album": { "albumId": "183100e3-0e2b-4404-a716-66104d440550", "albumName": "Random Access Memories", "imageURL": "http://upload.wikimedia.org/wikipedia/en/a/a7/Random_Access_Memories.jpg" } }
以上,
● 在resourceTypes中的謂詞get,post等,可以在具體的resource中進行重新定義
● 在resrouce級別,通過type: collection-item或type: collection與resourceTypes對應
Parameters
以上,resourceTypes欄位所代表的是一個對集合和個體類型相同操作的一個封裝,在這些操作中,在這些請求響應中,有時需要通過example欄位來舉例,通常這樣寫:
example: | { ... } 或者 example: | [ { }, { } ]
但在RAML中,為我們提供了<<exampleCollection>>和<<exampleItem>>占位符分別表示集合和個體。
resourceTypes: - collection: description: Collection of available <<resourcePathName>> in Jukebox. get: description: Get a list of <<resourcePathName>>. responses: 200: body: application/json: example: | <<exampleCollection>> post: description: | Add a new <<resourcePathName|!singularize>> to Jukebox. queryParameters: access_token: description: "The access token provided by the authentication application" example: AABBCCDD required: true type: string body: application/json: schema: <<resourcePathName|!singularize>> example: | <<exampleItem>> responses: 200: body: application/json: example: | { "message": "The <<resourcePathName|!singularize>> has been properly entered" } - collection-item: description: Entity representing a <<resourcePathName|!singularize>> get: description: | Get the <<resourcePathName|!singularize>> with <<resourcePathName|!singularize>>Id = {<<resourcePathName|!singularize>>Id} responses: 200: body: application/json: example: | <<exampleItem>> 404: body: application/json: example: | {"message": "<<resourcePathName|!singularize>> not found" }
在資源resource部分通常這樣調用:
/songs: type: collection: exampleCollection: | [ ... ] /{songId}: type: collection-item: exampleItem: | { ... }
具體來說,類似這樣:
/songs: type: collection: exampleCollection: | [ { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky" }, { "songId": "550e8400-e29b-41d4-a716-446655440111", "songTitle": "Loose yourself to dance" }, { "songId": "550e8400-e29b-41d4-a716-446655440222", "songTitle": "Gio sorgio by Morodera" } ] exampleItem: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "albumId": "183100e3-0e2b-4404-a716-66104d440550" } get: queryParameters: songTitle: description: "The title of the song to search (it is case insensitive and doesn't need to match the whole title)" required: true minLength: 3 type: string example: "Get L" /{songId}: type: collection-item: exampleItem: | { "songId": "550e8400-e29b-41d4-a716-446655440000", "songTitle": "Get Lucky", "duration": "6:07", "artist": { "artistId": "110e8300-e32b-41d4-a716-664400445500" "artistName": "Daft Punk", "imageURL": "http://travelhymns.com/wp-content/uploads/2013/06/random-access-memories1.jpg" }, "album": { "albumId": "183100e3-0e2b-4404-a716-66104d440550", "albumName": "Random Access Memories", "imageURL": "http://upload.wikimedia.org/wikipedia/en/a/a7/Random_Access_Memories.jpg" } }
Includes
可以把一些example放到單獨的文件,然後通過!include關鍵字來引用這些文件。
/songs: type: collection: exampleCollection: !include jukebox-include-songs.sample exampleItem: !include jukebox-include-song-new.sample /{songId}: type: collection-item: exampleItem: !include jukebox-include-song-retrieve.sample
traits
如何描述查詢、排序、分頁呢?
traits: - searchable: queryParameters: query: description: | JSON array [{"field1","value1","operator1"},{"field2","value2","operator2"},...,{"fieldN","valueN","operatorN"}] <<description>> example: | <<example>>aml - orderable: queryParameters: orderBy: description: | Order by field: <<fieldsList>> type: string required: false order: description: Order enum: [desc, asc] default: desc required: false - pageable: queryParameters: offset: description: Skip over a number of elements by specifying an offset value for the query type: integer required: false example: 20 default: 0 limit: description: Limit the number of elements on the response type: integer required: false example: 80 default: 10
按如下使用這些trait。
/songs: type: collection: exampleCollection: !include jukebox-include-songs.sample exampleItem: !include jukebox-include-song-new.sample get: is: [ searchable: {description: "with valid searchable fields: songTitle", example: "[\"songTitle\", \"Get L\", \"like\"]"}, orderable: {fieldsList: "songTitle"}, pageable ]
另外,schema也可以放到單獨的文件中,然後通過!include引用。
schemas: - song: !include jukebox-include-song.schema - artist: !include jukebox-include-artist.schema - album: !include jukebox-include-album.schema
resourceTypes也可以放到單獨的文件中:
resourceTypes: !include jukebox-includes-resourceTypes.inc