Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
cdk.out
*.js
*.d.ts
96 changes: 96 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
# Amazon Bedrock Mantle Responses API with AWS Lambda (OpenAI SDK Compatible)

This pattern deploys an API Gateway REST API backed by an AWS Lambda function that calls Amazon Bedrock via the OpenAI-compatible Responses API (bedrock-mantle endpoint) using the standard OpenAI Python SDK.

Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-bedrock-mantle-responses-api-cdk

Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example.

## Requirements

- [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources.
- [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured
- [Node.js 20+](https://nodejs.org/en/download/) installed
- [AWS CDK v2](https://docs.aws.amazon.com/cdk/v2/guide/getting_started.html) installed (`npm install -g aws-cdk`)
- [Python 3.12](https://www.python.org/downloads/) installed (for Lambda bundling)
- [Docker](https://docs.docker.com/get-docker/) installed (for CDK asset bundling)
- A Bedrock API key (see below)

## Generating a Bedrock API Key

1. Open the [Amazon Bedrock console](https://console.aws.amazon.com/bedrock/)
2. Navigate to **API keys** in the left navigation
3. Click **Create API key**
4. Copy the generated key — you will pass it as a parameter during deployment

## Deployment Instructions

1. Create a new directory, navigate to the directory, and clone the repository:
```bash
git clone https://github.com/aws-samples/serverless-patterns
cd serverless-patterns/lambda-bedrock-mantle-responses-api-cdk
```

2. Install dependencies:
```bash
npm install
```

3. Bootstrap CDK (if not already done):
```bash
cdk bootstrap
```

4. Deploy the stack, providing your Bedrock API key:
```bash
cdk deploy --parameters BedrockApiKey=YOUR_BEDROCK_API_KEY
```

5. Note the `ApiEndpoint` output URL.

## How it works

- API Gateway receives a POST request at `/ask`
- Lambda is invoked with the request body
- The Lambda function uses the OpenAI Python SDK configured to point to `https://bedrock-mantle.<region>.api.aws/v1`
- Authentication is handled via the Bedrock API key (no `bedrock:InvokeModel` IAM permission needed)
- The Responses API response is returned to the caller

## Available Regions

The bedrock-mantle endpoint is available in: `us-east-1`, `us-east-2`, `us-west-2`, and other regions.

## Testing

After deployment, send a POST request to the API endpoint:

```bash
curl -X POST https://<api-id>.execute-api.<region>.amazonaws.com/prod/ask \
-H "Content-Type: application/json" \
-d '{"prompt": "What is Amazon Bedrock?", "model": "us.anthropic.claude-sonnet-4-20250514-v1:0"}'
```

Expected response:
```json
{
"response": "Amazon Bedrock is a fully managed service...",
"model": "us.anthropic.claude-sonnet-4-20250514-v1:0",
"id": "resp_..."
}
```

## Cleanup

To delete the stack and all associated resources:

```bash
cdk destroy
```

> **Warning:** This will permanently delete all resources created by this stack. The removal policy is set to DESTROY.

## Architecture

```
Client -> API Gateway (POST /ask) -> Lambda (Python 3.12 + OpenAI SDK) -> Bedrock Mantle Responses API
```
16 changes: 16 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/bin/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { LambdaBedrockMantleStack } from '../lib/stack';

if (!process.env.CDK_DEFAULT_ACCOUNT) {
throw new Error('CDK_DEFAULT_ACCOUNT environment variable is required. Run: aws sts get-caller-identity');
}

const app = new cdk.App();
new LambdaBedrockMantleStack(app, 'LambdaBedrockMantleResponsesApiStack', {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: process.env.CDK_DEFAULT_REGION || 'us-east-1',
},
});
3 changes: 3 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"app": "npx ts-node --prefer-ts-exts bin/app.ts"
}
46 changes: 46 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/example-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"title": "Amazon Bedrock Mantle Responses API with AWS Lambda (OpenAI SDK Compatible)",
"description": "Call Amazon Bedrock via the OpenAI-compatible Responses API from AWS Lambda using the standard OpenAI Python SDK.",
"language": "TypeScript",
"level": "200",
"framework": "AWS CDK",
"introBox": {
"headline": "How it works",
"text": [
"This pattern deploys an API Gateway REST API that triggers a Lambda function.",
"The Lambda function uses the OpenAI Python SDK to call Amazon Bedrock via the bedrock-mantle Responses API endpoint.",
"Authentication uses a Bedrock API key passed as a CloudFormation parameter at deploy time."
]
},
"gitHub": {
"template": {
"repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-bedrock-mantle-responses-api-cdk",
"templateURL": "serverless-patterns/lambda-bedrock-mantle-responses-api-cdk",
"projectFolder": "lambda-bedrock-mantle-responses-api-cdk"
}
},
"resources": {
"bullets": [
{
"text": "Amazon Bedrock Documentation",
"link": "https://docs.aws.amazon.com/bedrock/latest/userguide/"
},
{
"text": "OpenAI Python SDK",
"link": "https://github.com/openai/openai-python"
}
]
},
"deploy": {
"text": ["cdk deploy --parameters BedrockApiKey=YOUR_API_KEY"]
},
"cleanup": {
"text": ["<code>cdk destroy</code>"]
},
"authors": [
{
"name": "Nithin Chandran R",
"bio": "Cloud Engineer at AWS"
}
]
}
50 changes: 50 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/lib/stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import * as cdk from 'aws-cdk-lib';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import { Construct } from 'constructs';

export class LambdaBedrockMantleStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);

const apiKey = new cdk.CfnParameter(this, 'BedrockApiKey', {
type: 'String',
description: 'Bedrock API key generated from the AWS console',
noEcho: true,
});

const fn = new lambda.Function(this, 'ResponsesApiFn', {
runtime: lambda.Runtime.PYTHON_3_12,
handler: 'index.handler',
code: lambda.Code.fromAsset('src', {
bundling: {
image: lambda.Runtime.PYTHON_3_12.bundlingImage,
command: [
'bash', '-c',
'pip install -r requirements.txt -t /asset-output && cp -au . /asset-output',
],
},
}),
timeout: cdk.Duration.seconds(60),
memorySize: 256,
environment: {
OPENAI_BASE_URL: `https://bedrock-mantle.${this.region}.api.aws/v1`,
OPENAI_API_KEY: apiKey.valueAsString,
},
});

const api = new apigateway.RestApi(this, 'ResponsesApi', {
restApiName: 'Bedrock Mantle Responses API',
});

api.root.addResource('ask').addMethod(
'POST',
new apigateway.LambdaIntegration(fn),
);

new cdk.CfnOutput(this, 'ApiEndpoint', {
value: api.url + 'ask',
description: 'API Gateway endpoint URL',
});
}
}
21 changes: 21 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "lambda-bedrock-mantle-responses-api-cdk",
"version": "1.0.0",
"bin": {
"app": "bin/app.ts"
},
"scripts": {
"build": "tsc",
"cdk": "cdk"
},
"dependencies": {
"aws-cdk-lib": "^2.170.0",
"constructs": "^10.0.0",
"source-map-support": "^0.5.21"
},
"devDependencies": {
"typescript": "~5.4.0",
"ts-node": "^10.9.0",
"@types/node": "^20.0.0"
}
}
33 changes: 33 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/src/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os
import json
from openai import OpenAI

client = OpenAI(
base_url=os.environ['OPENAI_BASE_URL'],
api_key=os.environ['OPENAI_API_KEY'],
)


def handler(event, context):
body = json.loads(event.get('body', '{}'))
prompt = body.get('prompt', 'What is Amazon Bedrock?')
model = body.get('model', 'openai.gpt-oss-120b')

try:
response = client.responses.create(
model=model,
input=[{'role': 'user', 'content': prompt}],
)
return {
'statusCode': 200,
'body': json.dumps({
'response': response.output_text,
'model': model,
'id': response.id,
}),
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({'error': str(e)}),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
openai
18 changes: 18 additions & 0 deletions lambda-bedrock-mantle-responses-api-cdk/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"lib": ["es2020"],
"declaration": true,
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"outDir": "./cdk.out",
"skipLibCheck": true
},
"exclude": ["node_modules", "cdk.out"]
}