AWS

TypeScriptで書いたLambdaをAPI GatewayとInvokeどちらからでも使えるようにする

「なんのこっちゃら」という方や「えぇ・・・」って思われる方もいるかも知れませんが、今の自分には必要だったのです。 やりたいこと 1つのLambdaをAPI Gateway経由と直接Invokeどちらからも動せる実装。 問 […]

広告ここから
広告ここまで

「なんのこっちゃら」という方や「えぇ・・・」って思われる方もいるかも知れませんが、今の自分には必要だったのです。

やりたいこと

1つのLambdaをAPI Gateway経由と直接Invokeどちらからも動せる実装。

問題

TypeScriptでeventの型をどうするか。

対応

型のあるAPI Gateway Proxy EventにInvoke側を寄せていきます。

コード

まずInvokeしてもAPI Gatewayからコールしても同じ型のイベントオブジェクトを手に入れられるようにします。

import { APIGatewayProxyEvent } from 'aws-lambda';

export interface PayloadType {
  method: 'GET' | 'OPTION' | 'POST' | 'DELETE' | 'PUT',
  path: string,
  body?: any,
  pathParameters?: {
    [name: string]: string
  },
  queryStringParameters?: {
    [name: string]: string
  },
  resource: string
}

export const generateEvent = (payload: PayloadType): APIGatewayProxyEvent => {
  const {
    method,
    body,
    path,
    pathParameters,
    queryStringParameters,
    resource
  } = payload
  const event: APIGatewayProxyEvent = {
    body: body ? JSON.stringify(body) : null,
    headers: {},
    multiValueHeaders: {},
    httpMethod: method,
    isBase64Encoded: false,
    path,
    pathParameters: pathParameters || null,
    queryStringParameters: queryStringParameters || null,
    multiValueQueryStringParameters: {},
    stageVariables: {},
    requestContext: {
      accountId: 'accountId',
      apiId: 'apiId',
      connectedAt: 9999,
      httpMethod: method,
      identity: {
        accessKey: null,
        accountId: null,
        apiKey: null,
        apiKeyId: null,
        caller: null,
        cognitoAuthenticationProvider: null,
        cognitoAuthenticationType: null,
        cognitoIdentityId: null,
        cognitoIdentityPoolId: null,
        sourceIp: 'sourcecIp',
        user: null,
        userAgent: null,
        userArn: null
      },
      path,
      stage: 'stage',
      requestId: 'requestId',
      requestTimeEpoch: 9999,
      resourceId: 'resourceId',
      resourcePath: resource
    },
    resource
  }
  return event
}

export const isDirectInvoke = <T extends PayloadType>(event: any): event is T => {
  return event.httpMethod === undefined
}

export const getAPIProxyEvent = <T extends PayloadType>(event: APIGatewayProxyEvent | T): APIGatewayProxyEvent => {
  if (isDirectInvoke<T>(event)) return generateEvent(event)
  return event
}

これをハンドラー側でよびましょう。

import { APIGatewayProxyHandler, APIGatewayProxyEvent } from 'aws-lambda';
import { generateEvent, PayloadType, getAPIProxyEvent } from './apiProxyHelpers'

interface NewPayload extends PayloadType {
  body: {}
}

export const handler:APIGatewayProxyHandler = async (proxyEvent: APIGatewayProxyEvent | NewPayload) => {
  const event = getAPIProxyEvent<CFPayload>(proxyEvent)
  return {
    statusCode: 200,
    body: JSON.stringify({event})
  }
}

これでhandler内ではeventはAPIGatewayProxyEventとして取り扱えますし、直接InvokeしてもAPI Gateway側を想定した実装のまま使えます。

実際のところ

asとかanyとか使っちゃえばいい気はします。好みとどれくらい頑張ろうかというモチベーションに相談してください。

ブックマークや限定記事(予定)など

WP Kyotoサポーター募集中

WordPressやフロントエンドアプリのホスティング、Algolia・AWSなどのサービス利用料を支援する「WP Kyotoサポーター」を募集しています。
月額または年額の有料プランを契約すると、ブックマーク機能などのサポーター限定機能がご利用いただけます。

14日間のトライアルも用意しておりますので、「このサイトよく見るな」という方はぜひご検討ください。

広告ここから
広告ここまで

Related Category posts