amazon web services - que - ¿Hay alguna forma de cambiar los códigos de estado http devueltos por Amazon API Gateway?
aws api gateway tutorial (9)
Por ejemplo, si quiero devolver un error 400 específico para parámetros no válidos o quizás un 201 cuando la llamada a la función lambda resultó en una creación.
Me gustaría tener diferentes códigos de estado http, pero parece que la puerta de enlace api siempre devuelve un código de estado 200 incluso si la función lambda devuelve un error.
Aquí está la forma más rápida de devolver códigos de estado HTTP personalizados y un
errorMessage
personalizado:
En el panel de API Gateway, haga lo siguiente:
- En el método para su recurso , haga clic en la respuesta del método
- En la tabla de estado HTTP , haga clic en agregar respuesta y agregue cada código de estado HTTP que le gustaría usar.
- En el método para su recurso , haga clic en respuesta de integración
-
Agregue una respuesta de integración para cada uno de los códigos de estado HTTP que creó anteriormente. Asegúrese de que el paso de entrada esté marcado. Use la expresión regular de error lambda para identificar qué código de estado debe usarse cuando devuelve un mensaje de error de su función lambda. Por ejemplo:
// Return An Error Message String In Your Lambda Function return context.fail(''Bad Request: You submitted invalid input''); // Here is what a Lambda Error Regex should look like. // Be sure to include the period and the asterisk so any text // after your regex is mapped to that specific HTTP Status Code Bad Request: .*
-
Su ruta API Gateway debería devolver esto:
HTTP Status Code: 400 JSON Error Response: { errorMessage: "Bad Request: You submitted invalid input" }
-
No veo forma de copiar esta configuración y reutilizarla para diferentes métodos, ¡así que tenemos muchas entradas manuales redundantes molestas que hacer!
Mis respuestas de integración se ven así:
Así es como se recomienda en un Blog de Computación de AWS si usa API Gateway. Comprobando si la integración funciona con la invocación directa de Lambda.
var myErrorObj = {
errorType : "InternalServerError",
httpStatus : 500,
requestId : context.awsRequestId,
message : "An unknown error has occurred. Please try again."
}
callback(JSON.stringify(myErrorObj));
Para las invocaciones directas de Lambda, esta parece ser la mejor solución de análisis en el lado del cliente.
Estoy usando sin servidor 0.5. Así es como funciona, para mi caso
s-function.json:
{
"name": "temp-err-test",
"description": "Deployed",
"runtime": "nodejs4.3",
"handler": "path/to/handler.handler",
"timeout": 6,
"memorySize": 1024,
"endpoints": [
{
"path": "test-error-handling",
"method": "GET",
"type": "AWS_PROXY",
"responses": {
"default": {
"statusCode": "200"
}
}
}
]
}
handler.js:
''use strict'';
function serveRequest(event, context, cb) {
let response = {
statusCode: ''400'',
body: JSON.stringify({ event, context }),
headers: {
''Content-Type'': ''application/json'',
}
};
cb(null, response);
}
module.exports.handler = serveRequest;
La forma más fácil de hacer esto es usar la integración LAMBDA_PROXY . Con este método, no necesita ninguna transformación especial para establecer en la canalización de API Gateway.
Su objeto de retorno debería ser similar al fragmento a continuación:
module.exports.lambdaHandler = (event, context, done) => {
// ...
let response = {
statusCode: 200, // or any other HTTP code
headers: { // optional
"any-http-header" : "my custom header value"
},
body: JSON.stringify(payload) // data returned by the API Gateway endpoint
};
done(null, response); // always return as a success
};
Tiene algunos inconvenientes: como tener que tener especial cuidado con el manejo de errores y acoplar su función lambda al punto final de API Gateway; Dicho esto, si realmente no lo iba a usar en ningún otro lugar, no es un gran problema.
Para aquellos que intentaron todo, plantearon esta pregunta y no pudieron hacer que esto funcionara (como yo), verifique el comentario del dispositivo en esta publicación (me salvó el día):
https://forums.aws.amazon.com/thread.jspa?threadID=192918
Reproduciéndolo completamente a continuación:
Yo también he tenido problemas con esto, y creo que los personajes de la nueva línea son los culpables.
foo. * coincidirá con las apariciones de "foo" seguidas de cualquier carácter EXCEPTO la nueva línea. Por lo general, esto se resuelve agregando el indicador ''/ s'', es decir, "foo. * / S", pero la expresión regular de error de Lambda no parece respetar esto.
Como alternativa, puede usar algo como: foo (. | / N) *
Para poder devolver un objeto de error personalizado como JSON, debe saltar un par de aros.
Primero, debe fallar el Lambda y pasarle un objeto JSON en cadena:
exports.handler = function(event, context) {
var response = {
status: 400,
errors: [
{
code: "123",
source: "/data/attributes/first-name",
message: "Value is too short",
detail: "First name must contain at least three characters."
},
{
code: "225",
source: "/data/attributes/password",
message: "Passwords must contain a letter, number, and punctuation character.",
detail: "The password provided is missing a punctuation character."
},
{
code: "226",
source: "/data/attributes/password",
message: "Password and password confirmation do not match."
}
]
}
context.fail(JSON.stringify(response));
};
A continuación, configura la asignación de expresiones regulares para cada uno de los códigos de estado que desea devolver. Usando el objeto que definí anteriormente, configuraría esta expresión regular para 400:
. * "estado": 400. *
Finalmente, configura una plantilla de mapeo para extraer la respuesta JSON de la propiedad errorMessage devuelta por Lambda. La plantilla de mapeo se ve así:
$ input.path (''$. errorMessage'')
Escribí un artículo sobre esto que entra en más detalles y explica el flujo de respuesta de Lambda a API Gateway aquí: http://kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object-and-status-code-from-api-gateway-with-lambda/
Quería que un error de Lambda fuera el error 500 correcto, después de investigar mucho, se me ocurrió lo siguiente, que funciona:
En LAMBDA
Para una buena respuesta, vuelvo de la siguiente manera:
exports.handler = (event, context, callback) => {
// ..
var someData1 = {
data: {
httpStatusCode: 200,
details: [
{
prodId: "123",
prodName: "Product 1"
},
{
"more": "213",
"moreDetails": "Product 2"
}
]
}
};
return callback(null, someData1);
}
Para una mala respuesta, regresando de la siguiente manera
exports.handler = (event, context, callback) => {
// ..
var someError1 = {
error: {
httpStatusCode: 500,
details: [
{
code: "ProductNotFound",
message: "Product not found in Cart",
description: "Product should be present after checkout, but not found in Cart",
source: "/data/attributes/product"
},
{
code: "PasswordConfirmPasswordDoesntMatch",
message: "Password and password confirmation do not match.",
description: "Password and password confirmation must match for registration to succeed.",
source: "/data/attributes/password",
}
]
}
};
return callback(new Error(JSON.stringify(someError1)));
}
En API Gateway
Para un MÉTODO DE OBTENCIÓN, diga OBTENER de / res1 / service1:
Through Method Response > Add Response, added 3 responses:
- 200
- 300
- 400
Entonces,
Through ''Integration Response'' > ''Add integration response'', create a Regex for 400 errors (client error):
Lambda Error Regex .*"httpStatusCode":.*4.*
''Body Mapping Templates'' > Add mapping template as:
Content-Type application/json
Template text box* $input.path(''$.errorMessage'')
Similarly, create a Regex for 500 errors (server error):
Lambda Error Regex .*"httpStatusCode":.*5.*
''Body Mapping Templates'' > Add mapping template as:
Content-Type application/json
Template text box* $input.path(''$.errorMessage'')
Ahora, publique / res1 / service1, presione la URL publicada, que está conectada a lambda anterior
Si utiliza el complemento de Chrome Advanced REST client (o Postman), verá los códigos http adecuados, como error del servidor (500) o 400, en lugar del código de respuesta 200 http para todas las solicitudes que se proporcionaron en "httpStatusCode".
Desde el ''Tablero'' de API, en API Gateway, podemos ver los códigos de estado http como a continuación:
1) Configure su recurso API Gateway para usar Lambda Proxy Integration marcando la casilla "Usar integración Lambda Proxy" en la pantalla "Solicitud de integración" de la definición del recurso API Gateway. (O defínalo en su configuración cloudformation / terraform / serverless / etc)
2) Cambie su código lambda de 2 maneras
-
Procese el
event
entrante (argumento de la primera función) de manera apropiada. Ya no es solo la carga útil, representa la solicitud HTTP completa, incluidos los encabezados, la cadena de consulta y el cuerpo. Muestra a continuación. El punto clave es que los cuerpos JSON serán cadenas que requieren unaJSON.parse(event.body)
explícita (no olvidetry/catch
eso). El ejemplo está abajo. -
Responda llamando a la devolución de llamada con un valor nulo y luego con un objeto de respuesta que proporcione los detalles HTTP, incluidos el
statusCode
, elbody
y losheaders
.-
body
debe ser una cadena, así queJSON.stringify(payload)
según sea necesario -
statusCode
puede ser un número -
headers
es un objeto de nombres de encabezado a valores
-
Ejemplo de argumento de evento Lambda para integración de proxy
{
"resource": "/example-path",
"path": "/example-path",
"httpMethod": "POST",
"headers": {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate",
"CloudFront-Forwarded-Proto": "https",
"CloudFront-Is-Desktop-Viewer": "true",
"CloudFront-Is-Mobile-Viewer": "false",
"CloudFront-Is-SmartTV-Viewer": "false",
"CloudFront-Is-Tablet-Viewer": "false",
"CloudFront-Viewer-Country": "US",
"Content-Type": "application/json",
"Host": "exampleapiid.execute-api.us-west-2.amazonaws.com",
"User-Agent": "insomnia/4.0.12",
"Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)",
"X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==",
"X-Forwarded-For": "73.217.16.234, 216.137.42.129",
"X-Forwarded-Port": "443",
"X-Forwarded-Proto": "https"
},
"queryStringParameters": {
"bar": "BarValue",
"foo": "FooValue"
},
"pathParameters": null,
"stageVariables": null,
"requestContext": {
"accountId": "666",
"resourceId": "xyz",
"stage": "dev",
"requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee",
"identity": {
"cognitoIdentityPoolId": null,
"accountId": null,
"cognitoIdentityId": null,
"caller": null,
"apiKey": null,
"sourceIp": "73.217.16.234",
"accessKey": null,
"cognitoAuthenticationType": null,
"cognitoAuthenticationProvider": null,
"userArn": null,
"userAgent": "insomnia/4.0.12",
"user": null
},
"resourcePath": "/example-path",
"httpMethod": "POST",
"apiId": "exampleapiid"
},
"body": "{/n /"foo/": /"FOO/",/n /"bar/": /"BAR/",/n /"baz/": /"BAZ/"/n}/n",
"isBase64Encoded": false
}
Forma de respuesta de devolución de llamada de muestra
callback(null, {
statusCode: 409,
body: JSON.stringify(bodyObject),
headers: {
''Content-Type'': ''application/json''
}
})
Notas
: creo que los métodos en
context
como
context.succeed()
están en desuso.
Ya no están documentados, aunque todavía parecen funcionar.
Creo que la codificación de la API de devolución de llamada es lo correcto en el futuro.
Actualización por 20-9-2016
Amazon finalmente hizo esto fácil usando la integración de Lambda Proxy . Esto permite que su función Lambda devuelva encabezados y códigos HTTP adecuados:
let response = {
statusCode: ''400'',
body: JSON.stringify({ error: ''you messed up!'' }),
headers: {
''Content-Type'': ''application/json'',
}
};
context.succeed(response);
¡Diga adiós mapeo de solicitud / respuesta en API Gateway!
opcion 2
Integre una aplicación Express existente con Lambda / API Gateway usando aws-serverless-express .