Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

An HTTP front door for a function

After this lesson: I can write the answer an API gateway expects from a function.

60 min lessonNo commands

A web address that runs a function

An API gateway is the front door that turns a web request into a call to a Lambda function, with no server of your own. It is how most small cloud apps answer the web, and the function must reply in the exact shape the gateway expects.

A shop wants a web address, /orders/ana, that answers with Ana's orders. The function must answer properly even when the request is wrong.

By the end of this lesson

Note

I can write the answer an API gateway expects from a function.

Key words

WordWhat it meansExample
Requestwhat a caller sends to a web address
Responsewhat the function sends back
Status codea number saying how the request went404
Headera named detail sent beside the bodycontent-type
Bodythe main text of a request or response

The cells students fill in are left blank in this preview.

A request comes in, a response goes out

The gateway turns the web request into an event. The method, such as GET, is at requestContext.http.method. The path is rawPath.

The function returns a dictionary with three parts: statusCode, headers and body. The body must be a string, so use json.dumps. These are the documented shapes, not output from a stack of yours.

Run it: the smallest front door

Code: python
import json

# The documented shape of an HTTP API request, cut down.
event = {
    "requestContext": {"http": {"method": "GET"}},
    "rawPath": "/orders/ana",
    "headers": {"accept": "application/json"},
}


def handler(event, context):
    method = event["requestContext"]["http"]["method"]
    path = event["rawPath"]
    data = {"you_asked": method + " " + path}
    return {"statusCode": 200,
            "headers": {"content-type": "application/json"},
            "body": json.dumps(data)}


answer = handler(event, None)
print(answer["statusCode"])
print(answer["body"])
print(type(answer["body"]).__name__)
# Change "GET" to "POST" in the event and run again.

A status code says who got it wrong

A 2 at the start, such as 200 or 201, means success. A 4, such as 400 or 404, means the caller asked for something wrong. A 5 means the function itself failed.

A wrong request is not a crash. Return a 4 with a short error in the body. A function that raises an error gives the caller a vague 5, and tells them nothing they can fix.

Worked example: the codes this lesson uses

CodeMeaningUse it when
200OKYou found and returned the data
201CreatedA new order was stored
400Bad requestA field is missing or wrong, or the body is not valid JSON
404Not foundNo such path or no such order
405Method not allowedThe path exists, the method does not
415Unsupported media typeThe content-type is not application/json

The cells students fill in are left blank in this preview.

A common mistake

Warning

Many people let the function crash on bad input. The caller then gets a vague server error. Check the input first. When the caller is at fault, return a 4 and say what to fix. Keep a 5 for faults that are yours.

Run it: an error as a response

Code: python
import json


def reply(status, data):
    return {"statusCode": status,
            "headers": {"content-type": "application/json"},
            "body": json.dumps(data)}


def handler(event, context):
    # A missing key is the caller's mistake, so answer 400, do not crash.
    if "queryStringParameters" not in event:
        return reply(400, {"error": "add ?customer=name"})
    name = event["queryStringParameters"]["customer"]
    return reply(200, {"hello": name})


print(handler({"queryStringParameters": {"customer": "ana"}}, None)["statusCode"])
print(handler({}, None)["statusCode"])
print(handler({}, None)["body"])
# Add a third line that calls handler with {"queryStringParameters": {}}. What happens?

Read the request carefully

Not every key is always there. With no query string, queryStringParameters is left out of the event. Check with in before you read it.

The body arrives as text. If isBase64Encoded is true, the text is encoded and you decode it first. Header names arrive in lower case, so look for content-type.

Run it: read a base64 body

Code: python
import json
import base64

event = {
    "body": base64.b64encode(b'{"item": "tea"}').decode("utf-8"),
    "isBase64Encoded": True,
}

text = event["body"]
print(text)
if event["isBase64Encoded"] is True:
    text = base64.b64decode(text).decode("utf-8")
print(text)
print(json.loads(text)["item"])
# Set isBase64Encoded to False and run again. What goes wrong?

What this module did not teach

Note

Everything here ran offline in Python, over answers shaped like the real ones. You did not deploy anything, sign in to a real account or see a bill. You did not meet the costs of keeping a service running. Those are the next steps, and they are best learnt with someone who can check your account settings.

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.