LoginSignup
10
6

More than 5 years have passed since last update.

HanamiでGraphQL APIを実装してみよう

Last updated at Posted at 2017-06-27

HanamiGraphQL APIを実装してみるよ。

プロジェクトの作成

mkdir hanami-blog
cd hanami-blog
Gemfile
# frozen_string_literal: true
source "https://rubygems.org"

gem "hanami", '1.0.0'
bundle install
bundle exec hanami new . --application-name=api 
bundle install

モデルの作成

bundle exec hanami generate model user
bundle exec hanami generate model post
20170621155700_create_users.rb
Hanami::Model.migration do
  change do
    create_table :users do
      primary_key :id

      column :name , String, null: false
      column :email, String, null: false

      column :created_at, DateTime, null: false
      column :updated_at, DateTime, null: false
    end
  end
end
20170621155712_create_posts.rb
Hanami::Model.migration do
  change do
    create_table :posts do
      primary_key :id
      foreign_key :user_id, :users, on_delete: :cascade, null: false

      column :title  , String, null: false
      column :content, String, null: true

      column :created_at, DateTime, null: false
      column :updated_at, DateTime, null: false
    end
  end
end
bundle exec hanami db prepare 

Typeの作成

Gemfile
+ gem 'graphql', '1.6.4'
bundle install
mkdir -p apps/api/types
apps/api/application.rb
      load_paths << [
        'controllers',
        'views',
+       'types'
      ]
apps/api/types/user_type.rb
UserType = GraphQL::ObjectType.define do
  name 'User'
  description 'User'
  field :id, types.ID
  field :name, types.String
  field :postss, types[!PostType]
end
apps/api/types/post_type.rb
PostType = GraphQL::ObjectType.define do
  name 'Post'
  description 'Post'
  field :id     , types.ID
  field :title  , types.String
  field :content, types.String
  field :user   , UserType do
    resolve ->(obj, _, _) { UserRepository.new.find(obj.user_id) }
  end
end
apps/api/types/query_type.rb
require_relative 'user_type'
require_relative 'post_type'

QueryType = GraphQL::ObjectType.define do
  name 'Query'
  description 'The query root for this schema'

  field :user do
    type UserType
    argument :id, !types.ID
    resolve ->(_, args, _) { UserRepository.new.find(args[:id]) }
  end

  field :post do
    type PostType
    argument :id, !types.ID
    resolve ->(_, args, _) { PostRepository.new.find(args[:id]) }
  end
end
apps/api/types/hanami_blog_schema.rb
require_relative 'query_type'

HanamiBlogSchema = GraphQL::Schema.define(query: QueryType)
lib/hanami_blog/repositories/post_repository.rb
class PostRepository < Hanami::Repository
  def posts_by_user(user)
    posts.where(user_id: user.id)
  end
end

Controllerの作成

apps/api/config/routes.rb
root to: "graphql#show"
apps/api/controllers/graphql/show.rb
module Api::Controllers::Graphql
  class Show
    include Api::Action

    def call(params)
      query_variables = params[:vairables] || {}
      self.body = JSON.generate(HanamiBlogSchema.execute(params[:query], variables: query_variables))
    end
  end
end

テスト用データ作成

bundle exec hanami c
irb(main):002:0> user = UserRepository.new.create name: "foo", email: "foo@exsample.com"
irb(main):005:0> PostRepository.new.create user_id: user.id, title: "aaa", contest: "AAA"
irb(main):006:0> PostRepository.new.create user_id: user.id, title: "bbb", contest: "BBB"

試してみる

bundle exec hanami s
curl -XGET -d 'query={ user(id: 1) { name email posts {id title} } }' http://localhost:2300/ | jq .
{
  "data": {
    "user": {
      "name": "foo",
      "email": "foo@exsample.com",
      "posts": [
        {
          "id": "1",
          "title": "aaa"
        },
        {
          "id": "2",
          "title": "bbb"
        }
      ]
    }
  }
}
curl -XGET -d 'query={ post(id: 1) { title user { name } } }' http://localhost:2300/ | jq . 
{
  "data": {
    "post": {
      "title": "aaa",
      "user": {
        "name": "foo"
      }
    }
  }
}

以上。
Hanami x GraphQLのニッチ x ニッチでどこに需要があるのかって感じですが、なにかのご参考になれば。

参考

10
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
6