8

I have an API Gateway POST endpoint that takes in a JSON request body. I have turned on the body request validator and added the request body model. However the error response I'm getting is only some generic message: "message": "Invalid request body" as defined in the Gateway responses. I'm wondering if it is possible to include the specific validation error in the response? In the logs it says specifically

Request body does not match model schema for content type application/json: 
[object has missing required properties (["property1","property2",...])] 

Is it possible to have something similar to this in the actual response? Thank you.

tianz
  • 2,155
  • 2
  • 19
  • 28

3 Answers3

8

In Gateway response for error type BAD_REQUEST_BODY error status 400

set Application/json to {"message":$context.error.validationErrorString}

Ref https://stackoverflow.com/a/48014686

2

AWS API Gateway will include more details only if the request payload format is valid, but parameters format is invalid:

{
  "message": "Missing required request parameters: [p1]"
}

If the request payload is invalid, you will always receive the same message:

{
  "message": "Invalid request body"
}

See the bottom of following page:

http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-request-validation-test.html

The only way you can get more details is through logs.

By the way, why do you want to send more details through your API, is it for development and debugging only? If yes, using logs is the way to go. You may have some log processing and storage solution to make your debugging easier (e.g. Splunk, Data Dog, Sumo Logic, etc.)

Otherwise, in general, returning too much of technical details in your API error messages is something to avoid.

Sepehr Samiei
  • 382
  • 1
  • 6
  • By "request payload", do you mean the body? By parameters, do you mean the query string arguments? – Bryan Jul 12 '18 at 16:29
  • Request payload is the entire request, including body, and whether it conforms to the API contract. Request parameters can also be query strings for GET operations, or parameters passed through request body in a POST operation. If, e.g. an API expects a parameter to be of Date format and you pass a string that does not represent a valid Date, you'll get an invalid parameter error. – Sepehr Samiei Jul 14 '18 at 04:03
1

TLDR; If you are using an Open API spec, Add this to the root of your Open API spec:

x-amazon-apigateway-gateway-responses:
   BAD_REQUEST_PARAMETERS:
      statusCode: 400
      responseTemplates: application/json: "{\n \"message\": \"Bad Request\", \n \"cause\": $context.error.validationErrorString \n }"
   BAD_REQUEST_BODY:
      statusCode: 400
      responseTemplates: application/json: "{\n \"message\": \"Bad Request\", \n \"cause\": $context.error.validationErrorString \n }"

Explained:

If you are using an Open API spec (Yaml file), you can add some default error handlers of a predefined set of 'Gateway responses' to the root of your open API spec and configure them to return specific information by using the 'context' (a set of variables).

There is a limited set of Gateway responses, here is a list: https://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html

And here is the variables available via the context: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variables-template-example

Here is an example of what I return in an error:

{
    "message": "Bad Request",
    "cause": "Missing value ...",
    "code": "LTAPI_400",
    "X-Transaction-ID": "io7b3c78vtv87baxd324"
}

So my 'x-amazon-apigateway-gateway-responses' are:

x-amazon-apigateway-gateway-responses:
   ACCESS_DENIED:
      statusCode: 401
      responseTemplates:
          application/json: "{\n \"message\": \"$context.authorizer.context.error_type\", \n \"cause\": \"$context.authorizer.context.error_message\", \n \"code\": LTAPI_401, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"

  AUTHORIZER_FAILURE:
      statusCode: 503
      responseTemplates:
          application/json: "{\n \"message\": \"Service Unavailable\", \n \"cause\": \"The request couldn't be completed successfully because of an error in a downstream system.\", \n \"code\": LTAPI_503, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"

  AUTHORIZER_CONFIGURATION_ERROR:
     statusCode: 503
     responseTemplates:
        application/json: "{\n \"message\": \"Service Unavailable\", \n \"cause\": \"The request couldn't be completed successfully because of an error in a downstream system.\", \n \"code\": LTAPI_503, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"

  BAD_REQUEST_PARAMETERS:
     statusCode: 400
     responseTemplates:
        application/json: "{\n \"message\": \"Bad Request\", \n \"cause\": $context.error.validationErrorString, \n \"code\": LTAPI_400, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"

  BAD_REQUEST_BODY:
     statusCode: 400
     responseTemplates:
        application/json: "{\n \"message\": \"Bad Request\", \n \"cause\": $context.error.validationErrorString, \n \"code\": LTAPI_400, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"

  DEFAULT_5XX:
     statusCode: 500
     responseTemplates:
        application/json: "{\n \"message\": \"Internal Server Error\", \n \"cause\": \"An unexpected error has occurred.\", \n \"code\": LTAPI_500, \n \"X-Transaction-ID\": \"$input.params('X-Transaction-ID')\" \n }"