Skip to main content

Command Palette

Search for a command to run...

“AWS API Gateway & Lambda: From Beginner to Expert"

Updated
•16 min read•View as Markdown
“AWS API Gateway & Lambda: From Beginner to Expert"
S
My name is Sandhya. I come from a non-tech background with six years of experience before taking a two-year career break to learn cloud computing. Today I work as an AWS Cloud Infrastructure Support Engineer — my first year in tech. Now I have a new goal: transition into AI and MLOps engineering. And it all starts with Python. This blog is my public learning diary. I will document every step — the wins, the errors, the confusion, and the breakthroughs. If you are also starting from scratch, I hope this helps you feel less alone.

What is API Gateway? Why and How?

AWS API Gateway is a fully managed service that acts like a smart receptionist for your backend. It receives requests from clients, validates and transforms them if needed, and then forwards them to your backend (like a Lambda function). It also handles scaling, security, monitoring, and versioning automatically.

Think of it as the front door to your application.

Why use API Gateway?

  • Scalability → Handles thousands of requests per second without you worrying about servers.

  • Security → Supports authentication, authorization, throttling, and access control.

  • Efficiency → Lets you run multiple API versions (dev, test, prod) easily.

  • Monitoring → Integrated with CloudWatch for metrics and logging.

  • Flexibility → You can transform requests/responses before they reach or leave your backend.

How does it work?

API Gateway acts as a reverse proxy, accepting API calls from clients and routing them to the appropriate backend serviceLambda, EC2, HTTP endpoint, or other AWS services.

Understanding API Methods

Method Description
GET Retrieves data (read-only)
POST Submits data to create resources
PUT Updates or creates a resource
DELETE Removes a resource
PATCH Applies partial updates

Tutorial: Creating Your First API with Lambda

Step 1: Create a Simple Lambda Function

In the AWS Lambda console, create a new Python function and use this code:

import json

def lambda_handler(event, context):
    name = "World"
    if event.get('queryStringParameters'):
        name = event.get('queryStringParameters').get('name', name)

    response_data = {
        "message": f"Hello ! Your Get request was received successful.",
        "status": "success"
    }

    return {
        "statusCode": 200,
        "headers": {"Content-Type": "application/json"},
        "body": json.dumps(response_data)
    }

Step 2: Create a REST API in API Gateway

  1. Go to the API Gateway Console and click Create API.

  2. Choose HTTP API, then click Build.

  3. Select New API, name it (e.g., InfraOps API), and click Create API.

  4. Leave the stage name to $default

  5. review and create.

Create Integration: An API gateway has been created, but it has not been integrated with Lambda. To begin the integration with Lambda, we must first create a route. These routes will define where you can get the Get API.

🔹 Step 2: Define a Route

  1. In your API, go to Routes -> Click Create.

  2. Choose:

    • Method: GET
  1. Click Create.

🔹 Step 3: Create Integration

  • Go to routes > Integrations -> Click Attach Integration.
  • Create and attach an integration.

  • Choose your backend: Lambda function → if you want serverless logic.

  • Select the resource (e.g., your Lambda function "name") and click create.

Test the Endpoint

Once you’ve deployed your API to API Gateway, AWS provides an Invoke URL for the stage. To test it in your browser: Copy the Invoke URL from the Stages section of your API Gateway. Paste this full URL into your browser’s address bar and hit Enter. You should see the response returned by your integration (Lambda, HTTP backend, etc.).

Here’s what’s happening under the hood when you hit your GET API Gateway endpoint:

  1. HTTP Request → You send a GET request to the API Gateway Invoke URL.

  2. API Gateway Route → The request is matched to the route you defined (GET).

  3. Integration Trigger → API Gateway invokes the backend integration you attached—in this case, your Lambda function.

  4. Lambda Execution → The Lambda runs your code, processes the request, and generates a response (JSON in your example).

  5. API Gateway Response → API Gateway takes the Lambda’s output and returns it as an HTTP response to the client (browser, curl, Postman, etc.).

Client → API Gateway → Lambda → Response → Client

Accessing an API Gateway endpoint with a browser works fine for GET requests, since they don’t require a payload. However, for methods like PUT, POST, and PATCH, you need to send a request body (payload). Because browsers aren’t designed for that, you should use tools such as Postman or curl to test and validate those API requests.

When you paste the GET API Gateway URL into Postman and send the request, Postman is acting as the client, just like your browser would. The request flows through the API Gateway, triggers your Lambda integration, and returns the JSON response back to Postman:

📊 HTTP API vs REST API (Robust Comparison)

Feature / Aspect HTTP API (General) REST API (Specific Style of HTTP)
Definition Any API exposed over HTTP protocol A structured API following REST principles
Performance ✅ Faster, lower latency ❌ Slightly slower due to added features
Cost (AWS API Gateway) ✅ Cheaper, optimized for simple workloads ❌ More expensive, feature‑rich
Simplicity ✅ Easier to set up, minimal configuration ❌ More complex, requires resource modeling
Resource Modeling ❌ Not enforced ✅ Strong resource‑based design (nouns, CRUD)
Request/Response Mapping ❌ Limited ✅ Full mapping templates supported
Security Options ✅ Native JWT/OAuth2 support ✅ API Keys, IAM, custom authorizers
Usage Plans & Quotas ❌ Not supported ✅ Supported (rate limiting, quotas)
Stage Variables ❌ Not supported ✅ Supported (environment‑specific configs)
CORS ✅ Native support ❌ Manual setup required
Custom Domains ✅ Supported ✅ Supported
Best Use Cases Lightweight microservices, internal APIs, event‑driven apps Enterprise APIs, public APIs, complex integrations
Scalability ✅ High, but limited advanced controls ✅ High, with fine‑grained traffic management
Developer Experience ✅ Quick to build and deploy ❌ More setup, but predictable and standardized

🔹 Proxy vs Non‑Proxy Integration in API Gateway

Non‑Proxy Integration

  • API Gateway can modify requests/responses before sending them to Lambda. You can use mapping templates in Integration Request and Integration Response.

  • Example: Client sends a payload.

  • { "name": "John" }

  • API Gateway adds a prefix →

  • { "name": "Prefix_John" }.

  • Lambda processes the modified payload.

  • Advantage: It gives you flexibility to transform inputs and outputs(payload) without touching Lambda.

Proxy Integration

  • API Gateway forwards the entire request as‑is to Lambda.

  • Lambda must handle parsing, validation, and response formatting.

  • Advantage: Simpler setup, full control inside Lambda.

Create a Lambda function - non-proxy-lambda-processor

import json

def lambda_handler(event, context):
    # Try to get 'name' directly from event
    name = event.get('name')

    # If not found, check query string parameters
    if not name:
        params = event.get('queryStringParameters', {})
        name = params.get('name', 'World')

    # Return response
    return {
        "statusCode": 200,
        "body": json.dumps(f"Hello, {name}!")
}
  • The event object is like a dictionary that holds all the data coming from API Gateway.

  • Inside that event, you’re looking for the key "name".

  • Whatever value is stored under that key gets assigned to the variable name.

  • So yes — the value of "name" is stored in the variable called name.

  • Later, when you return the response, you’re printing out that variable’s value.

deploy and test

Create API → In API Gateway, choose REST API and give it a name.

Create Resource → Define a resource name. Successfully created resource '/non-proxy-demo'

Create Method → Attach an HTTP method (GET, POST, PUT, DELETE) to the resource.

Successfully created method 'POST' in 'non-proxy-demo'. Redeploy your API for the update to take effect.

  • After you create a method (like POST), API Gateway shows the full request flow between client → API Gateway → Lambda → response.

  • In the Method Request, you can configure things like headers, query string parameters, and request validation.

  • Example: You add a URL query string parameters called "name" (e.g., ?name=sandhya) and mark it as required.

  • Once validated, the request goes to Lambda, which processes the payload and returns the response.

  • Successfully edited method request for ‘POST’. Redeploy your API for the update to take effect.

Integration request

Click Edit to configure request details.

Add Mapping Template

  • Set Content-Type to application/json.

  • Add the template to transform the request before it reaches Lambda.

Use Template to Modify Request Body

Example (for query string parameter ?name=sandhya):

{ 
"name": "prefix_${input.params('name')}" 
}
  • Successfully updated method request settings for 'POST' in 'non-proxy-demo'. Redeploy your API for the update to take effect.

This ensures Lambda receives:

{ "name": "prefix_sandhya" }

Test Before Deploy

  • Use the built‑in Test option in API Gateway.

  • Pass query string like ?name=sandhya.

  • Confirm the response shows the prefix added.

    Integration Request → Mapping Template → Modify payload → Lambda processes modified input.

    What’s happening step by step

  • Client request → /non-proxy-demo?name=sandhya

  • Method Request → validates the query string parameter name.

  • Integration Request → mapping template transforms it into:

{ "name": "prefix_sandhya" }

Lambda execution → reads the name value and returns:

{"statusCode": 200, "body": "\"Hello, prefix_sandhya!\""}
  1. API Gateway response → sends the JSON back to the client.

Deploy API

  • Choose a stage (e.g., dev, test, prod).

  • Deploy the API to generate the Invoke URL.

Test with Postman

  • Open Postman → create a new request.

  • Select POST as the method.

  • Copy the full Invoke URL from your deployed stage (e.g., https://<api-id>.execute-api.<region>.amazonaws.com/dev/non-proxy-demo).

this is the non‑proxy integration flow in API Gateway:

Create a Method

  • You added a POST method to your resource /non-proxy-demo.

Method Request

  • You defined a query string parameter name (e.g., ?name=sandhya) and marked it required.

  • You added a request validator to check inputs.

Integration Request

  • You linked the method to your Lambda function.

  • You added a mapping template to transform the request before Lambda sees it. {"name": "prefix_${input.params('name')}"}

This means if the client sends ?name=sandhya, Lambda receives: { "name": "prefix_sandhya" }

  • Tested the request : You ran a test and confirmed Lambda responded with "Hello, prefix_sandhya!".

  • Deployed to a stage (dev), copied the full Invoke URL, and tested with Postman.

  • You got the expected response back from Lambda. {"statusCode":200,"body":"Hello, prefix_sandhya!"}

what you did with the Integration Request and the mapping template is essentially pre‑processing the request before it ever reaches Lambda.

Here’s the flow in simple terms:

  • Client sends request → /non-proxy-demo?name=sandhya

  • Integration Request mapping template → intercepts that request and modifies it (adds "prefix_" to the name).

  • Lambda receives modified payload → { "name": "prefix_sandhya" }

  • Lambda processes → returns "Hello, prefix_sandhya!"

So yes — the mapping template is where you can add, remove, or transform data before Lambda sees it. That’s the power of non‑proxy integration: you don’t just forward the raw request, you can reshape it to fit exactly what your backend expects.

👉 In short: Method Request validates → Integration Request transforms → Lambda executes.

Clear takeaway

  • API Gateway = front door to your backend.

  • Non‑proxy integration lets you control and transform requests/responses before they hit Lambda.

  • You successfully built, tested, and deployed an API with a dev stage, and confirmed it works via Postman.

Integration Response mapping template in a non‑proxy API Gateway method:

🔹 Step 1: Open Your API

  • Go to the API Gateway console.

  • Select your non‑proxy API (the one you created earlier).

  • Click on the POST method under your resource.

🔹 Step 2: Go to Integration Response

🔹 Step 3: Add a Response Mapping Template

  • Edit the Integration Response

  • Click Add Mapping Template.

  • Enter application/json as the content type.

  • Paste a simple mapping template, for example:

{ "message": \(input.json('\).body') }

🔹 Step 4: Save and Deploy

  • Save the template.

🔹 Step 5: Deploy the API

  1. In the API Gateway console, click Actions → Deploy API.

  2. Select your existing stage (e.g., dev).

  3. Click Deploy.

🔹 Step 6: Test the Invoke URL

Now call your endpoint from Postman or curl:

Console Test → instant check, no redeploy needed.

Now lets see the difference between Integration Request and Integration Response

🔹 Flow with your Lambda

Your Lambda looks like this:

So Lambda always returns a JSON object with a body string that says "Hello, {name}!".

🔹 Integration Request (before Lambda)

  • Purpose: Change what Lambda receives.

  • Example: Client calls:

POST /non-proxy-demo?name=sandhya

Request mapping template modifies it:

{ "name": "prefix_sandhya" }
  • Lambda receives name="prefix_sandhya".
{
  "statusCode": 200,
  "body": "\"Hello, prefix_sandhya!\""
}

🔹 Integration Response (after Lambda)

  • Purpose: Change what the client sees.

  • Lambda output was:

{
  "statusCode": 200,
  "body": "\"Hello, prefix_sandy!\""
}
# (notice the extra quotes because of json.dumps in your Lambda code).
  • Response mapping template added RESP_prefix_ in front:

Client finally sees:

  • Integration Request is where you added prefix_ before Lambda runs.

  • Integration Response is where you added RESP_prefix_ after Lambda runs.

🔹 Proxy integration

  • API Gateway forwards the request directly to Lambda and returns Lambda’s response directly to the client.

  • No mapping templates are available.

  • If you want to change the response (e.g., add a prefix/suffix, wrap into { "message": ... }You must write that logic in the Lambda function itself.

🔹 Steps to create a Proxy API in API Gateway

Create a Lambda function

import json

def lambda_handler(event, context):
    name = event.get('name')

    if not name:
        params = event.get('queryStringParameters', {})
        name = params.get ('name', 'World')

    return {
       "statusCode": 200,
       "body": f"Hello, {name}!"
    }
  1. Create a REST API

    • In API Gateway, choose Create API → REST API → New API.

    • Give it a name (e.g., ProxyDemoAPI).

  2. Create a Resource

    • Under your API, create a new resource (e.g., /non-proxy-demo).

    • This is the path your clients will call.

  3. Create a Method (POST)

    • On the resource, add a method → choose POST.

    • Select Lambda Function as the integration type.

    • Enable Lambda Proxy Integration.

    • Pick the Lambda function you created earlier and create.

Edit Method Request

Request validator -> Choose Validatebody, query string parameters, and headers

URL query string parameters:

  • You add a query string parameter called name.

  • Check “Required.” (Marking a parameter as Required means API Gateway will reject the request if that parameter is missing.)

  • Now, if a client calls /proxy-api-demo without ?name=sandhya, API Gateway will return a 400 Bad Request before Lambda is even invoked.

In Proxy integration, Integration Request mapping parameters are not available because the API request is passed directly to Lambda

Console test

Deploy the API

  • Create a new stage (e.g., dev).

  • Deploy the API to that stage.

Test the Invoke URL

Now call your endpoint from Postman or curl:

With proxy integration, API Gateway sends the whole request (headers, query string, body) straight to Lambda, and whatever Lambda returns goes straight back to the client.

VALIDATORS: Request, Body, Query string

In API Gateway, validators are the feature that let you check incoming requests before they ever reach your Lambda.

  • You can define a model (using JSON Schema) that describes the expected structure of the request body — for example, requiring name as a string, email in proper format, and mobile as a number.

  • Then you attach a validator to your method. The validator enforces that the request body matches the model and that required query string parameters or headers are present.

  • If the request doesn’t match (e.g., email is missing or mobile is not numeric), API Gateway rejects it with a 400 Bad Request automatically.

  • Only valid requests are forwarded to your Lambda or backend service, saving you from writing extra validation code inside Lambda.

validators make sure the request body, query parameters, and headers are in the right format before Lambda sees them.

User → Request Body → Model → JSON Schema → API Gateway → Lambda
  • User sends the same request

  • This time a Model is attached to the API Gateway

  • The Model checks the request against the JSON Schema which defines:

    • name must be a string with minLength 1

    • email must be a valid email format

    • mobile-number must be an integer between 100000000 and 9999999999

  • If request matches the schema → passes through to Lambda ✅

  • If request fails the schema → API Gateway rejects it with 400 Bad Request ❌

Top flow = no rules, everything passes. Bottom flow = Model acts as a gatekeeper, only valid requests reach Lambda.

Steps to implement a request validator in API Gateway

Create a Lambda

import json

def lambda_handler(event, context):
    # Parse the incoming request body
    body = json.loads(event.get('body', '{}'))

    return {
        "statusCode": 200,
        "body": f"Request Payload = {body}!"
    }
  1. Create REST API → add a resource → create a method (e.g., POST).

  2. In the left sidebar, go to Models → Create.

    • Name: DemoRequestValidator

    • Content type: application/json

    • Add your JSON Schema (e.g., requiring name, email, mobile).

    {
      "$schema": "http://json-schema.org/draft-04/schema#",
      "title": "RequestModel",
      "type": "object",
      "required": ["name", "email", "mobile-number"],
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1
        },
    
        "email": {
          "type": "string",
          "format": "email"
        },
    
        "mobile-number": {
          "type": "integer",
          "minimum": 100000000,
          "maximum": 9999999999
        }
      },
    
      "additionalProperties": false
    }
    
    • Save.
  3. Go to Edit Method Request for your POST method.

    • Under Request Validator, choose Validate body
  4. In Request Body, set:

    • Content type: application/json

    • Model: DemoRequestValidator

Edit integration request

Check Lambda proxy integration and select the lambda function you created" "

  1. Save and Deploy API to a stage.

  2. Copy the Invoke URL and paste it into Postman. In Body, choose raw and paste the JSON above. Click send.

Let's test if it works as intended

Test 1 — Invalid email (removed @) email: "sandhyaabc.com" (not a valid email format)

Test 12— Extra digits in mobile number mobile-number: 12345678901 1(11 digits — exceeds maximum)

THAT'S THE VALIDATOR WORKING PERFECTLY! 🎉

More from this blog

�

💻 Sandhya Babu's DevOps Journey 🚀

46 posts

🌟 Welcome to My Blog! 🌟

Dive into my DevOps and Cloud Computing journey with tutorials and insights on Kubernetes, CI/CD, Docker, and more. Join me in exploring tech together!