AWS Api Gateway - Validate incoming XML payload - amazon-web-services

I am trying to validate an incoming XML payload via API gateway. To be specific, I actually don't even care about the schema, I just want to make sure that the body is not empty (and maybe that it is valid XML if I can get that functionality). I see a variety of posts from years ago stating that XML input validation is not yet supported in API Gateway.
Can somebody confirm if this is still the case? To provide a specific example, I have a model like this:
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "Test Schema",
"type" : "object",
"minProperties": 1,
"properties": {
"account_id": {
"type": "string",
"pattern": "[A-Za-z]{6}[0-9]{6}"
}
},
"required": ["account_id"]
}
If I add request body validation using this model for content type "application/json" all is well, but if I do the same for content type "application/xml" no validation is performed.

Yes APIGW only supports json payload validation.

Related

Appsync as Proxy to another Graphql server

I have a existing graphql server provied by 3rd party. I also have my own backend running on EC2 to provide APIs.
I'm trying to build the appsync with aws-cdk for connecting to both 3rd party graphql and my backend instance also.
With the graphql server, appsync will act as proxy to forward queries only. My questions are:
Do we have anyway to load remote schema and populate it in appsync along with its schema?
How can we forward the requests to another graphql server using aws-cdk? I'm trying something like this:
private get _requestMappingTemplate(): string {
return `
{
"version": "2018-05-29",
"method": "GET",
"resourcePath": $util.toJson("/graphql"),
"params": {
"headers": {
"Authorization": "Bearer $ctx.request.headers.Authorization"
},
"body": {
"query": "$util.escapeJavaScript($ctx.info.getSelectionSetGraphQL())"
}
}
}`;
}
But from the aws doc, getSelectionSetGraphQL returns string representation of the selection set, formatted as GraphQL schema definition language (SDL). Although fragments aren't merged into the selection set
Is that possible to setup AppSync for forwarding request to another GraphQL servers? Any best practice to follow?
It's quite a bit more complicated. I'm still working on it, and the best I got so far is given below. It still drops query arguments, so has limited use.
#* TODO: Add some more interesting info to the operation name, e.g. a timestamp *#
#set($operationName = $context.info.parentTypeName)
#set($payloadBody = {
"query": "$util.str.toLower($context.info.parentTypeName) $operationName { $context.info.fieldName $context.info.selectionSetGraphQL }",
"operationName": $operationName,
"variables": $context.info.variables
})
{
"version" : "2018-05-29",
"operation": "Invoke",
"payload":{
"path": "/graphql",
"httpMethod": "POST",
"headers": $util.toJson($ctx.request.headers),
"requestContext": {
"authorizer": {
"claims": $context.identity.claims
}
},
"body": "$util.escapeJavaScript($util.toJson($payloadBody))",
"isBase64Encoded": false
},
}

AWS EventBridge Get EC2 Tags

I am trying to use AWS EventBridge Input Transformer to get the tags of an EC2 instance but I am not familiar with this stuff. the event JSON would look like this (Trimming out irrelevant info):
"tags": [{
"key": "Name",
"value": "windows-server-1"
},
{
"key": "Patch Group",
"value": "Windows"
}],
I am able to access different tags using numeric keys like so:
"patchGroup":"$.detail.resource.instanceDetails.tags[1].value"
The issue is the numeric key isnt standard on our instances and I will always need the Patch Group tag. If I were using JS or C# there would be logic I could implement to find this, I am not seeing anything like that in the documentation. Is there a way to easily get a tag with a key I am missing?

How to use/call amazon connect API StartChatContact & StartContactChat to initiate the chat channel?

I am trying to follow StartContactChat & CreateParticipantConnection to initiate the chat from third party applications e.g. Postman.
i want to route the chat to agent on talk to agent message from API, the chat should be routed to the agent in amazon connect.
StartChatContact's Request Syntax is given like this:
PUT /contact/chat HTTP/1.1
Content-type: application/json
{
"Attributes": {
"string" : "string"
},
"ChatDurationInMinutes": number,
"ClientToken": "string",
"ContactFlowId": "string",
"InitialMessage": {
"Content": "string",
"ContentType": "string"
},
"InstanceId": "string",
"ParticipantDetails": {
"DisplayName": "string"
}
}
I have done with it using URL: PUT https://connect.us-east-1.amazonaws.com/contact/chat and got the ParticipantToken and now trying to create the participant connect using CreateParticipantConnection - https://connect.us-east-1.amazonaws.com/participant/connection but keep facing the error:
{
"message": "Unable to determine service/operation name to be authorized"
}
i have added the participant token generated by StartContactChat in Authorization --> AWS Signature --> Session Token as well as in Header but still the still getting the AccessDeniedExcetion.
The CreateParticipantConnection API does not belong to the same service as the StartChatContact API. As a result, https://connect.us-east-1.amazonaws.com/participant/connection is the wrong endpoint for the latter API. Instead, it should be https://participant.connect.us-east-1.amazonaws.com/participant/connection

APIGateway does not perform request validation when called using POSTMan

Just learning my way through AWS - I have an APIGateway REST API setup with Lambda proxy integration. The API has a model defined, and request validation setup on the body using this model.
Say the model is
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"propertyA": {
"type": "string"
},
"propertyB": {
"type": "string"
},
"propertyC": {
"type": "string"
},
"propertyD": {
"type": "string"
}
},
"required": ["propertyA", "propertyB", "propertyC", "propertyD"]
}
Now, if I test the API via APIGateway console, and purposely give an invalid input (omitting a required property propertyD):
{
"propertyA": "valueA",
"propertyB": "valueB",
"propertyC": "valueC"
}
the request fails with the error(400): Sun Jul 11 13:07:07 UTC 2021 : Request body does not match model schema for content type application/json: [object has missing required properties (["propertyD"])]
But when I invoke the same API(and stage) with the same invalid input from Postman, the validation seems to be not happening, and request is proxied to Lambda, which even returns a 200 OK as long as I comment out the parts of code that depend on propertyD.
What's the difference here? Should I be passing in any request header from the client side? I couldn't find anything from the AWS documentations
Answering my question-
Issue was with the headers used in the request - Postman defaulted the JSON as a Content-Type of text/plain, I had to switch to JSON using the dropdown in Body tab to make PostMan set the Content-Type to application/json
Following this post seems to have fixed the problem: https://itnext.io/how-to-validate-http-requests-before-they-reach-lambda-2fff68bfe93b, although it doesn't explain how
Apparently the magic lies with the config adding Content-Type Header under HTTP Request Headers section, even though the header is set correctly as application/json in PostMan.

AppSync check if DynamoDB record exists

I am trying to write a resolver for AppSync that derives the value for a Boolean field based on the existence of a record in DynamoDB.
I currently have the following request mapping template:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"field1": $util.dynamodb.toDynamoDBJson($ctx.args.field1),
"field2": $util.dynamodb.toDynamoDBJson($ctx.args.field2)
}
}
And the following response mapping template:
#if($util.isNull($ctx.result))
#set($exists = false)
#else
#set($exists = true)
#end
$util.toJson({
"field1": $ctx.args.field1,
"field2": $ctx.args.field2,
"exists": $exists
})
This works correctly if the record exists but if it does not then AppSync simply returns "null" for the entire API call and does not seem to evaluate the response mapping template at all. Is there any way I can instruct it not to do this?
Another option would be to perform a query and look at the length of the response but I have no idea how to check length in these templates.
This is an expected behavior for the 2017 version of the Request template. If you would like the $ctx.result to be evaluated, switch to the 2018 version as below:
{
"version": "2018-05-29",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.id),
},
}
Refer to this change log for additional details.