LoginSignup
7
6

More than 5 years have passed since last update.

graphql-rest-proxy で REST な API を GraphQL に変換する

Last updated at Posted at 2019-03-26

image.png

graphql-rest-proxy という、 REST な API を GraphQL サーバーに変換するツールを作りました。

動機

GraphQL は素晴らしいので、 REST API から GraphQL に移行したいと思ったとします。
ただ、既存の REST API を GraphQL に置き換えるのは大変でしょう。

graphql-rest-proxy は、既存の REST API に変更を与えることなく、 GraphQL サーバーを稼働させることができます。

インストール

npm -g install graphql-rest-proxy

または Yarn で

yarn global add graphql-rest-proxy

使い方

STEP 1. GraphQL の Schema を定義する

schema.graphql
type User {
  id: Int
  name: String
  isActive: Boolean
}

type Query {
  getUser: User @proxy(get: "https://my-rest-api.com/user")
}

STEP 2. Proxy server を起動する

graphql-rest-proxy schema.graphql

# => graphql-rest-proxy is running on http://localhost:5252

STEP 3. クライアントからGraphQLのリクエストをする

curl -XPOST -H 'Content-Type: application/json' \
    -d '{ "query": "{ getUser { id name isActive } }" }' \
    http://localhost:5252/graphql

このようなレスポンスが帰ってきます。


{
  "data": {
    "getUser": {
      "id": 1,
      "name": "Tom",
      "isActive": false
    }
  }
}

Schema 定義例

基本的なクエリ

type User {
  id: Int
  name: String
}

type Query {
  getUser: User @proxy(get: "https://my-rest-api.com/user")
  getUsers: [User] @proxy(get: "https://my-rest-api.com/users")
}

パラメータ付きのクエリ

id というクエリパラメータは $id という変数名で参照できます。

type User {
  id: Int
  name: String
}

type Query {
  getUserById(id: Int!): User @proxy(get: "https://my-rest-api.com/users/$id")
}

Input Parameters

Mutation は variables を REST API に送信します。

type UserInput {
  name: String!
}

type User {
  id: Int
  name: String
}

type Mutation {
  createUser(user: UserInput!): User @proxy(post: "https://my-rest-api.com/users")
  updateUser(id: Int!, user: UserInput!): User @proxy(patch: "https://my-rest-api.com/users/$id")
}

リクエスト例

fetch('http://localhost:5252/graphql', {
  method: 'patch',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: gql`
      mutation UpdateUser($id: Int!, $user: UserInput!) {
        updateUser(id: $id, user: $user) {
          id
          name
        }
      }
    `,
    variables: {
      id: 1,
      user: {
        name: 'acro5piano',
      },
    },
  }),
})

ネストしたオブジェクト

親の ID は、これまた $id で参照できます。

type Post {
  id: Int
  title: String
}

type User {
  id: Int
  name: String
  posts: [Post] @proxy(get: "https://my-rest-api.com/users/$id/posts")
}

type Query {
  getUser: User @proxy(get: "https://my-rest-api.com/user")
}

base url を設定する

冗長な記述をへらすため、 baseUrl という CLI オプションを設定できます。

graphql-rest-proxy --baseUrl https://my-rest-api.com schema.graphql
type Query {
  getUser: User @proxy(get: "/user")
}

工夫点

最小のリクエストで済むように、子オブジェクトがレスポンスに含まれていた場合、それを返します。

例えば Schema が下記のようだったとして

type Post {
  id: Int
  title: String
}

type User {
  id: Int
  name: String
  posts: [Post] @proxy(get: "https://my-rest-api.com/users/$id/posts")
}

type Query {
  getUser: User @proxy(get: "https://my-rest-api.com/user")
}

REST API が下記のようなレスポンスを返した時、

curl https://my-rest-api.com/user
{
  "id": 1,
  "name": "acro5piano",
  "posts": {
    "id": 1,
    "title": "graphql-rest-proxy"
  }
}

posts/user に含まれているので、 graphql-rest-proxyhttps://my-rest-api.com/users/1/posts にリクエストしません。

詳しい情報は、 https://github.com/acro5piano/graphql-rest-proxy を参照してくださいm(_ _)m

おまけ

パッケージは今まで Rollup.js を使っていましたが、今回を機に @pika/pack を使ってみました。

Rollup では面倒だった、実行可能コマンドの指定やWebpack的なコード埋め込みが、ほぼ自動で設定できるようになり、非常に快適でした。 @pika/pack もいつか記事にしたい。

7
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
7
6