こんにちは、エムスリーエンジニアリンググループ 兼 QLife エンジニアの園田 (@ryoryoryohei) です。
AWS AppSync 使ってますか? サーバーレスで GraphQL のエンドポイントを提供できる強力なサービスです。
AppSync には認証方式が現状 4 つあり、そのうちの 1 つである IAM 認証を設定した場合、GraphQL の HTTP リクエストは AWS の 署名バージョン 4 で署名 されている必要があります。
GraphQL の代表的な Ruby ライブラリである Github の graphql-client
は当然 IAM 認証には対応していないので、IAM 認証に対応させるためのアダプターライブラリを実装して公開しました。
ソースファイルは 1 ファイルで 50 ステップほどしかないという超シンプル構成です。
require 'graphql/client/http' require 'json' require 'aws-sigv4' require 'net/http' module GraphQL class Client class Aws < GraphQL::Client::HTTP def initialize(uri, **opts, &block) if block_given? super(uri, &block) else super(uri) end appsync_signer_option = opts.merge(service: 'appsync') @signer = ::Aws::Sigv4::Signer.new(appsync_signer_option) end def execute(document:, operation_name: nil, variables: {}, context: {}) request = Net::HTTP::Post.new(uri.request_uri) request['Accept'] = 'application/json' headers(context).each { |name, value| request[name] = value } request.body = build_body(document, operation_name, variables) request = sign!(request) response = connection.request(request) case response when Net::HTTPOK, Net::HTTPBadRequest JSON.parse(response.body) else { 'errors' => [{ 'message' => "#{response.code} #{response.message}" }] } end end def build_body(document, operation_name, variables) body = { 'query' => document.to_query_string } body['variables'] = variables if variables.any? body['operationName'] = operation_name if operation_name JSON.generate(body) end def sign!(request) signature = @signer.sign_request(http_method: request.method, url: uri, body: request.body) request['Host'] = signature.headers['Host'] request['X-Amz-Date'] = signature.headers['x-amz-date'] request['X-Amz-Security-Token'] = signature.headers['x-amz-security-token'] request['X-Amz-Content-Sha256']= signature.headers['x-amz-content-sha256'] request['Authorization'] = signature.headers['authorization'] request['Content-Type'] = 'application/graphql' request end end end end
GraphQL::Client::HTTP
を継承して execute
メソッドをオーバーライドしています。その中で署名を追加しているだけです。
Version 1.0.0 では
Net::HTTP
を継承したクラスを利用するようにしていたのですが、それだとwebmock
が認識してくれなかったため、execute
メソッドをオーバーライドするように変更しました。
使い方も非常に簡単です。Github の README をご覧ください。
以上、今回はこれだけです!
We are hiring
QLife では共にチーム一丸となってより良いものづくりにこだわれる仲間を募集中です! 小さいサービスが多いので新しい AWS のサービスの利用にも非常に積極的に取り組んでいます! カジュアル面談も行っていますので、興味がある方は entry@qlife.co.jp に「カジュアル面談希望」とメールをください!
エムスリーでもエンジニアを随時募集しています!共に医療 × テクノロジーの未来を切り拓いてくれる仲間を募集中です! AWS 以外にも GCP や Firebase などのクラウドも活用しています!興味がある方はカジュアル面談やTechtalkにおこしください!!