AWS Builder Center

Serverless Meets Generative AI: Build a Q&A API with AWS Lambda, API Gateway, and Amazon Bedrock

A step-by-step walkthrough of a serverless generative AI backend: how Lambda, API Gateway, and Amazon Bedrock fit together, the minimal code and IAM permissions you need, and the cost and safety details worth planning for before you ship.

Two topics keep showing up across the AWS community: serverless architectures and generative AI on Amazon Bedrock. They fit together naturally. Bedrock gives you foundation models through an API, and Lambda lets you run the glue code without managing a single server.
In this article we'll build the smallest useful version of that combination: an HTTP endpoint that receives a question, sends it to a foundation model through Amazon Bedrock, and returns the answer.

The architecture

1
Client -> API Gateway -> AWS Lambda -> Amazon Bedrock -> answer back to the client
Each piece has one job:
  • API Gateway exposes a public HTTPS endpoint and forwards requests.
  • AWS Lambda validates the input, calls Bedrock, and shapes the response.
  • Amazon Bedrock hosts the foundation models, so there are no GPUs or model servers to run.
Because every component is managed and scales on demand, an idle project costs almost nothing, and you only pay when someone actually sends a request.

Step 1: Enable model access

Before any code runs, open the Amazon Bedrock console in your chosen Region and make sure you have access to at least one foundation model. Note the model ID, because your Lambda function will need it.

Step 2: Write the Lambda function

Here is a minimal Python handler using the Bedrock Converse API, which gives you one consistent request format across different models:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import json
import boto3

bedrock = boto3.client("bedrock-runtime")
MODEL_ID = "YOUR_MODEL_ID" # the model you enabled in Step 1


def lambda_handler(event, context):
body = json.loads(event.get("body") or "{}")
question = body.get("question", "").strip()

if not question or len(question) > 1000:
return _response(400, {"error": "Send a 'question' of up to 1000 characters."})

result = bedrock.converse(
modelId=MODEL_ID,
messages=[{"role": "user", "content": [{"text": question}]}],
inferenceConfig={"maxTokens": 500, "temperature": 0.3},
)

answer = result["output"]["message"]["content"][0]["text"]
return _response(200, {"answer": answer})


def _response(status, payload):
return {
"statusCode": status,
"headers": {"Content-Type": "application/json"},
"body": json.dumps(payload),
}
Two small details matter here. Input validation stops empty or oversized prompts before they cost you money, and maxTokens puts a ceiling on how long any single response can be.

Step 3: Give the function only the permission it needs

Your Lambda execution role needs permission to invoke the model, and nothing more. Scope it to the specific model instead of using a wildcard:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["bedrock:InvokeModel"],
"Resource": "arn:aws:bedrock:YOUR_REGION::foundation-model/YOUR_MODEL_ID"
}
]
}
Least privilege is a habit worth building early. If the function is ever misused, the damage is limited to one model in one Region.

Step 4: Put API Gateway in front

Create an HTTP API, add a POST /ask route, and connect it to your Lambda function with a proxy integration. Then test it:
1
2
3
curl -X POST "https://YOUR_API_ID.execute-api.YOUR_REGION.amazonaws.com/ask" \
-H "Content-Type: application/json" \
-d '{"question": "Explain what a Lambda cold start is in two sentences."}'
If you get a JSON answer back, the whole chain works.

What to plan for before you share it

A demo that works is not the same as something safe to leave online. Keep these in mind:
  • Cost. Foundation models are billed by usage, so set a budget alert, keep maxTokens low, and consider throttling or requiring authentication on the API.
  • Timeouts. API Gateway has an integration timeout, and long generations can exceed it. Keep answers short, or look at asynchronous or streaming patterns for longer outputs.
  • Safety. Bedrock Guardrails can filter harmful or off-topic content, which matters as soon as strangers can type into your endpoint.
  • Privacy. Avoid logging full prompts and responses if users might paste sensitive information.

Where to go next

Once the basic endpoint works, there are natural upgrades:
  1. Add your own data with a knowledge base, so answers are grounded in your documents instead of only the model's general knowledge.
  2. Try agents, which let a model break a request into steps and call your APIs or Lambda functions to complete multi-step tasks.
  3. Compare Lambda with containers for heavier workloads. It's rarely containers or serverless, and many real systems use both.
The pattern we built here is small, but it is the same shape as much larger systems: a thin serverless layer, a managed model, and careful limits around cost and safety. Start small, measure, and add complexity only when you need it.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article