@r7kamuraさん作のJsonWorldを利用して生成したJSON Schemaを、
同じく@r7kamuraさん作のJsonismで読み込み、APIを呼び出します
準備
JsonWorld, Jsonismについては@r7kamuraさん本人による下記のエントリをチェック
サンプル
Railsを利用します
仕様
Railsのscaffoldで以下のモデルを作成しました。
attr | type |
---|---|
People#name | String |
People#age | Integer |
Resourceクラス作成
app/api/resources/person.rb
require 'json_world'
module Api
module Resources
class Person
include JsonWorld::DSL
title 'Person'
property(
:id,
description: '人物のid',
example: 1,
type: Integer,
)
property(
:name,
description: '人物の名前',
example: "tanaka",
type: String,
)
property(
:age,
description: '人物の年齢',
example: 34,
type: Integer,
)
link(
:list,
description: "全ての人物の一覧を取得します。",
path: "/api/v1/people",
rel: "instances",
)
link(
:get,
description: "人物を取得します。",
path: "/api/v1/people/:id",
rel: "self",
)
link(
:create,
description: "人物を登録します。",
path: "/api/v1/people/:id",
method: "POST",
rel: "self",
parameters: {
name: {
description: "人物の名前",
example: "tanaka",
type: String,
},
age: {
description: "人物の年齢",
example: 34,
type: Integer,
},
},
)
link(
:update,
description: "人物を更新します。",
path: "/api/v1/people/:id",
method: "PATCH",
rel: "self",
parameters: {
name: {
description: "人物の名前",
example: "tanaka",
type: String,
},
age: {
description: "人物の年齢",
example: 34,
type: Integer,
},
},
)
link(
:delete,
description: "人物を削除します。",
path: "/api/v1/people/:id",
method: "DELETE",
rel: "self",
)
attr_reader :id, :name, :age
# @param [Person] person
def initialize(person, people)
@id = person.id
@name = person.name
@age = person.age
@people = people.age
end
end
end
end
Schemaクラス作成
app/api/schema.rb
require 'json_world'
require "#{Rails.root}/app/api/resources/person.rb"
module Api
class Schema
include JsonWorld::DSL
title 'Sample API v1 JSON Schema'
description 'このスキーマ定義では、Sample API v1 のインターフェースをJSON Hyper Schema draft v4形式で表現しています。'
property :people, links: true, type: Api::Resources::Person
link href: "http://localhost:3000", rel: "self"
end
end
Controller
app/controllers/api/v1/people_controller.rb
require "#{Rails.root}/app/controllers/application_controller.rb"
require "#{Rails.root}/app/api/resources/person.rb"
module Api
module V1
class PeopleController < ApplicationController
before_action :set_person, only: [:show, :edit, :update, :destroy]
# 動作確認用にCSRFを無効化しています
skip_before_action :verify_authenticity_token
# GET /api/v1/people
def index
render json: Person.all
end
# GET /api/v1/people/1
def show
render json: PersonResource.new(Person.find(params[:id]))
end
# POST /api/v1/people
def create
@person = Person.new(person_params)
if @person.save
render json: @person
else
render json: @person.errors, status: :unprocessable_entity
end
end
# PATCH/PUT /api/v1/people/1
def update
if @person.update(person_params)
render json: @person
else
render json: @person.errors, status: :unprocessable_entity
end
end
# DELETE /api/v1/people/1
def destroy
@person.destroy
head :no_content
end
private
# Use callbacks to share common setup or constraints between actions.
def set_person
@person = Person.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def person_params
params.require(:person).permit(:name, :age)
end
end
end
end
routes.rb
Rails.application.routes.draw do
namespace :api, format: 'json' do
namespace :v1 do
resources :people
end
end
resources :people
root to: 'people#index'
end
JSON Schemaを生成
Rails コンソールを利用してJSON Schemaを生成します。
出力した内容を sample_api_v1.json
として保存します。
$ rails console
irb(main):002:0> puts Api::Schema.to_json_schema
{
"description": "このスキーマ定義では、Sample API v1 のインターフェースをJSON Hyper Schema draft v4形式で表現しています。",
"links": [
{
"method": "GET",
"title": "{:href=>\"http://localhost:3000\", :rel=>\"self\"}"
}
],
"properties": {
"people": {
"links": [
{
"description": "全ての人物の一覧を取得します。",
"href": "/api/v1/people",
"method": "GET",
"rel": "instances",
"title": "list"
},
{
"description": "人物を取得します。",
"href": "/api/v1/people/:id",
"method": "GET",
"rel": "self",
"title": "get"
},
{
"description": "人物を登録します。",
"href": "/api/v1/people/:id",
"method": "POST",
"rel": "self",
"schema": {
"properties": {
"name": {
"description": "人物の名前",
"example": "tanaka",
"type": "string"
},
"age": {
"description": "人物の年齢",
"example": 34,
"type": "integer"
}
},
"required": [
"name",
"age"
]
},
"title": "create"
},
{
"description": "人物を更新します。",
"href": "/api/v1/people/:id",
"method": "PATCH",
"rel": "self",
"schema": {
"properties": {
"name": {
"description": "人物の名前",
"example": "tanaka",
"type": "string"
},
"age": {
"description": "人物の年齢",
"example": 34,
"type": "integer"
}
},
"required": [
"name",
"age"
]
},
"title": "update"
},
{
"description": "人物を削除します。",
"href": "/api/v1/people/:id",
"method": "DELETE",
"rel": "self",
"title": "delete"
}
],
"properties": {
"id": {
"description": "人物のid",
"example": 1,
"type": "integer"
},
"name": {
"description": "人物の名前",
"example": "tanaka",
"type": "string"
},
"age": {
"description": "人物の年齢",
"example": 34,
"type": "integer"
}
},
"required": [
"id",
"name",
"age"
],
"title": "Person"
}
},
"required": [
"people"
],
"title": "Sample API v1 JSON Schema"
}
動作確認
APIサーバー起動
$ rails s -b 0.0.0.0
Curlで疎通確認
$ curl http://localhost:3000/people/1.json
{"id":1,"name":"tanaka","age":23,"created_at":"2015-07-15T07:29:24.210Z","updated_at":"2015-07-15T07:29:24.210Z"}
Jsonismを使った、API呼び出しプログラムを作成
jsonism_sample.rb
require 'json'
require 'jsonism'
require 'pp'
schema_body = File.read("sample_api_v1.json")
schema = JSON.parse(schema_body)
client = Jsonism::Client.new(schema: schema)
puts client.methods(false)
pp client.list_person.body.map(&:to_hash)
Jsonismの動作確認
$ ruby jsonism_sample.rb
list_person
get_person
create_person
update_person
delete_person
[{"id"=>1,
"name"=>"tanaka",
"age"=>23,
"created_at"=>"2015-07-15T07:29:24.210Z",
"updated_at"=>"2015-07-15T07:29:24.210Z"},
{"id"=>2,
"name"=>"suzuki",
"age"=>42,
"created_at"=>"2015-07-15T07:29:34.840Z",
"updated_at"=>"2015-07-15T07:29:34.840Z"},
{"id"=>3,
"name"=>"honda",
"age"=>99,
"created_at"=>"2015-07-21T06:27:41.264Z",
"updated_at"=>"2015-07-21T06:27:41.264Z"},
{"id"=>4,
"name"=>"seki",
"age"=>123,
"created_at"=>"2015-07-28T07:46:24.991Z",
"updated_at"=>"2015-07-28T07:46:24.991Z"},
{"id"=>6,
"name"=>"hoge",
"age"=>123,
"created_at"=>"2015-07-29T08:13:34.077Z",
"updated_at"=>"2015-07-29T08:13:34.077Z"},
{"id"=>8,
"name"=>"hoge",
"age"=>123,
"created_at"=>"2015-07-29T08:34:03.411Z",
"updated_at"=>"2015-07-29T08:34:03.411Z"}]