ighthouse - GraphQL server for Laravel でget相当の機能を実装する


GraphQLのシンプルさはフロントエンドから見るととても魅力的です。
Reactアプリの開発も捗りそうなので、既存のRESTful APIと併設する形で試験実装してみました。
Apacheサーバーで、PHPを動かしている場合でもLighthouseという強力なGraphQLフレームワークがあるのでかなり楽に立ち上げることができました。

ですが、既存のデータベースを対応させようとするとかなり色々設定しなくてはならず、すんなりとは行かなかったので、つまづいた場所を中心に設定箇所をまとめてみました・

試行環境

ソフトウェア バージョン
MacOS 10.10.5
PHP 7.2.5
Laravel 7.0 1
Lighthouse 4.10 2

サーバの立ち上げはLaravelやLighthouseのセットアップは終わっている状態から始めます。
またデータベースへの接続設定も終わっているものとします。

準備

プロジェクトの作成と、lighthouseなど各種必要なものをインストールします。

$ composer create-project --prefer-dist laravel/laravel graphql
$ cd graphql
$ composer require nuwave/lighthouse
$ php artisan vendor:publish --provider="Nuwave\Lighthouse\LighthouseServiceProvider" --tag=schema
$ composer require mll-lab/laravel-graphql-playground
$ php artisan serve

localサーバーが起動するので、ブラウザからlocalhost:8000にアクセスして開発中の画面を確認します。
また、//localhost:8000/graphql-playground でクエリの実行確認などができます。

スキーマの定義

webアプリなどから問い合わせる際の形式を定義する所です。
ここで項目の名前やデータの型などを定義していきます。
定義する作業をやってみると、RESTfulでエンドポイントを考えている時と同じ様な感覚でした。

schema.graphql
scalar Date @scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\Date")

type Query {
    book(isbn: Int! @eq(key: CODE)): Book @find
}

type Book {
   isbn: Int
   title: String
   unit_price: Int
   released_on: Date
}

書籍データの問い合わせを行う形式を定義してみました。

Queryの{}内で問い合わせできるデータの形式や引数を定義しています。
ここではbookという名前でBook形式のデータをisbnという名前のInt型データで一致するものを問い合わせすることを定義しています。
Bookのデータ形式は別途 type Book{} で定義しています。

これで、//localhost:8000/graphql-playground の画面で実際に問い合わせができる様になったはずです。

以下の様なクエリーを投げられる様になっているはずです。

query {
   book(isbn: 4150200858){
      title
      unit_price
      released_on
   }
}

エラーが出ることなく null データが返ってきたでしょうか?
nullデータが返ってきていれば、スキーマ定義は成功です。

クエリの実装

次は、実際にデータを返す部分の実装になります。
その前に、実データが入っているデータベースのサンプルを提示しておきます。

table:HDL010

CODE NAM TANKA YMD
4253903592 ブラック・ジャック 10656 20030920
4150200858 プリンセス・ブライド 614 19860501
4488725007 銀河英雄伝説 12848 20171012

カラム名を isbn, title, unit_priceなどとして欲しいところが、どう言うわけかローマ字まじりの名前になっていてテーブル名も何の略語かわからないというサンプルデータです

まずはLaravelでモデルを作成します

php artisan make:model Models/Book

app/modelsの中に Book.php というファイルが作成されたはずです。
これで Laravel の Eloquent を継承した Book というモデルが作成されました。
が、参照するべきデータベースのテーブルがLaravelの命名規則に従っていないため、このままではデータを取得できません。
そこで、以下の様にカスタマイズします。

app/Models/Book.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    protected $table = 'HDL010';
    protected $primaryKey = 'CODE';

    public function getIsbnAttribute(){ return $this->attributes['CODE']; }
    public function getTitleAttribute(){ return $this->attributes['NAM']; }
    public function getUnitPriceAttribute(){ return $this->attributes['TANKA']; }
    public function getReleasedOnAttribute(){ return date('Y-m-d', strtotime($this->attributes['YMD']); }
}

これで、nullデータしか返ってこなかった問い合わせがデータを伴って返ってくる様になったはずです。

最後に

LaravelのEloquentや、それを活用したLighthouseは非常に簡単にGraphQLを実装できるツールですが、既存のデータベースが命名規則に則っていなかったり、データベースの正規化が不十分な場合はすんなりといきません。
データ型によってはリレーションもうまく行かずにデータが正しく取得できない場合もありました。
それでも、Laravelには例外に対するカスタマイズが用意されていて、その設定さえキチンと行えば、Lighthouseがうまく処理をしてくれるので、相当楽にGraphQLサーバを立ち上げることができました。

ただ、この”キチンと設定”というのが、ネットで調べてもなかなかたどり着けない、ちょっとしたコツと言った感じでした。