I've added a request validator to my API Gateway swagger file (OAS 3.0). When I test the validation by passing in an invalid request body the error message I receive includes errors that I don't understand. Steps to reproduce are below.
Create a new api gateway using the following swagger:
openapi: 3.0.0
info:
version: "1"
title: Request Validation Example
description: |
## Request Validation
Minimal swagger to reproduce request validation errors.
x-amazon-apigateway-request-validators:
all:
validateRequestBody: true
validateRequestParameters: true
x-amazon-apigateway-gateway-responses:
BAD_REQUEST_BODY:
statusCode: 400
responseTemplates:
application/json: |
{
message: $context.error.messageString
errors: $context.error.validationErrorString
}
paths:
/employee:
post:
x-amazon-apigateway-request-validator: all
summary: Create a new Employee
operationId: CreateEmployee
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Employee"
required: true
responses:
"201":
description: Created
$ref: "#/components/responses/200"
components:
responses:
"200":
description: Success
schemas:
Employee:
type: object
properties:
id:
type: integer
format: int32
phoneNumbers:
type: array
items:
$ref: "#/components/schemas/PhoneNumber"
salary:
type: number
format: double
required:
- phoneNumbers
- salary
PhoneNumber:
type: object
properties:
number:
type: string
required:
- number
Set up the integration method for the newly created employee resource, choose the mock integration.
Test the employee POST method using the following request body:
{
"id": 1,
"phoneNumbers": [
{
"number": "1234567890"
}
],
"salary": 45000
}
Request validation will succeed with this request body
Test the employee POST method with the following request body:
{
"id": "1",
"phoneNumbers": [
{
"number": "1234567890"
}
],
"salary": 45000
}
You will now see the following request validation error:
{
message: "Invalid request body"
errors: [instance type (string) does not match any allowed primitive type (allowed: [\"integer\"]), format attribute \"double\" not supported, format attribute \"int32\" not supported]
}
You can see that this message includes the correct error saying that the string id doesn't match the type integer. You will also see errors regarding format attributes double and int32 not being supported, these are the errors I don't understand. As far as I know double and int32 format attributes are supported by OAS 2.0 and 3.0. Do API Gateway request validators support the double and int32 format attributes? Is the request validator incorrectly configured in my swagger definition?
Edit:
It appears that the int32 and double format attributes are known issues: https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-known-issues.html#api-gateway-known-issues-rest-apis
However, I also experience these issues using a regex in the format attribute. This isn't specifically mentioned in the known issues so still looking for information on that.
I think it's important to note that the models defined in a OAS document are supposed to be JSONSchema, not necessarily OpenAPI. They're validated at runtime as JSONSchema Draft 4, which does not include a format attribute in the specification.
What can be confusing at times is the import operation. When using OpenAPI to define your API and importing it, API Gateway ends up parsing the intersection of the OAS specification for models and JSONSchema draft 4.
If there is an attribute of JSONSchema that you need, which is not included in OpenAPI's Schema specification, (e.g. type: [..., null]) then creating or updating an API Gateway ::Model directly is a workaround.
Related
After one approve is made,
I want to know how to get current approval allowance(from an address, to a specified contract and gateway), in json-rpc way.
e.g. like eth_call?
The to field of the call is the token contract, and the data param is ABI-encoded signature of allowance() function followed by its arguments. eth_call also requires to specify at which block you're requesting the data - you can use the "latest" value for the current block
curl -X POST \
--url "<your_node_url>" \
--data '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xdAC17F958D2ee523a2206206994597C13D831ec7","data":"0xdd62ed3e00000000000000000000000086987cca9f86da6b4d8a805c1ebd4130ae120a24000000000000000000000000b2723beacce4bc54f23544343927f048cef6bd5a"}, "latest"],"id":1}'
Docs: https://ethereum.org/en/developers/docs/apis/json-rpc/#eth_call
I used this JS snippet to build the data param value:
const data = web3.eth.abi.encodeFunctionCall({
name: 'allowance',
type: 'function',
inputs: [{
type: 'address',
name: 'from'
},{
type: 'address',
name: 'to'
}]
}, [
"0x86987cca9f86da6b4d8a805c1ebd4130ae120a24",
"0xB2723BEacce4BC54F23544343927f048CeF6bD5A"
]);
console.log(data);
I'm trying to process a simple HTML form from a Python application described using OpenAPI 2.0 and generating the Flask-Connexion code using OpenAPI Generator v4.3.1 and v5.0.1, but I always get a response like:
"['whatever'] is not of type 'string'"
This is my OpenAPI 2.0 spec, and it seems to fit with the section "Form Parameters" of https://swagger.io/docs/specification/2-0/describing-parameters/ :
swagger: "2.0"
info:
version: "1.0.0"
title: "Test"
host: localhost:8080
basePath: /api
schemes:
- http
paths:
/mytest:
post:
operationId: process_test_form
consumes:
- application/x-www-form-urlencoded
produces:
- text/html; charset=utf-8
parameters:
- name: myparam
in: formData
description: "my param"
type: string
required: True
responses:
"200":
description: "Success"
schema:
type: string
I generate the Python application with OpenAPI Generator 4.3.1 and v5.0.1 like this:
java -jar openapi-generator-cli-4.3.1.jar generate -g python-flask -i ./spec.yml
Respecting the generated "requeriments.txt" I did "pip3 install -r requirements.txt" , so I'm finally using:
Werkzeug (0.16.1)
swagger-ui-bundle (0.0.8)
python-dateutil (2.8.1)
setuptools (39.0.1)
connexion (2.7.0)
Then I run the generated code it like this:
python3 -m openapi_server
It can be easyly tested with a simple HTML form like this:
<html>
<body>
<h1>My test</h1>
<form action="http://0.0.0.0:8080/api/mytest" method="post">
<input type="text" name="myparam"><br/>
<input type="submit" name="Accept"><br/>
</form>
</body>
</html>
But it always get the error:
"['anytextentered'] is not of type 'string'"
I can't find what's wrong. The EndPoint is created and it's correctly targeted from the form, because if I omit the parameters I get an error ""'myparam' is a required property"". Maybe there's something missing in the generated requeriments.txt ?
Any help will be very appreciated.
Thanks in advance!
/Ángel
Edit: I tested the v3.0 spec given by Software2 and it generates the same error in my environment (I'm using the one generated by "OpenAPI Generator"). A working "requeriments.txt" would be appreciated.
Swagger 2.0 is quite old. While it may be valid, it's possible there's a bug somewhere in one of the tools that consumes your spec. (Even if this doesn't solve the issue, updating to this more modern format is probably a good idea.) Try using OpenAPI 3.0. Here is your code run through an auto-converter:
openapi: 3.0.1
info:
title: Test
version: 1.0.0
servers:
- url: http://localhost:8080/api
paths:
/mytest:
post:
operationId: process_test_form
requestBody:
content:
application/x-www-form-urlencoded:
schema:
required:
- myparam
properties:
myparam:
type: string
description: my param
required: true
responses:
200:
description: Success
content:
text/html; charset=utf-8:
schema:
type: string
components: {}
I know it's been a year, but I just came across your issue and was having the same problem, myself. I managed to find that it is a missing type:object at the top that seemed to be keeping it from working by looking at oas examples here.
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object <-- this was what I was missing
properties:
id:
type: string
format: uuid
I hope this is at least interesting to you, even if it's likely too late to be helpful.
-Daniel
I would like to use listDevices to get all my devices under a registry.
Google NodeJS Core IOT API spec
I get an array back which seems to contain a metadata obj/json doc but it's empty.
---
- credentials: []
metadata: {}
id: device001
name: ''
numId: '3038801391636994'
config:
lastConfigAckTime:
state:
lastConfigSendTime:
blocked: false
lastStateTime:
logLevel: LOG_LEVEL_UNSPECIFIED
gatewayConfig:
- credentials: []
metadata: {}
id: device002
name: ''
numId: '2991873732633082'
config:
lastConfigAckTime:
state:
lastConfigSendTime:
blocked: false
lastStateTime:
logLevel: LOG_LEVEL_UNSPECIFIED
gatewayConfig:
If I run a getDevice I do get the expected metadata but that requires a request for each device which becomes too slow and hammers resources. Bug or design?
const [response] = await iotClient.getDevice({name: devicePath});
Which actually shows the metadata
Found device: device002 {
credentials: [
{
expirationTime: [Object],
publicKey: [Object],
credential: 'publicKey'
}
],
metadata: {
hasGPS: 'true',
model: 'Pyton_v1',
hasSolar: 'true',
netType: 'WIFI'
},
id: 'device002'
}
I've made some tries with the device list functions and I think it is a design.
If you run the "gcloud iot devices list" command you get only the fields id and num_id, the ones that are filled in your output array too.
I tried using other client libraries and I got the same results, so it looks like it is designed like this but the NodeJS library retrieves additional fields for each device.
It is defined in the fieldMask parameter in listDevices api. Check the example code here:
https://cloud.google.com/iot/docs/how-tos/devices?authuser=1#getting_device_details
I have a Lambda function integrated with API Gateway and the stack was deployed as cloud formation template. When I try to test the endpoint in the AWS web console I got correct response but when I try to invoke the deployed version of the API I got that error.
"message": "Could not parse request body into json: Unrecognized token ....etc"
I tried this mapping { "body" : $input.json('$') } in the integration request, but didn't work.
Here is the JSON I am trying to send using POSTMAN
{
"description": "test description",
"status": "test status"
}
and the request has header: Content-Type: application/json
Here you are screenshots for POSTMAN request body & headers, and the response from the API:
Any Solution guys?
UPDATE:
I put a mapping template at integration request level as the following:
{
"body-json" : $input.json('$')
}
And updated the lambda function to log the coming request, then made 2 requests:
First one: from API Gateway test web console:
I found the following in the cloudwatch logs:
INFO {
body: {
description: 'test',
projectId: 23,
action: 'test',
entity: 'test',
startDate: '01-01-2020',
endDate: '01-01-2020'
}
}
Second one: from POSTMAN:
I found the following in the cloudwatch logs:
INFO {
body: 'ewogICAgImRlc2NyaXB0aW9uIjogInRlc3QiLAogICAgInByb2plY3RJZCI6IDIzLAogICAgImFjdGlvbiI6ICJ0ZXN0IiwKICAgICJlbnRpdHkiOiAidGVzdCIsCiAgICAic3RhcnREYXRlIjogIjAxLTAxLTIwMjAiLAogICAgImVuZERhdGUiOiAiMDEtMDEtMjAyMCIKfQ=='
}
That indicates that in case of making the request using POSTMAN, the JSON payload is stringified automatically. What can cause such thing? and how to deal with it?
In this case we need to edit the mapping template since we are not using a proxy integration.
"body-json" : $input.json('$')
//also if binary data type is enabled for your api your body will be a base64
//encoded string which could be decoded using
$util.base64Decode($input.json('$'))
Also binary data types maybe enabled by default, search for these in the SAM template
x-amazon-apigateway-binary-media-types:
- '*/*'
You need to add a custom header in your response for it to respond correctly.
// The output from a Lambda proxy integration must be
// in the following JSON object. The 'headers' property
// is for custom response headers in addition to standard
// ones. The 'body' property must be a JSON string. For
// base64-encoded payload, you must also set the 'isBase64Encoded'
// property to 'true'.
let response = {
statusCode: responseCode,
headers: {
"x-custom-header" : "my custom header value"
},
body: JSON.stringify(responseBody)
};
I have a problem Working in Api manager of the Anypoint platform at https://anypoint.mulesoft.com/apiplatform..
I made an API Raml definition and am testing all endpoints using the Mock service. So when making a call to the Api endpoint a mock baseurl is provided and the response consists of the example provided with the called endpoint / http verb. This works fine for GET but when doing a 'Try It' for the POST I get
status 400 error
{
"error": "body: person: required"
}
as a response. No matter how I provide the body parameters. My endpoint POST definition is:
post:
body:
application/json:
properties:
person:
required: true
type: object
token:
required: true
type: string
example: |
{
person: {
"firstName": "John",
"infix": "",
"id": "605a0302-cc33-449a-ac50-5ef26e3e3330",
"emailaddress": "john#doe.nl",
"lastName": "Doe"
},
token: '42E2BC51-6C62-6D46-AC1457446EC4C737'
}
In the Api workbench' Mocking service pane I enter this in the body:
{
person: {
"firstName": "John",
"infix": "",
"id": "605a0302-cc33-449a-ac50-5ef26e3e3330",
"emailaddress": "john#doe.nl",
"lastName": "Doe"
},
token: '42E2BC51-6C62-6D46-AC1457446EC4C737'
}
but I still get "error": "body: person: required" also if I omit token ....
What am |I doing wrong here???
Ok., turns out devil's in the details. Input was bad formed json - should surround keys with "" and no singleqoutes for the token value... :(
the json format defined in the raml is not proper one, can you change the raml exmple to a valid json format and test it. it will work fine