Lambda Function URLsで実現するサーバーレスAPIの新しい選択肢と実装戦略
Function URLsが生まれた背景と本質的な価値
AWS Lambdaでシンプルなエンドポイントを作りたいとき、これまでは必ずAPI Gatewayを経由する必要がありました。しかし実際の開発現場では、Webhookの受信口や社内ツールのバックエンドなど、API Gatewayの豊富な機能が不要なケースも多く存在します。
Lambda Function URLsは、こうしたニーズに応える形で2022年4月にリリースされました。この機能により、Lambda関数に対してhttps://<url-id>.lambda-url.<region>.on.aws
という形式の固定URLが自動発行され、追加料金なしでHTTPSエンドポイントを持つことができるようになりました。
私がこの機能を初めて触った時の印象は、「やっと来たか」というものでした。多くのケースでAPI Gatewayは過剰であり、Function URLsの登場により、アーキテクチャの選択肢が大きく広がったと感じています。
![AuthType [None] を使用する場合でも、関数のリソースベースのポリシーではパブリックアクセスを明示的に許可する必要があることに注意](https://images.microcms-assets.io/assets/eda1944e83624e11a2b9bcc79bba1c89/b888b29b883046d9b60326b1fedb4864/lambda-url-create-function-1024x470.png)

Function URLsの技術的特性
認証方式とセキュリティモデル
Function URLsでは、2つの認証方式が選択できます。
AWSドキュメントによると、認証方式の選択肢は以下の通りです。
AWS_IAM
:SigV4署名による認証が必須となり、AWS IAMによるアクセス制御が可能NONE
:認証なしで誰でもアクセス可能(ただしリソースベースポリシーでの制御は可能)
実際のプロダクション環境では、NONE
を選択する場合でも、必ず「リソースベースポリシー」や前段のCDN、WAFなどで適切なアクセス制御を行うことが重要です。完全に公開されたエンドポイントは、DDoS攻撃やコスト攻撃の対象となるリスクがあります。
CORSの設定と管理
ブラウザからのアクセスを想定する場合、「CORS」(Cross-Origin Resource Sharing)の設定が必要になります。Function URLsでは、URL設定側でCORSを一括管理できるようになっています。
設定可能な主要パラメータは以下の通りです。
- AllowOriginsで許可するオリジンを指定
- AllowMethodsで許可するHTTPメソッドを定義
- AllowHeadersでカスタムヘッダーの許可を設定
- MaxAgeでプリフライトリクエストのキャッシュ時間を制御
引用:Creating and managing Lambda function URLs - AWS Lambda Function URLのCORSは、URL設定側で一括管理可能です。プリフライトではURL設定が優先され、二重設定は重複ヘッダー警告の原因になるため、URL側に集約することを推奨します。
スロットリングとスケーリング戦略
Function URLsのスロットリングは、「予約済み同時実行」(Reserved Concurrency)によって制御されます。これは非常に重要なポイントで、最大RPSは予約値の約10倍という目安があります。
表 Function URLsのスロットリング設定と期待値
予約済み同時実行 | 想定最大RPS | 用途例 |
---|---|---|
10 | 約100 | 開発・テスト環境 |
100 | 約1,000 | 中規模Webhook |
500 | 約5,000 | 本番環境API |
1,000 | 約10,000 | 高負荷サービス |
この表は、一般的な目安を示したものです。実際のRPSは、関数の実行時間やメモリサイズ、処理内容によって変動するため、必ず実環境でのテストを行い、適切な値を設定する必要があります。
API Gatewayとの使い分け戦略
Function URLsが適している場面
私の経験上、Function URLsが特に効果を発揮するのは以下のようなケースです。
シンプルなWebhookレシーバーの実装では、Function URLsは最適な選択肢となります。GitHubやStripeなどの外部サービスからのWebhookを受け取る際、API Gatewayの豊富な機能は不要であることがほとんどです。
// Node.js でのウェブフックを処理するシンプルな関数コード
// 引用 : https://aws.amazon.com/jp/blogs/news/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-
function-microservices/
exports.handler = async (event) => {
// (オプション) メソッドとクエリ文字列を取得
const method = event.requestContext.http.method;
const queryParam = event.queryStringParameters.myCustomParameter;
console.log(`Received ${method} request with ${queryParam}`)
// 署名とペイロードを取得
const webhookSignature = event.headers.SignatureHeader;
const webhookPayload = JSON.parse(event.body);
try {
validateSignature(webhookSignature); // 署名が無効である場合はスロー
handleEvent(webhookPayload); // 処理エラーの場合はスロー
} catch (error) {
console.error(error)
return {
statusCode: 400,
body: `Cannot process event: ${error}`,
}
}
return {
statusCode: 200, // デフォルト値
body: JSON.stringify({
received: true,
}),
};
};
社内ツールやマイクロサービスのバックエンドとして使用する場合も、Function URLsで十分なケースが多いです。特に、認証をIAMで管理できる環境では、AWS_IAM
認証を使用することで、シンプルかつ安全な実装が可能になります。
API Gatewayを選ぶべき場面
一方で、以下のような要件がある場合は、API Gatewayを選択する方が適切です。
カスタムドメインが必須の場合、Function URLsは標準ドメイン形式しか提供していないため、API GatewayかCloudFrontの併用が必要になります。また、リクエスト/レスポンスの変換やバリデーション、使用プランによるレート制限、APIキーによる認証など、高度なAPI管理機能が必要な場合も、API Gatewayの選択が妥当です。
表 Function URLsとAPI Gatewayの機能比較
機能 | Function URLs | API Gateway |
---|---|---|
追加料金 | なし | あり |
カスタムドメイン | 非対応 | 対応 |
リクエスト変換 | 非対応 | 対応 |
使用プラン | 非対応 | 対応 |
WAF統合 | CloudFront経由 | 直接統合可能 |
レスポンスキャッシュ | 非対応 | 対応 |
この比較表から分かるように、Function URLsはシンプルさと低コストを重視した設計になっています。複雑なAPI管理が必要な場合は、API Gatewayの採用を検討すべきです。
実装例:TypeScriptでのFunction URLs活用
基本的な実装パターン
Function URLsを使用したLambda関数の実装例を見てみます。以下は、TypeScriptでシンプルなAPIエンドポイントを実装する例です。
import { APIGatewayProxyEventV2, APIGatewayProxyResultV2 } from 'aws-lambda';
interface RequestBody {
name: string;
email: string;
}
export const handler = async (
event: APIGatewayProxyEventV2
): Promise<APIGatewayProxyResultV2> => {
// リクエストメソッドの確認
if (event.requestContext.http.method !== 'POST') {
return {
statusCode: 405,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ error: 'Method Not Allowed' }),
};
}
try {
// リクエストボディのパース
const body: RequestBody = JSON.parse(event.body || '{}');
// バリデーション
if (!body.name || !body.email) {
return {
statusCode: 400,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ error: 'Invalid request body' }),
};
}
// ビジネスロジックの実行
const result = await processUserData(body);
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: 'Success',
data: result
}),
};
} catch (error) {
console.error('Error processing request:', error);
return {
statusCode: 500,
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ error: 'Internal Server Error' }),
};
}
};
async function processUserData(data: RequestBody): Promise<object> {
// ビジネスロジックの実装
return {
id: Math.random().toString(36).substring(7),
...data,
createdAt: new Date().toISOString(),
};
}
このコードで注目すべきは、Function URLsがAPI Gateway Payload v2.0形式のイベントを使用する点です。event.requestContext.http.method
でHTTPメソッドを取得し、event.body
でリクエストボディにアクセスできます。
レスポンスストリーミングの実装
大量のデータを返す場合や、生成系AIの出力を逐次返却したい場合は、「レスポンスストリーミング」が有効です。
import { streamifyResponse } from 'lambda-stream';
import { Readable } from 'stream';
export const handler = streamifyResponse(async (event, responseStream, context) => {
const pipeline = new Readable({
async read() {
// データを段階的に生成
for (let i = 0; i < 10; i++) {
const chunk = JSON.stringify({
index: i,
timestamp: Date.now()
}) + '\\\\n';
this.push(chunk);
// 処理の間隔を設ける(実際の処理を模擬)
await new Promise(resolve => setTimeout(resolve, 100));
}
// ストリームの終了
this.push(null);
}
});
// レスポンスヘッダーの設定
responseStream.setContentType('application/x-ndjson');
// パイプラインの実行
pipeline.pipe(responseStream);
});
レスポンスストリーミングを使用することで、TTFB(Time To First Byte)を大幅に短縮できます。特に、大規模なデータセットを扱う場合や、リアルタイムに近い応答が求められる場合に威力を発揮します。
運用における実践的なTips
監視とアラートの設定
Function URLsは、CloudWatchに専用のメトリクスを自動送信します。主要なメトリクスとその活用方法を整理すると以下のようになります。
UrlRequestCount
は総リクエスト数を示し、トラフィック傾向の把握に使用します。Url4xxCount
とUrl5xxCount
はそれぞれクライアントエラーとサーバーエラーの発生状況を監視するために重要です。これらのメトリクスを基に、適切なアラートを設定することで、問題の早期発見が可能になります。
セキュリティのベストプラクティス
Function URLsを本番環境で使用する際の、セキュリティに関する私の推奨事項は以下の通りです。
まず、公開が必要ない限りAWS_IAM
認証を選択することです。これにより、AWS IAMの強力なアクセス制御メカニズムを活用できます。NONE
認証を使用する場合でも、必ずリソースベースポリシーで最小限のアクセス許可を設定し、可能であればCloudFrontやWAFを前段に配置して、DDoS攻撃や不正アクセスから保護します。
コスト最適化の観点
Function URLsは追加料金が発生しないという大きなメリットがあります。API Gatewayと比較した場合のコスト削減効果を見積もってみます。
月間100万リクエストを処理する場合、API Gateway(REST API)では約3.5ドルの料金が発生しますが、Function URLsではこの費用がゼロになります。年間で考えると42ドルの削減となり、複数のエンドポイントを運用している場合は、さらに大きな効果が期待できます。
Infrastructure as Codeでの実装
CloudFormationでの定義
Function URLsをCloudFormationで定義する際の実装例を示します。
// CDK v2での実装例
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as nodejs from 'aws-cdk-lib/aws-lambda-nodejs';
export class FunctionUrlStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// Lambda関数の作成
const fn = new nodejs.NodejsFunction(this, 'MyFunction', {
entry: 'src/handler.ts',
handler: 'handler',
runtime: lambda.Runtime.NODEJS_20_X,
timeout: cdk.Duration.seconds(30),
memorySize: 512,
reservedConcurrentExecutions: 100, // スロットリング設定
});
// Function URLの作成
const fnUrl = fn.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.AWS_IAM,
cors: {
allowedOrigins: ['<https://example.com>'],
allowedMethods: [lambda.HttpMethod.GET, lambda.HttpMethod.POST],
allowedHeaders: ['Content-Type', 'Authorization'],
maxAge: cdk.Duration.hours(24),
},
});
// URL出力
new cdk.CfnOutput(this, 'FunctionUrl', {
value: fnUrl.url,
description: 'The URL of the Lambda function',
});
}
}
このCDKコードでは、予約済み同時実行を100に設定し、CORS設定も含めてFunction URLを構成しています。実際のプロジェクトでは、環境変数や設定値を外部化し、環境ごとに適切な値を設定することが重要です。
私の考察
Function URLsは、サーバーレスアーキテクチャにおける重要な進化だと考えています。API Gatewayという中間層を省略できることで、レイテンシの削減とコストの最適化が実現されました。
今後期待される機能拡張として、カスタムドメインのネイティブサポートやVPCエンドポイント経由でのプライベートアクセスなどが挙げられます。これらが実現されれば、Function URLsの適用範囲はさらに広がるでしょう。
また、エッジコンピューティングの文脈でも、Function URLsは重要な役割を果たす可能性があります。Lambda@Edgeとの連携や、将来的にはリージョン間レプリケーションなども視野に入ってくるかもしれません。
まとめ
Lambda Function URLsは、「シンプルさ」と「費用対効果」を重視したサーバーレスエンドポイントの実装において、最適な選択肢となりました。API Gatewayが提供する高度な機能が不要な場合、Function URLsを採用することで、アーキテクチャの複雑性を減らし、運用コストを削減できます。
実装時のポイントをまとめると以下のようになります。
- 認証方式は要件に応じて適切に選択し、セキュリティを最優先に考える
- 予約済み同時実行でスロットリングを制御し、想定外のトラフィックから保護する
- CloudWatchメトリクスを活用した監視体制を構築する
- 必要に応じてCloudFrontやWAFと組み合わせて利用する
Function URLsとAPI Gatewayは競合するものではなく、それぞれが得意とする領域があります。プロジェクトの要件を正確に把握し、適材適所で使い分けることが、効率的なサーバーレスアーキテクチャ構築の鍵となります。
私自身、複数のプロジェクトでFunction URLsを活用してきましたが、その簡潔さと実用性は有用だと感じていますが、ただし、業務システムやアプリケーションにおける大規模なAPIの管理には不向きだという事を確実に念頭に扱いましょう。
複雑な認証・認可を伴うAPIの実装は、APIGatewayあるいはAppSyncを使用するのがベターです。