EY-Office ブログ

React-admin + PostGraphileで管理画面を作ろうとしたが簡単ではなかった

最近、AWS関連の記事8月5日8月12日8月18日を書いているのはバックエンドの開発を行っているからです。バックエンドはフロントエンドにAPIを提供するのが一番の目的ですが、管理画面も重要な機能だと思います。

管理画面といえば業務フローをサポートするための画面もありますが、ここではデータの確認や簡単な修正、いわゆるデーターベースのCRUD画面(Create, Read, Update, Delete)に付いての書きます。

React-admin + PostGraphile

React-admin、PostGraphileとは

CRUD画面を簡単に作成できるツールやライブライリーは多く存在します。たとえばRuby on RailsにはRailsAdminのような有名なライブラリーがあります。
今回の仕事の参加する開発者はReactプログラマーなので、管理画面もReactベースのものが良いと思います。Reactベースの管理画面ライブライリーも多数ありますが、ReactAdminが良く使われているようです。

React-admin

ReactAdminチュートリアルのMapping API Endpoints With Resourcesにあるように簡単なコードでCRUD画面が作れます。また画面をカスタマイズする場合はReactコンポーネントとして作るので将来の拡張もやりやすそうです。
さらにReactAdminはサーバーとの接続部分がData Providersとして分離されていて、RestAPI, GraphQLをはじめFirebase用など、たくさんのプロバイダーがすでに在ります。

PostGraphile

今回のシステムはRDBにはPostgreSQLを使います、いろいろと検索していたらPostGraphileというものを見つけました!

PostGraphileはメカニカル(メタリック)な像がアイコンになっています、ご存じなようにPostgreSQLのアイコンはです。このメカ像は、PostgreSQLデータの問合せ・変更できるGraphQLサーバーが簡単に作れる素晴らしいソフトウェアです。

PostGraphileはスタンドアロンでも使えますが、Express等に組み込めるライブライリーとしても使えます。PostGraphileを起動すると組み込まれているGraphQLのWebクライアントGraphiQLを使ってPostgreSQLのテーブルがGraphQLで問合せ・変更(query・mutation)を試せます。

また、React-adminにはPostGraphileに接続する専用プロバイダーra-postgraphileがあります。

React-admin、PostGraphileを試してみた

PostgreSQL、PostGraphileを使ったExpressサーバー、React-admin用React環境をDocker Desktop for Mac上に作り試してみました。ここから色々な問題にぶち当たります😅。

1. ra-postgraphileのサンプルコードが動かない

React-adminra-postgraphileページに簡単なサンプルコードがあるので、これを参考に管理画面のコードを書きましたがエラーになってしまいました。Apollo Clientを使っていますがコードが古いのかもしれません。いろいろと調べ以下のようなコードで動きました(as any がまだ解決できていませんね)。

import { useEffect, useState } from 'react'
import { Admin, Resource, ListGuesser, ShowGuesser, EditGuesser, LegacyDataProvider,
  List, Datagrid, TextField, DateField, EmailField, ReferenceField,
  EditButton, ResourceProps, ResourceComponentProps } from 'react-admin';
import { ApolloProvider, useApolloClient } from '@apollo/react-hooks'
import pgDataProvider from 'ra-postgraphile'
import { ApolloClient, InMemoryCache } from '@apollo/client'

const ReacTAdmin = () => {
  const [dataProvider, setDataProvider] = useState<LegacyDataProvider|null>(null)
  const client = useApolloClient()

  useEffect(() => {
    (async () => {
      const dataProvider = await pgDataProvider(client as any) // TODO fix any
      setDataProvider(() => dataProvider)
    })()
    }, [client])

  return (
    dataProvider && (
    <Admin dataProvider={dataProvider}>
      <Resource name="users" list={ListGuesser} show={ShowGuesser} edit={EditGuesser}/>
    </Admin>)
  )
}

export const App = () => {
  const apolloClient = new ApolloClient({
    uri: `http://localhost:5000/graphql`,
    cache: new InMemoryCache()})

  return (
    <ApolloProvider client={apolloClient}>
      <ReacTAdmin />
    </ApolloProvider>
  )
}

2. Cannot query field “users” on type “Query”. Did you mean “user” …

React-adminとPostGraphileが接続できるようになりましたが、React-adminのコンソールにCannot query field "users" on type "Query". Did you mean "user", "allUsers", or "query"?というエラーが表示されました。
上のコードの<Resource name="users" ...usersがいけないようです、試しに<Resource name="allUsers" ...と変更したところエラーは発生しなくなりましたが何も表示されませんでした。

いろいろ調べましたが解決しません。😅😅😅

しかし、React-Admin and Postgraphile playgroundというReact-admin + ra-postgraphile + PostGraphileを使ったサンプルコードがGitHubにありました。早速git cloneして動かしてみました(Docker化されているので直ぐに動きました)。なんと同じDBを使ってもGraphiQLの左側に表示されているスキーマ一覧が違います。

私のPostGraphileサーバーstephane-kleinさんのサンプル
AllGroupsgroups
AllUsersusers
group
groupByIdgroup
user
userByIduser

PostGraphileの設定が違うようです、stephane-kleinさんのサンプルコードを読んでみるとPostGraphileに PgSimplifyInflectorPluginというプラグインが使われています。私のPostGraphileサーバーにもこのプラグインを追加したところ同じスキーマ一覧になりました!

ra-postgraphileページをよく見るとLimitationsのところにPgSimplifyInflectorPlugin,PgConnectionFilterPluginを入れている環境でテストしていると書かれていました。😅

3. Error: You must declare a <Resource name=“nodes”> in order to use…

しかし、Error: You must declare a <Resource name="nodes"> in order to use a <ReferenceField reference="nodes"><ReferenceField source="nodeId" reference="nodes"><TextField source="id" /></ReferenceField>というエラーが発生します。

ここに出てくるnodeIdは上のGraphiQL画像に表示されていますが、query結果のオブジェクトに付いているユニークなIDです。これはFacebbokが作ったGraphQLクライアントライブライリーRelayで導入されたものです、クライアント側でデータをキャッシュするのに役立つIDです。詳細はこちら

しかし、stephane-kleinさんのサンプルではnodeIdは使われていませんでした。コードを見るとskipPlugins: [NodePlugin] でnodeId機能をスキップしていました。この設定を入れてやっとReact-adminの画面にusersテーブルの内容が表示されました! 👏
もちろん、変更等も動作しました 👏👏

まとめ

React-admin + PostGraphileで、(半日くらい悩みましたが)比較的簡単に管理画面ができました。

ただし色々な問題を解決できたのは、Stéphane Kleinが作られたReact-Admin and Postgraphile playgroundのおかげです。

Stéphane Kleinさん、ありがとうございます!!

- about -

EY-Office代表取締役
・プログラマー
吉田裕美の
開発者向けブログ