2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

朝日新聞社Advent Calendar 2022

Day 18

pureなjsでGraphQLのrequestを投げる方法(Lambda@Edgeなど)

Last updated at Posted at 2022-12-17

Lambda@EdgeからとあるエンドポイントにGraphQLのqueryを実行したい場合がありました。
Lambda@Edgeにはレイヤーをアタッチすることができないので、Lambdaのランタイムに組み込まれている方法でhttpリクエストを飛ばす必要があります。
(正確にはコードとライブラリをまとめたzipが1MB以下に収まるのであれば、そのzipをデプロイすることでサードパーティのNodeライブラリも利用することができるようになりますが、実装時点では調査が足らず不可能だと思っていました。詳しくは下のリンクをご参照ください。)

今回はとある事情から、ランタイムとしてNode.jsのv16系を利用していました。
Nodeのhttpクライアントライブラリとしてはaxiosnode-fetchなどがよく使われますが、Node16にこれらは組み込まれていません。
Node.jsのv18系を使えるなら、fetchがデフォルトで使えるためそちらを使った方が良いでしょう。

Node.jsのv16系では唯一httpsのみが組み込みで使えますが、それを利用した場合のGraphQLのquery実行の方法が分かりづらかったので、メモの意味合いも兼ねて記事にしようと思います。

いきなりコードを共有

エラーハンドリングなどは適当な部分もありますので、参考にする際は適宜処理を追加して下さい。

"use strict";

const https = require("https");

const options = {
  hostname: "hogepiyotest.com", // リクエスト先のホスト名を指定
  path: "/",
  port: 443,
  method: "POST",
  headers: {
    "Content-Type": "application/json",
  },
};

// 実行したいQuery
const infoQuery = `
query Info($id: ID!) {
  info(id: $id) {
    id
    description
  }
}
`;

const getInfo = (operation, id) => {
  const requestBody = JSON.stringify({
    operationName: operation,
    variables: {
      id: id,
    },
    query: infoQuery,
  });

  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let body = "";
      res.on("data", (d) => {
        body += d;
      });
      res.on("end", () => {
        console.log(JSON.parse(body).data);
        resolve(JSON.parse(body).data);
      });
    });

    req.on("error", (error) => {
      console.error(error);
      reject(new Error(error));
    });

    req.write(requestBody);
    req.end();
  });
};

exports.handler = async (event) => {
  const request = event.Records[0].cf.request;
  const path = request.uri;
  // 今回はアクセスされたURLのパスの一番目に、欲しい情報に対応するIDを指定すると仮定
  const pathList = path.split("/");
  const id = pathList[1];

  const fetchedData = await getInfo("info", id);
  // 以下、受け取った内容をご所望の形に整形してください
  ...
};

ざっくり解説

今回のミソは、httpsを使ってGraphQLのリクエストをどのように投げれば良いのか、ということに尽きます。
こちらを参考に実装しましたが、少しだけ解説します。

getInfoという関数がGraphQLのリクエストの役割を担っており、その中でPromiseを利用した非同期処理を行います。
Promiseの中にあるhttpsを使ったリクエストがその非同期処理の正体です。

ここでGraphQLのリクエストについて簡単に説明します。
GraphQLのリクエストで送信できるデータは、queryoperationNamevariablesの3つです。
queryは必須で、GraphQLクエリを記述します。GraphQLは単一のエンドポイントを介して機能するため、エンドポイントが応答するデータはすべてクエリに依存します。

variablesはオプションで、クエリに渡される変数の値を含むJSONオブジェクトです。例えば、クエリにidという変数が必要な場合(クエリにおいては$idと表示される)、以下のように変数を送信する必要があります。

{
"id":1
}

今回はこのidの値を可変にするためにgetInfo関数でidを受け取れるようにしています。

operationNameも省略可能です(今回は明示しています)。これは、複数の名前のついたオペレーションを含むクエリがある場合に、どのオペレーションを実行するかを指定するために使用されます。

この3つのパラメータをrequestBodyとして定義し、getInfoの中でエンドポイントにリクエストしています。

あとはこのgetInfoをawaitを用いて呼び出すことで、Promiseの中身を取り出すことができます。
今回は受け取った中身の加工部分の処理は特に記述していませんが、あとは好きなように調理するだけです。

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?