はじめに#

Graphql 使っていますか?

iamfax.comではgraphqlを積極的に使っています。Graphqlは最初中々使う理由を見いだせないかもしれませんが、

  • エンドポイントが一つでまとまり、バージョン管理の簡略化( v1/v2/.. などのRESTあるあるがなくなる)
  • 強力な型システム
  • リレーションシップを持つデータを一度のリクエストで取得可能
  • リアルタイムデータのためのサブスクリプション

等、使ってみると強力な機能があり、なにはともあれまずは一度は使ってみることをおすすめします。RESTでよくね?と感じると思うかもしれませんが、使えば良さがわかって来ると思います。

さて、実際にGraphql使ってみましょう!というのは簡単ですが、使うための環境構築が面倒です。そこで、今回はGraphqlを手軽に使うために、オープンソースのHASURAを使ってGRAPHQLサーバーを作り、使う環境を整えます。

Hasura とは?#

Graphqlの問題?のひとつが構築がめんどくさいというところです。Lalavel, RailsやDjangoなどで構築しないと…なんて考えるとDockerがあるとはいえ面倒です。そこでHASURAです。

HASURAはテーブルさえ作ればGraphQLサーバーを構築することが可能なオープンソースのGraphQLサーバーです!PostgreSQLのテーブルを作るだけでいいんです!随分お手軽でしょう?

HasuraはGUIのポチポチとするだけでサーバーが作れますので、今回はStep by stepで画像形式でインストール方法を説明していきます。

最後にRUSTでアクセスして通信する事例もご紹介します。

Docker compose を使って Hasura を構築する#

次のDocker compose を用意します。

services:
  postgres:
    image: postgres:16.1 # 最新のPostgreSQLイメージを指定
    restart: always
    volumes:
      - db_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgrespassword # 強力なパスワードに変更してください
  graphql-engine:
    image: hasura/graphql-engine:v2.47.0 # 最新のHasuraイメージを確認してください
    ports:
      - "8080:8080"
    depends_on:
      - "postgres"
    restart: always
    environment:
      ## postgres database to store Hasura metadata
      HASURA_GRAPHQL_METADATA_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## this env var can be used to add the above postgres database to Hasura as a data source. this can be removed/updated based on your needs
      PG_DATABASE_URL: postgres://postgres:postgrespassword@postgres:5432/postgres
      ## enable the console server
      HASURA_GRAPHQL_ENABLE_CONSOLE: "true" # set to "false" to disable console
      ## enable debugging mode. It is recommended to disable this in production
      HASURA_GRAPHQL_DEV_MODE: "true"
      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log
      ## uncomment next line to set an admin secret
      # HASURA_GRAPHQL_ADMIN_SECRET: myadminsecretkey
volumes:
  db_data:

Docker compose 環境は構築済みと仮定しています。まだの人は公式サイトを参考に構築しましょう。

Hasura: GUIでテーブルを作る方法#

Hasuraコンソールの上部メニューから「DATA」を選択します。 Step1 このような画面になるので、「Connect Database」を押してPostgres dbを選択します。 Step2 Step3 ここで、DBのセットアップができます。Environment variableにしておき、先程のDocker compose に記載されているHASURA_GRAPHQL_METADATA_DATABASE_URLと書きます。Database nameは適当で構いません。Connect databaseを押します。

Step4

テーブルを作る#

DBと接続できたら試しに、Userテーブルを作ります。dataより、「Create Table」ボタンをクリックします。 Step5 テーブル情報を入力します:


```Table Name: users
Columns:
id (Type: Integer (auto-increment), Primary Key: チェック)
name (Type: Text, Nullable: false)
email (Type: Text, Nullable: true, Unique: チェック)
Primary Key: id

Step6 上記のような形になったら、「Add Table」をクリックします。

サンプルデータを追加する#

「Insert Row」タブで、いくつかサンプルデータを追加します(例: id=1, name=“Alice”, email=“[email protected]”)。 上部メニューから「API」を選択します。 Step7 GraphiQLエクスプローラーが表示されるので、以下のクエリを試してみてください。

query MyQuery {
  users {
    id
    name
    email
  }
}

Step8

RUSTでアクセスする#

外部からアクセスできるかどうか、今回はRUSTで試してみます。別にPythonだろうがRuby, Goだろうがいいのですが、今回は型厳格なGraphqlを使っていますので、せっかくならRUSTで試してみましょう。

次のmain.rsを用意します。

use reqwest::Client;
use serde::{Deserialize};
use serde_json::json; // serde_json::json! マクロを使うために必要

// GraphQLのレスポンス構造体 (usersクエリに対応)
#[derive(Debug, Deserialize)]
struct User {
    id: i32,
    name: String,
    email: Option<String>, // emailはNullableなのでOption
}

#[derive(Debug, Deserialize)]
struct UsersData {
    users: Vec<User>,
}

#[derive(Debug, Deserialize)]
struct GraphQLResponse {
    data: Option<UsersData>, // "data"フィールドはクエリ成功時に存在する
    errors: Option<serde_json::Value>, // エラーがあればここに入る
}

// Hasuraのエンドポイント
const HASURA_ENDPOINT: &str = "http://localhost:8080/v1/graphql";
// 必要であればAdmin Secretを設定 (docker-compose.ymlで設定した場合)
// const HASURA_ADMIN_SECRET: &str = "myadminsecretkey";

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = Client::new();

    // 実行したいGraphQLクエリ
    let query = r#"
        query GetAllUsers {
          users {
            id
            name
            email
          }
        }
    "#;

    // GraphQLリクエストのペイロード
    let request_payload = json!({
        "query": query,
        // "variables": {} // 必要であれば変数を追加
    });

    println!("Sending GraphQL query to Hasura...");

    let request_builder = client.post(HASURA_ENDPOINT)
        .header("Content-Type", "application/json");

    // Admin Secretが設定されている場合はヘッダーに追加
    // if !HASURA_ADMIN_SECRET.is_empty() {
    //     request_builder = request_builder.header("X-Hasura-Admin-Secret", HASURA_ADMIN_SECRET);
    // }

    let response = request_builder
        .json(&request_payload)
        .send()
        .await?;

    if response.status().is_success() {
        let gql_response: GraphQLResponse = response.json().await?;

        if let Some(data) = gql_response.data {
            println!("Successfully fetched users:");
            for user in data.users {
                println!(
                    "  ID: {}, Name: {}, Email: {}",
                    user.id,
                    user.name,
                    user.email.as_deref().unwrap_or("N/A") // Option<String>の表示
                );
            }
        } else if let Some(errors) = gql_response.errors {
            eprintln!("GraphQL errors: {:?}", errors);
        } else {
            eprintln!("Received successful response but no data or errors.");
        }
    } else {
        eprintln!(
            "Failed to query Hasura. Status: {}. Body: {}",
            response.status(),
            response.text().await?
        );
    }

    Ok(())
}

cargo.tomlは次のとおりです。

[package]
name = "hasura_rust_hello"
version = "0.1.0"
edition = "2024"

[dependencies]
tokio = { version = "1", features = ["full"] }
reqwest = { version = "0.11", features = ["json"] } # HTTPクライアント
serde = { version = "1.0", features = ["derive"] } # JSONのシリアライズ/デシリアライズ
serde_json = "1.0" # JSON操作

さて、実行してみましょう

$ cargo run
Sending GraphQL query to Hasura...
Successfully fetched users:
  ID: 1, Name: fax_all_you_need_is, Email: [email protected]

きちんと表示されれば成功です

おわりに#

今回は、Docker ComposeとHasuraを使って、非常に手軽にGraphQL APIサーバーをローカル環境に構築し、Rustからアクセスする方法をご紹介しました。Hasuraの「テーブルを作るだけでGraphQL APIが完成する」という手軽さは、GraphQLを試してみたい、あるいは迅速にAPIをプロトタイピングしたい場合に大きなメリットとなります。

GUIで直感的に操作できるため、学習コストも比較的低く、すぐにGraphQLの強力な機能を体験できるでしょう。

Hasuraの限界と考慮点

これほど便利なHasuraですが、「これだけで全てOK!」というわけではありません。いくつかの限界や、より複雑なシステムを構築する際に考慮すべき点があります。

  • 複雑なビジネスロジックの分離: 例えば、「ユーザー登録時にウェルカムメールを送信する」や「注文確定時に複数の外部サービスと連携して処理を行う」といった、データベース操作以外の複雑な副作用やワークフローを含むビジネスロジックは、Hasura自体に直接書き込むことはできません。これらはHasuraの ActionsEvent Triggers といった機能を使って、外部のカスタムロジック(例えばRustやPythonで書いた別のマイクロサービスやサーバーレス関数)に処理を委譲する形で実装する必要があります。

  • リクエスト/レスポンスの高度な処理: クライアントからのリクエストデータや、データベースからのレスポンスデータを、Hasuraが自動的に行う以上の複雑な形式に変換したり、高度なバリデーションを行ったりする処理は、Hasura単体では難しいです。これも同様にActionsなどを活用して、連携する外部サービス側で対応することになります。

つまり、Hasuraはデータベースを中心としたGraphQL APIの強力な基盤として機能しますが、アプリケーション全体のロジックを全て担うわけではありません。Hasuraの得意な部分(DBからのAPI自動生成、認証・認可、リアルタイム性など)を活かしつつ、より複雑な部分は他のサービスと連携させるアーキテクチャを考えることが重要です。

とはいえ、多くの一般的なウェブアプリケーションやモバイルバックエンドにおいて、Hasuraは開発速度を大幅に向上させ、GraphQLの恩恵をすぐに享受できる素晴らしいツールです。ぜひ、ご自身のプロジェクトで試してみてください!