¿Te resulta más fácil leer con fondo crema, un tono de color, más contraste o un texto más grande? Elige tus colores y tu texto una sola vez, para todas las páginas.

Lección gratuita

Una puerta HTTP para una función

Después de esta lección: Puedo escribir la respuesta que una puerta de API espera de una función.

Lección de 60 minSin comandos

Una dirección web que ejecuta una función

Una tienda quiere una dirección web, /pedidos/lucia, que responda con los pedidos de Lucía. Nadie quiere mantener un servidor solo para eso.

Un API Gateway puede recibir la petición web y entregarla a una función Lambda. La función debe responder con la forma exacta que espera la puerta, también cuando la petición es incorrecta.

Al final de esta lección

Nota

Puedo escribir la respuesta que una puerta de API espera de una función.

Palabras clave

PalabraQué significaEjemplo
Peticiónlo que envía quien llama a una dirección webrequest
Respuestalo que la función devuelveresponse
Código de estadoun número que dice cómo fue la petición404
Cabeceraun dato con nombre que viaja junto al cuerpocontent-type
Cuerpoel texto principal de una petición o respuestabody

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Entra una petición, sale una respuesta

La puerta convierte la petición web en un evento. El método, como GET, está en requestContext.http.method. La ruta está en rawPath.

La función devuelve un diccionario con tres partes: statusCode, headers y body. El cuerpo debe ser un texto, así que usa json.dumps. Son formas documentadas, no la salida de una pila tuya.

Run: la puerta más pequeña

Código: python
import json

# La forma documentada de una petición de HTTP API, recortada.
event = {
    "requestContext": {"http": {"method": "GET"}},
    "rawPath": "/pedidos/lucia",
    "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__)
# Cambia "GET" por "POST" en el evento y vuelve a ejecutarlo.

Un código de estado dice quién se equivocó

Un 2 al principio, como 200 o 201, significa éxito. Un 4, como 400 o 404, significa que quien llama pidió algo incorrecto. Un 5 significa que falló la propia función.

Una petición incorrecta no es un fallo del programa. Devuelve un 4 con un error corto en el cuerpo. Una función que lanza un error da a quien llama un 5 vago y no le dice nada que pueda arreglar.

Ejemplo resuelto: los códigos de esta lección

CódigoSignificadoÚsalo cuando
200OKEncontraste y devuelves los datos
201CreadoSe guardó un pedido nuevo
400Petición incorrectaFalta un campo, está mal o el cuerpo no es JSON válido
404No encontradoNo existe la ruta o el pedido
405Método no permitidoLa ruta existe, el método no
415Tipo de contenido no admitidoEl content-type no es application/json

Las celdas que rellenan los estudiantes quedan en blanco en esta vista previa.

Un error frecuente

Advertencia

Mucha gente deja que la función se rompa con una entrada mala. Quien llama recibe entonces un error de servidor vago. Comprueba antes la entrada. Cuando la culpa es de quien llama, devuelve un 4 y di qué debe arreglar. Reserva el 5 para los fallos tuyos.

Run: un error como respuesta

Código: python
import json


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


def handler(event, context):
    # Una clave que falta es culpa de quien llama: responde 400, no te rompas.
    if "queryStringParameters" not in event:
        return reply(400, {"error": "añade ?customer=nombre"})
    name = event["queryStringParameters"]["customer"]
    return reply(200, {"hello": name})


print(handler({"queryStringParameters": {"customer": "lucia"}}, None)["statusCode"])
print(handler({}, None)["statusCode"])
print(handler({}, None)["body"])
# Añade una tercera línea que llame a handler con {"queryStringParameters": {}}. ¿Qué pasa?

Lee la petición con cuidado

No siempre están todas las claves. Sin cadena de consulta, queryStringParameters no aparece en el evento. Comprueba con in antes de leerla.

El cuerpo llega como texto. Si isBase64Encoded es verdadero, el texto está codificado y primero hay que descodificarlo. Los nombres de cabecera llegan en minúsculas, así que busca content-type.

Run: lee un cuerpo en base64

Código: python
import json
import base64

event = {
    "body": base64.b64encode(b'{"item": "te"}').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"])
# Pon isBase64Encoded en False y vuelve a ejecutarlo. ¿Qué sale mal?

Lo que este módulo no enseñó

Nota

Todo aquí se ejecutó sin conexión, en Python, sobre respuestas con la forma de las reales. No desplegaste nada, no entraste en una cuenta real ni viste una factura. No conociste lo que cuesta mantener un servicio en marcha. Eso es un paso aparte, y se aprende mejor con alguien que pueda revisar los ajustes de tu cuenta.

¿Enseñas a una clase? Asigna este módulo a tus alumnos con guía del profesor, tareas con corrección automática y un laboratorio para cada alumno.