GraphQL query - suppress non-null error and return partial data - amazon-web-services

I'm using AppSync and DynamoDB. Is there a way to suppress the non-null error and return partial data for a graphql query whose result omits a non-null field? For example if I run the following query:
query GetPerson {
getPerson(id: "123") {
name
active
}
}
And in my AppSync resolver I have logic that decides whether or not to return the value for active. If I decide not to return active, then I get the following response:
{
"data": {
"getPerson": null
},
"errors": [
{
"path": [
"getPerson",
"active"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'Boolean' within parent 'Person' (/getPerson/active)"
}
]
}
because in my schema the active field is non-null. Is there any to suppress this error and return the partial data (i.e. the value for name)? I would like to get a response like this instead:
{
"data": {
"getPerson": {
"name": "Jane Doe"
}
},
"errors": [
{
"path": [
"getPerson",
"active"
],
"locations": null,
"message": "Cannot return null for non-nullable type: 'Boolean' within parent 'Person' (/getPerson/active)"
}
]
}

No. A non-null field should never return null.
If the field is requested and it resolves to null, GraphQL will return an error. Because the field cannot be null, GraphQL will return null for the parent field instead. If that field is also non-null, it will return null for that field's parent... and so on, until it hits either a nullable parent field or the root (i.e. data). This behavior is described in the spec:
If an error is thrown while resolving a field, it should be treated as though the field returned null, and an error must be added to the "errors" list in the response.
If the result of resolving a field is null (either because the function to resolve the field returned null or because an error occurred), and that field is of a Non-Null type, then a field error is thrown. The error must be added to the "errors" list in the response...
Since Non-Null type fields cannot be null, field errors are propagated to be handled by the parent field. If the parent field may be null then it resolves to null, otherwise if it is a Non-Null type, the field error is further propagated to it’s parent field...
If all fields from the root of the request to the source of the field error return Non-Null types, then the "data" entry in the response should be null.
If it's possible for active to be null, then you should not make it non-nullable in your schema.

Related

Race condition like behavior in Apollo Resolvers

We've been having some strange issues with field resolution using Apollo federation --
We have a type defined in Service A called ObjectA. We extended ObjectA in Service B by adding the localizedName field
ObjectA #key(fields: "id") {
id
name
localizedName #requires(fields: "id name")
}
Generally, everything works fine, however when we use a resolver from Service B which returns data in the form of
{
__typename: "ObjectB",
AList: [{__typename: "ObjectA", id: "someId" }],
... other ObjectB fields
}
Fields from ObjectA such as name are returned properly by the resolveReference function, however the localizedName field is usually, but not always null. When the field is null, we see the error
"message": "Field \"name\" was not found in response.",
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"Error: Field \"name\" was not found in response.",
" at executeSelectionSet (C:\\Users\\user\\Documents\\workspace\\gateway\\node_modules\\#apollo\\gateway\\dist\\executeQueryPlan.js:230:27)",
When this possible race condition does not occur, the service works correctly and the localizedName field is resolved.
Is there something that I can do to resolve this? It seems to stem from the query plan trying to fetch the data from B for the field before the resolveReference has been called in A.

AppSync validation error doesn't trigger error handler in response mapping template

I am working with AppSync and it seems that validation errors don't trigger the error catch in the response mapping template.
The attribute values contain an AWSPhone input.
If I input a wrong format for AWSPhone, the error (as expected) is:
{
"data": null,
"errors": [
{
"path": null,
"locations": [
{
"line": 2,
"column": 17,
"sourceName": null
}
],
"message": "Validation error of type WrongType: argument 'input.company.phoneNumber' with value 'StringValue{value='+1-541-754-300'}' is not a valid 'AWSPhone' # 'createProfile'"
}
]
}
My request mapping template is like so:
{
"version": "2018-05-29",
"operation": "PutItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.input.client),
},
"attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
}
My response mapping template:
#if($ctx.error)
$util.error("Custom error response")
#end
$util.toJson($ctx.result)
It's clear that an error does indeed happen but it doesn't trigger the case in my response template.
How do I go about returning a custom message for a validation error?
Is it even possible in this scenario?
Based on what you provided, it looks like your PutItem operation did succeed and returned the item that you put on the $ctx.result field. Then, when AppSync tried to coerce one of the fields on the output of your response mapping template into a AWSPhone it failed with the validation error you mentioned.
The #if($ctx.error) $util.error("Custom error response") will catch only DynamoDB errors. The GraphQL coercion from your result to the field output type happens after the template has evaluated.
One way to catch this would be to add validation into your request mapping template before saving it in DynamoDB or changing the value coming back from DynamoDB into the proper AWSPhone scalar format.

appsync dynamodb won't return primary partition key

With thanks in advance as this is probably a 101 question - I can't find an answer anywhere.
I've set up what I think is a simple example of AppSync and DynamoDB.
In DynamoDB I have a categorys table, with items of the form
{
slug: String!,
nm: String,
nmTrail: String,
...
}
So - no id field. slug is he primary partition key, not null and expected to be unique (is unique in the data I've got loaded so far).
I've set up a simplified AppSync schema in line with the above definition and
a resolver...
{
"version": "2017-02-28",
"operation" : "GetItem",
"key" : {
"slug" : { "S" : "${context.arguments.slug}" }
}
}
A query such as
query GoGetOne {
getCategory(slug: "Wine") {
nm
}
}
Works fine - returning the nm value for the correct item in categorys - similarly I can add any of the other properties in categorys to return them (e.g. nmTrail) except slug.
If I add slug (the Primary Partition Key, a non-nullable String) to the result set then I get a DynamoDB:AmazonDynamoDBException of the provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException.
If I scan/query/filter the table in DynamoDB all is good.
Most of the AWS examples use an id: ID! field in the 'get one' examples and also ask for it as a returned item.
update1 in response to KDs request
My update mutation schema is:
type Mutation {
putCategory(
slug: String!,
nm: String,
nmTrail: String,
mainCategorySlug: String,
mainCategoryNm: String,
parentCategorySlug: String,
parentCategoryNm: String
): Category
}
No resolver associated with that and (obviously) therefore haven't used mutation to put anything yet - just trying to get batch uploaded data to begin with.
/update1
What am I missing?
I tried to reproduce your API as much as I could and it works for me.
Category DynamoDB table
Schema:
type Query {
getCategory(slug: String!): Category
}
type Category {
slug: String
nm: String
nmTrail: String
}
Resolver on Query.getCategory request template:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"slug": $util.dynamodb.toDynamoDBJson($ctx.args.slug),
}
}
Resolver on Query.getCategory response template:
$util.toJson($ctx.result)
Query:
query GoGetOne {
getCategory(slug: "Wine") {
slug
nm
}
}
Results
{
"data": {
"getCategory": {
"slug": "Wine",
"nm": "Wine1-nm"
}
}
}

Intercept the Validation error from Flask restplus namespace class

Currently the Namespace parser validates the request arguments and throws error like
{
"errors": {
"file": "Missing required parameter in an uploaded file"
},
"message": "Input payload validation failed"
}
From the flask-app i want to intercept or handle these exceptions and send a customised response for consistency like
{
"errors": {
"file": "Missing required parameter in an uploaded file"
},
"message": "Input payload validation failed",
"id" : "some customer id "
}
Is it possible to handle this exception from app level instead of doing it for every api
According to this issue https://github.com/noirbizarre/flask-restplus/issues/530 there is a workaround to have a personalized message.
That said, it is possible to implement this with the definition of the BadRequest error handler and modify the data attribute:
#api.errorhandler(BadRequest)
def bad_request(self):
self.data.update({'id': 'some customer id'})
return {}, 400
Though, there is no clean way to avoid the empty dictionary return, as it is discarded.

Insights post_impressions return empty

The following FQL always returns empty JSON response. I have all the necessary permissions set up and I tried all the other suggestions mentioned here.
What else can I try?
SELECT metric, value FROM insights WHERE object_id= '100002643961484_444481312316664' AND metric='post_impressions' AND period = 0
Also
SELECT post_id, impressions FROM stream WHERE source_id = me()
returns null for all the posts. Are there any other restrictions except permissions that make requests return null and empty values?
{
"post_id": "100002643961484_444585178972944",
"impressions": null
},
{
"post_id": "100002643961484_444481312316664",
"impressions": null
},
{
"post_id": "100002643961484_444481068983355",
"impressions": null
},