Postgraphile＋Apolloをテストで立ち上げる

Postgraphileはnode.jsで動く。
Postgresから簡単にGraphQL作れるらしい
[ここ](https://zenn.dev/adwd/articles/7c081b2f8a977f)とかを見て試す。
環境はWindowsServer2012

# Postgraphileインストール
Postgresは既にローカルで動いているので省略。

`npm install postgraphile`

実際には今回は面倒なので-gでインストール。(npxでローカルでも実行できるはず？）
4.12.8がインストールされた。

起動は以下のコマンド
`postgraphile -c postgres://postgres:password@localhost:5432/postgres --watch --enhance-graphiql --dynamic-json`

これで起動出来た

```
  ‣ GraphQL API:         http://localhost:5000/graphql
  ‣ GraphiQL GUI/IDE:    http://localhost:5000/graphiql
  ‣ Postgres connection: postgres://postgres:[SECRET]@localhost/postgres (watching)
```

このURLにアクセスして確認、しようと思ったがpublic schemaだった。`--schema test`でスキーマを指定できる。
実際に昔作ったtestテーブルでクエリ発行

```
query MyQuery {
  allTests(first: 10) {
    edges {
      node {
        id
      }
    }
  }
}
```

```
{
  "data": {
    "allTests": {
      "edges": [
        {
          "node": {
            "id": 1
          }
        },
        {
          "node": {
            "id": 2
          }
        },
        {
          "node": {
            "id": 3
          }
        }
      ]
    }
  }
}
```
と簡単に出来た。

# HTTPサーバから立上げ
node.jsのサーバ経由で使う方法もある。
[公式](https://www.graphile.org/postgraphile/usage-library/)にも載っている。

```
const express = require("express");
const { postgraphile } = require("postgraphile");

const app = express();

app.use(
  postgraphile(
    process.env.DATABASE_URL || "postgres://user:pass@host:5432/dbname",
    "public",
    {
      watchPg: true,
      graphiql: true,
      enhanceGraphiql: true,
    }
  )
);

app.listen(process.env.PORT || 5000);
```

ただ、これで実行すると
`Ensure that there is only one instance of "graphql" in the node_modules directory.`
のエラーが出てしまったので、何かインストールしたものが悪いのかもしれない。

```
"resolutions": {
 "graphql": "15.5.0"
}
```
のように書いて解決、と[ネット上](https://qiita.com/koedamon/items/0fd3a01f7e398e54b747)では書いてあるが、色々面倒そうなのでここでは諦める。。。
`"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0",`と@apolloの中には書いてあった。


なお、Productionでの推奨オプションは

```javascript
const postgraphileOptions = {
  subscriptions: true,
  retryOnInitFail: true,
  dynamicJson: true,
  setofFunctionsContainNulls: false,
  ignoreRBAC: false,
  extendedErrors: ["errcode"],
  appendPlugins: [require("@graphile-contrib/pg-simplify-inflector")],
  graphiql: false,
  enableQueryBatching: true,
  disableQueryLog: true, // our default logging has performance issues, but do make sure you have a logging system in place!
  legacyRelations: "omit",
  pgSettings(req) {
    /* TODO */
  },
};
```
と書いてあるが詳しくは見ていない。


# その他サーバ側

セキュリティ関係については[公式](https://www.graphile.org/postgraphile/production/)にいくつか書いてある。
DoSに関してはhttps://www.apollographql.com/blog/graphql/security/securing-your-graphql-api-from-malicious-queries/を参照。
一般的にはhttps://github.com/graphile/persisted-operationsのプラグインを入れるのが良いらしい。

オプションにbodySizeLimitがある。
graphqlDepthLimitやgraphqlCostLimitのような制限を使いたい場合はPro版が存在する、っぽい。

うまく動かないときは
[ここ](https://www.ey-office.com/blog_archive/2021/08/27/react-admin-plus-postgraphile-was-not-easy/)とか参考？

GraphQLよりRestAPIだろ、という場合はRestAPIを作る[PostgRESTの記事](https://qiita.com/kanedaq/items/0c3097604d0e86afd1e3)

# Apolloクライアント
GraphQLに繋ぐ側として、今回はついでにApolloのクライアント側だけ試しておく。
[ここ](https://qiita.com/jintz/items/4ddc6bf4f95238eff5e9)や[ここ](https://pgmemo.tokyo/data/archives/2084.html)とか[ここ](https://qiita.com/seya/items/26c8a0dc549a10efcdf8)を見ながら。

##apolloクライアント
Reactではなくnode.js単体で返すパターンでテスト。
あまり情報がないが[ここ](https://newbedev.com/apolloclient-is-not-a-constructor-apollo-client-with-nodejs)が多少参考になる。

まずは必要なものをインストール
`npm install @apollo/client graphql apollo-boost node-fetch react`

サーバはpostgraphileコマンドで立ち上げている。
expressを使って/apiにアクセスするとGraphQLから取得するようにnode.js側を組んでみた。
試行錯誤でごちゃごちゃやっているので、不要な処理もあるはず。

```javascript
import apolloClient, { gql } from "apollo-boost";
import express from "express";
import apolloInMemoryCache from 'apollo-cache-inmemory';
import apolloHttpLink from 'apollo-link-http';
import nodeFetch from 'node-fetch';
global.fetch = nodeFetch;
const { HttpLink } = apolloHttpLink;
const { InMemoryCache } = apolloInMemoryCache;
const { ApolloClient } = apolloClient;
const app = express();
var server = app.listen(3000, function(){
    console.log("Node.js is listening to PORT:" + server.address().port);
});

const client = new ApolloClient({
  uri: 'http://localhost:5000/graphql', // このパターンだとこれは必要ないはず
  cache : new InMemoryCache(),
  link:  new HttpLink( {uri:'http://localhost:5000/graphql'})
});

async function getTestProps() {
    const {data} = await client.query({
      query: gql`
      query MyQuery { allTests(first: 10) { edges { node { id name } } } }
      `,
    });
    return data
}

// 外部から取得する際の処理
app.get("/api", async function(req, res, next){
    let data =  await getTestProps();
    res.json(data);
});
```

これでデータが返ってきた。

```
{"allTests":{"edges":[{"node":{"id":1,"name":"one","__typename":"Test"},"__typename":"TestsEdge"}
,{"node":{"id":2,"name":"two","__typename":"Test"},"__typename":"TestsEdge"}
,{"node":{"id":3,"name":"therr","__typename":"Test"},"__typename":"TestsEdge"}],"__typename":"TestsConnection"}}
```