なぜこれを書くのか
GraphQLといえば、手軽さでいうとこのマネージドサービス、AWS AppSyncが出てきます。
バンバン使っていきたいところです。
公式のやりかたはこちらのドキュメントです。
以下のソースコードのようにAWSAppSyncClientというライブラリを使っていて分かりづらい。
apollo-link
を直接使ったほうがブラウザ側だけでなくサーバ側アプリにも使えて可搬性が高い。
なので単なるapollo-linkだけを使ったNode.jsアプリからAppSyncにアクセスしたいです。
なので、そういう事例を作ってみます。
const AWSAppSyncClient = require('aws-appsync').default;
// Set up Apollo client
const client = new AWSAppSyncClient({
url: url,
region: region,
auth: {
type: type,
credentials: credentials,
}
//disableOffline: true //Uncomment for AWS Lambda
});
client.hydrated().then(function (client) {
//Now run a query
client.query({ query: query })
//client.query({ query: query, fetchPolicy: 'network-only' }) //Uncomment for AWS Lambda
.then(function logData(data) {
console.log('results of query: ', data);
})
.catch(console.error);
});
AppSyncで少し遊んで原理を確認
結局、いろいろみても、
- jQueryを使った事例にもあるように、AppSyncに単なるjQueryのAjaxでもアクセスできています。
- AWSAppSyncClientは単なるapollo-clientのラッパですと公式に書いてあります。
本当は難しくないはずなのです。
怖がらなくても、AppSyncは単なるAPI_KEY認証のGraphQLサーバ
AppSyncでのAPIの作り方は、Qiita記事を参考にするとすぐにできます。
作ったAPIの管理画面から「Download configs」をクリックするとこんなファイルがダウンロードできます。
ダウンロードしたaws-exports.js
ファイル
const awsmobile = {
"aws_appsync_graphqlEndpoint": "https://***************.appsync-api.**********.amazonaws.com/graphql",
"aws_appsync_region": "*************",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "*******************",
};
export default awsmobile;
中身にはAPI_KEYなどが入っています。
このAPI_keyが使えればいいわけです。
ひとまず、InsomniaというAPIテストツールから実行してみます。
URLには上記でダウンロードしたconfig内のURL、X-Api-Keyにはconfig内のapiKeyを設定して、クエリを実行すると、下のようにAPIにアクセスできました。
API_KEY認証はapollo-linkのheadersでできます
X-Api-Key
というヘッダを付ければ動く、ということがわかれば、あとはapollo-linkがそれに対応するかどうかですが、
むろんapollo-linkは対応しています。
こんな風にHttpLink
のコンストラクタにheaders
を入れて好きにヘッダを書き込めばいいです。
new HttpLink({
uri: URL,
headers: {
'X-ヘッダの名前': ヘッダの値
}
})
本編:apollo-linkを使ったアクセスの実装
今回は、Node.jsのアプリでAppSyncにアクセスします。
アプリのソースコードのフォルダで作業します。
まず、先ほどAPI管理画面の「Download configs」からダウンロードした下記のaws-exports.js
をアプリのフォルダに入れます。
const awsmobile = {
"aws_appsync_graphqlEndpoint": "https://***************.appsync-api.**********.amazonaws.com/graphql",
"aws_appsync_region": "*************",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "*******************",
};
export default awsmobile;
アプリのファイルindex.js
にインポートします。
const aws_exports = require('./aws-exports').default;
さいごに、apollo-linkで上記設定を使ってLinkを作ります。
const { HttpLink } = require('apollo-link-http');
//もしくはimport { HttpLink } from 'apollo-link-http';
const fetch = require('node-fetch');
const uri = aws_exports.aws_appsync_graphqlEndpoint,
const apiKey = aws_exports.aws_appsync_apiKey;
const link = new HttpLink({uri, fetch, headers: {
'X-Api-Key': apiKey
}});
このLinkを使ってAppSyncにクエリを投げます。
実装例
私はNode.jsを使って、graphql-tools
のリモートスキーマを作成しAppSyncの結果をそのままフォワードするアプリを作りました。
import {makeRemoteExecutableSchema, mergeSchemas, introspectSchema} from 'graphql-tools';
const fetch = require('node-fetch');
const { HttpLink } = require('apollo-link-http');
const { ApolloServer, gql } = require("apollo-server-express");
import serverless from "serverless-http";
import express from "express";
const aws_exports = require('./aws-exports').default;
const createSchema = async () => {
const createRemoteSchema = async (uri, apiKey) => {
const link = new HttpLink({uri, fetch, headers: {
'X-Api-Key': apiKey
}});
return makeRemoteExecutableSchema({
schema: await introspectSchema(link),
link
});
};
const citySchema = await createRemoteSchema(
aws_exports.aws_appsync_graphqlEndpoint,
aws_exports.aws_appsync_apiKey);
return citySchema
};
const run = async () => {
const schema = await createSchema();
const app = express();
const server = new ApolloServer({ schema });
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`Server ready at http://localhost:4000${server.graphqlPath}`)
);
}
run()
AWS Lambdaでも動く
最後のrun()以降を下記に変えると、AWS Lambda上でもちゃんと動きました。
const createServer = (schema) => {
const app = express();
const server = new ApolloServer({ schema });
server.applyMiddleware({ app });
return serverless(app);
};
let sls
exports.graphqlHandler = async (event, context) => {
if(sls == null) {
const schema = await createSchema();
sls = createServer(schema);
} else {
console.log("Already initialized")
}
return await sls(event, context);
}
まとめ
AppSyncのGraphQLにアクセスするアプリを作るため、apollo-linkを使った実装例を示しました。
Node.jsサーバアプリとしても動きますし、ちょっと変えればAWS Lambdaでも動きます。
AppSyncだけではちょっと難しい複雑な処理をLambda上でやらせるときに使えそうです。
使ってみてください。