Rails×GraphQL×Dockerの環境構築について

# はじめに
こんにちは、なかじ(@nakayama-bird)と申します。
今年1月からオンラインプログラミングスクールRUNTEQでRuby on Railsを中心としたWebアプリケーションの開発について学習した後、12月からエンジニアとして働き始めました。
職場のバックエンドの開発でGraphQLを使用していることから、学習のためDocker環境でRails×GraphQLの環境構築を行いました。
RUNTEQのアドカレのテーマが『プログラミングでの"ワクワク"』らしく、サクサク環境構築して新しい技術にワクワク触れるをモットーに書いてみました🙆‍♀️

:::note warn
私はプログラミング初学者です。
内容に誤りのある場合がございます。
もし間違いがあればご指摘いただけますと幸いです。
:::

# 目次
[1.この記事のゴール](#1-この記事のゴール)
[2.GraphQLとは何か](#2-graphqlとは何か)
[3.Rails×GraphQL×Dockerの環境構築](#3railsgraphqldockerの環境構築)

# 1. この記事のゴールと技術構成
この記事では、Dockerを使用して開発環境下でRails×GraphQLの操作ができるようになることをゴールとしています。

| カテゴリー | 使用技術・スペック |
|:-----------|:------------|
| フレームワーク |Rails 7.2.2（APIモード）|
| 使用言語 |ruby 3.3.6|
| DB  | Postgresql      |
| 開発環境 | Docker |
| PC        | MacBook Air M2 (メモリ: 16GB, ストレージ: 256GB SSD) |


:::note warn
学習用として開発環境でGraphQLを動かせることを目的としております。
またバックエンド側のみの内容となっております。
:::

# 2. GraphQLとは何か
本題の前にそもそもGraphQLとは何であるかについて概要を説明します。
公式ドキュメントには下記の通り記載があります。
>GraphQL is a query language for your API, and a server-side runtime for executing queries using a type system you define for your data. The GraphQL specification was open-sourced in 2015 and has since been implemented in a variety of programming languages. GraphQL isn’t tied to any specific database or storage engine—it is backed by your existing code and data.
[Introduction to GraphQL | GraphQL](https://graphql.org/learn/)

「GraphQLはAPI用のクエリ言語であり、データ用に定義した型システムを使用してクエリを実行するためのサーバー側ランタイム」だそうです...と言われても私はあまりイメージがわきませんでした。

そこでドキュメント内の[Try it out!](https://graphql.org/learn/#try-it-out)に触れてみました。元々表示されているのはheroのnameを呼び出すためのクエリですが、やっぱりidもあわせて呼び出せるようにしたいなと思うと下記のようになります。

- クエリ
```graphql
{
  hero {
    name
    id
    # add additional fields here!
  }
}
```
- レスポンス
```json
{
  "data": {
    "hero": {
      "name": "R2-D2",
      "id": "2001"
    }
  }
}
```
クエリに項目を追加するだけで対応可能です。

しかしながら、「それの何が良いのか...」と最初に読んだとき私は思いました。
そこで、API設計でよく使われるRESTとの比較から理解するべく下記の記事を読みました。初学者でも理解しやすい記事でしたので、GraphQLの学習する際にはおすすめです。
ざっとした理解ですが、REST APIは「シンプルだけど不要な情報も呼び出してしまう可能性がある」、GraphQLは「データを効率的に取得できるけれど複雑になってしまう」というような感じです。

https://zenn.dev/nameless_sn/articles/the_differences_between_rest_and_gql

しかしながら実際Railsのアプリケーション上で試してみないとイメージが湧かなそうだと考え下記の教材をもとに学習を進めたいと考えました。その際、Dockerを使用して環境構築を行いたいと考えたことがきっかけでこの記事を執筆しました。

https://zenn.dev/igaiga/books/rails-practice-note/viewer/rails_graphql_workshop#%E5%8F%82%E8%80%83%E8%B3%87%E6%96%99

# 3.Rails×GraphQL×Dockerの環境構築
では本題の環境構築に入っていきましょう。
### Dockerファイルの作成からビルド
```
$ mkdir graphql_tutorial
$ cd graphql_tutorial
$ touch Dockerfile.dev
$ touch compose.yml
```
```dockerfile
# Dockerfile.dev
FROM ruby:3.3.6
ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev vim

RUN mkdir /myapp
WORKDIR /myapp

RUN gem install bundler
COPY . /myapp

```
```yml
# compose.yml
services:
  db:
    image: postgres
    restart: always
    environment:
      TZ: Asia/Tokyo
      POSTGRES_PASSWORD: password
    volumes:
      - postgresql_data:/var/lib/postgresql
    ports:
      - 5432:5432
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -d myapp_development -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5
  web:
    build:
      context: .
      dockerfile: Dockerfile.dev
    command: bash -c "bundle install && bundle exec rails db:prepare && rm -f tmp/pids/server.pid && rails s -b 0.0.0.0"
    tty: true
    stdin_open: true
    volumes:
      - .:/myapp
      - bundle_data:/usr/local/bundle:cached
    environment:
      TZ: Asia/Tokyo
    ports:
      - "3000:3000"
    depends_on:
      db:
        condition: service_healthy
volumes:
  bundle_data:
  postgresql_data:
```
```
$ docker compose build
```
### Railsアプリケーションの作成
```
$ docker compose run --rm web gem install rails -v '~> 7.0'
```
- APIモードで`rails new`します
```
$ docker compose run --rm web rails new . --api --force --database=postgresql
```
- `config/database.yml`に`host`,`username`,`password`を追記します
```yml
# config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  host: db # 追記
  username: postgres # 追記
  password: password # 追記
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
```
$ docker compose run --rm web rails db:create
$ docker compose up
```
- `localhost:3000`にアクセスするとRailsの画面が表示されます

![スクリーンショット 2024-12-08 17.24.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760414/fea93c41-0300-05b3-69e1-817c2b82e031.png)

### Graphqlの導入
- RailsでGraphqlを使用する際に必要なgemです
- `graphiql-rails`は開発環境でIDEを導入するためのgemです
```ruby
# Gemfile
gem 'graphql'
gem 'graphiql-rails', group: :development
```
https://github.com/rmosolgo/graphql-ruby

https://github.com/rmosolgo/graphiql-rails

- `graphiql-rails`を使うためにSprocketsかPropshaftが必要になります（詳細は[こちら](https://github.com/rmosolgo/graphiql-rails?tab=readme-ov-file#sprockets-or-propshaft)）
- 今回はPropshaftにしました
```ruby
# Gemfile
gem 'propshaft'
```
- `docker compose up`しているのと別のターミナルで操作
```
$ docker compose exec web bash
$ bundle install
```
- 続いてGraphqlに関わるファイルを追加します
```
$ bin/rails g graphql:install
```
- またAPIモードの場合`app/assets/config/manifest.js`の追加が必要なので追加します（詳しくは[こちら](app/assets/config/manifest.js)）
```
$ mkdir -p app/assets/config
$ touch app/assets/config/manifest.js
```
```js
// app/assets/config/manifest.js
//= link graphiql/rails/application.css
//= link graphiql/rails/application.js
```
- 一通りの設定を終えて必要であれば一度コンテナを落としてから再起動しましょう
- `localhost:3000/graphiql`にアクセスすると下記のような画面が確認できます

![スクリーンショット 2024-12-08 21.46.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3760414/4282bc5f-3644-7c50-fafc-5c282511fbc3.png)

# まとめ
今回は、Rails×GraphQL×Dockerの環境構築についてまとめました。
これまで学習をしていて初学者だと、新しい技術に触れる際、環境が立ち上がらないと中々学習を進めるのが難しいと感じてしまうことが多々ありました。
その際、コピーアンドペーストで一旦動く環境を作ることができるとかなりハードルが下がるなと思ったため今回の記事はそのことも意識して執筆しました。GraphQLの学習に少しでもお役に立てましたら幸いです。

ここまで読んでいただきありがとうございました！