I am trying to validate requests coming into API gateway by using the request validator to validate the body of the request. The JSON body which is expected just has one key which is "userId" and the value should be a UUID. I have setup my model like this:
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "newUser",
"type" : "object",
"properties" : {
"userId" : {
"type" : "string",
"format" : "uuid"
}
}
}
After a few tests it seems to be working, it accepts a valid UUID and all of these correctly return a bad request:
{
"userId": null
}
{
"userId": "text"
}
{
"userId": 123
}
{
"userId": "8327a29c-7134-4566-8b58-"
}
{
"userId": "8327a29c-7134-4566-8b58-46bcf951ef6az"
}
However if you remove a few characters or add a couple of valid hex characters to make it an invalid length then it will pass validation and forward on the request. What is the correct way of validating UUIDs using the request validator in API gateway which actually works?
After investigating more, uuid as a format isn't explicitly defined in the OpenAPI specification. Therefore implementation of format validation is not always consistent with every system. So I think the AWS validator implementation is a little bit funky.
The cleanest solution I have thought of is using regex like this:
{
"$schema" : "http://json-schema.org/draft-04/schema#",
"title" : "newUser",
"type" : "object",
"properties" : {
"userId" : {
"type" : "string",
"format" : "uuid",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
}
}
}
Related
Implementing subscriptions for AWS AppSync I use the enhanced filter capability to filter out tasks, that does not belong to a specific user.
To distinguish between users an ID is used in the claims part of the verified JWT that is then parsed in the $context object in the VTL response mapping.
But subscribers will always receive all objects that are created without the filter taking effect.
Our graphql schema (simplified) is looking like this
type Mutation {
createTask(
done: Boolean!,
due: String!,
id: String!,
identityId: String!,
read: Boolean!,
note: String!,
): Task
}
type Subscription {
create: Task
#aws_subscribe(mutations: ["createTask"])
}
type Task #aws_iam
#aws_oidc {
identityId: String!
done: Boolean
due: String
id: String
read: Boolean
note: String
}
The datasource for the subscription resolver is a NONE datasource and the request and response mappings are the following:
Request:
{
"version": "2017-02-28"
}
Response:
$extensions.setSubscriptionFilter({
"filterGroup": [
{
"filters" : [
{
"fieldName" : "identityId",
"operator" : "eq",
"value" : $context.identity.claims.identityId
}
]
}
]
})
$util.toJson($context.result)
With this enhanced filter I expect AppSync to filter out all tasks where the identityId does not match the one in the token... but that does not work for any reason.
What do i miss?
After a long search and almost giving up, I found the solution myself.
It's all about the correct composition of the payload attribute in the request mapping.
Without the payload object one could not access the claims in the identity part of the context object. Or at least the filtering doesn't seem to work.
Finally my request mapping looks like this:
{
"version" : "2017-02-28",
"payload" : {
"resultList" : $util.toJson($context.result),
"idnId" : "$context.identity.claims.identityId"
}
}
And in the response mapping
$extensions.setSubscriptionFilter({
"filterGroup": [{
"filters" : [{
"fieldName" : "identityId",
"operator" : "eq",
"value" : $context.result.idnId
}]
}]
})
$util.toJson($context.result.resultList)
I can then access the two objects.
So the filtering now works as expected.
I have a REST api and a GET method to a DynamoDB table with this mapping template using Dynamo Query:
{
"TableName": "table",
"KeyConditionExpression": "#id = :v1",
"ExpressionAttributeNames": {
"#id": {
"S": "uuid"
}
},
"ExpressionAttributeValues": {
":v1": {
"S": "$input.params('id')"
}
}
}
When I try to call the endpoint(using url.amazonaws.com/v1/getid?id=itemid), I get
{
"__type": "com.amazon.coral.service#SerializationException",
"Message": "Start of structure or map found where not expected"
}
I have an IAM role that allows Query to Dynamo attached. I haven't gotten this error before with my other GET methods so I assume it is something with 'uuid' being a reserved word. I can't change that so am I doing something wrong with the mapping template?
While it looks correct from here, I got this error when my mapping JSON document was incorrect JSON.
Maybe your actual code has a JSON error?
I've model called "customer" which returns personal details of customer in below structure. It also returns token in meta data. How to retrieve this from model?
"customer" : {
"title" : "Mr",
"firstName": "Person",
"surname" : "surname",
"primaryTelephoneNumber" : {
"number" : "0123456789",
"type": "Home"
}
},
"meta" : {
"token" : "6e16063a-8a89-5d1a-b9cb-72d14c4c7579"
}
To get the metadata just use the metadataFor method, so in your case it would be var meta = this.store.metadataFor("customer");
I'm working on a web service API using the HATEOAS REST representation.
My client can create an item (e.g. a stub of a blogpost):
POST /item
204 Created
Content-Type: application/vnd.foo.item+json
{
"id": 42,
"title": "Lorem Ipsum",
"status": "STUB",
"body": "Very long text."
"_links": {
"self": {
"href": "/item/42"
},
"activate": {
"href": "/item/42/activate"
},
}
}
After that the client can activate the item following the activate link (e.g. go live with the post). So it makes another call to the API:
POST /item/42/activate
200 Ok
Content-Type: application/vnd.foo.item+json
{
"id": 42,
"title": "Lorem Ipsum",
"status": "ACTIVE",
"body": "Very long text."
"_links": {
"self": {
"href": "/item/42"
},
"permalink": {
"href": "/item/42/permalink"
}
}
}
Up to here it is fine. But the problem is that I'm looking for a way to tell the client a suggestion about the next action to do (it's backend business logic).
In my case could be:
Bring the user to post page following the permalink
Bring the user to a shop cart to buy post extra features (visibility, more images, homepage positions and so on...)
Tell the user that the post is pending content review
I don't have an idea on how I could encapsulate this information in HATEOAS.
I was thinking to something like:
POST /item/42/activate
200 Ok
Content-Type: application/json
{
"suggested-action": "check-censure-panel",
"censure-reason": "censored (gambling)",
"_embedded": {
"foo.item": {
"id": 42,
"title": "Lorem Ipsum",
"status": "ACTIVE",
"body": "Very long text."
"_links": {
"self": {
"href": "/item/42"
},
"permalink": {
"href": "/item/42/permalink"
}
}
}
}
But the problem is that every suggested action is heterogeneous for extra attributes, another example may be:
"suggested-action": "go-to-checkout",
"product-order": 424242100,
They don't have a common interface, so I can't make a a vnd.foo.suggestedAction+json type.
What is the best way to design this response?
The next action is a state transition, and you seem to be using HAL so any state transitions should be presented as HAL.
Clients of your app need to react to what state transitions your app provides. So one very simple thing you could do is send a Location header to the next resource the app should present. You could even 302 redirect them there instead of 200'ing them with the updated resource.
You could provide the next action as a link...and not necessarily a HAL link. You could do it as a Link header (https://www.rfc-editor.org/rfc/rfc5988) but i think that would be weird, i just bring it up to knock home the point that your app needs to tell your client about a link.
You seem to want to use custom media types, but you could use profile links (https://www.rfc-editor.org/rfc/rfc6906) and mix in a profile into your vnd.foo type. You can stick to your vnd.foo type and just have it defined that there is an optional suggested-action link relationship. The problem in your example is you're defining it with data fields, but use a link:
{
"id": 42,
"title": "Lorem Ipsum",
"status": "ACTIVE",
"body": "Very long text."
"_links": {
"self": {
"href": "/item/42"
},
"permalink": {
"href": "/item/42/permalink"
},
"x:suggested-action" : {
"href" : "/path/to/best/action"
}
}
the client can follow that link, present the user with an option to follow that link, or ignore it. In the middle case, it's nice if your app provides some context to the user, like a title field:
"x:suggested-action" : {
"href" : "http://path/to/check/censure/panel",
"title" : "Check Censure Panel"
}
Also you can give a hint as to the resource the app can expect:
"x:suggested-action" : {
"href" : "http://path/to/check/censure/panel",
"title" : "Check Censure Panel",
"type" : "vnd.censure.panel/json"
}
I personally don't like doing that as i like my client to react to whatever i send them, but it's useful when you give multiple suggested actions:
"x:suggested-action" : [
{
"href" : "http://path/to/check/censure/panel",
"title" : "Check Censure Panel",
"type" : "vnd.censure.panel/json"
},
{
"href" : "http://path/to/checkout",
"title" : "Start Checkout",
"type" : "vnd.checkout/json"
}
]
now the app can decide based on well defined media types which of the suggested actions it wants to do, present, or ignore.
I am using template on elasticsearch 1.1.1 which is creating special mapping at index creation.
My template is as following :
{
"template": "*",
"mappings": {
"foo": {
"properties": {
"where": {
"type": "nested",
"properties": {
"*": {
"index": "not_analyzed"
},
"geo_point": {
"type": "geo_point"
}
}
}
}
}
}
}
There will be future fields in the nested object "where". I would like them to not be analyzed to avoid tokenization during a terms Faceting. Unfortunately I do not know the name of this future fields when my index is created.
Do you know any way of defining a mapping for any future field in a nested or inner object ?
Sincerely,
You can use dynamic templates for this, along with the index template that you already posted. Have a look here.
You can specify patterns that match your fields and have mappings apply to them instead of the usual defaults.