Serialize ember-data models into query-params - serialization

I want to bind a controller property that contains an ember-data object to a query string param. I'm using 1.6.0-beta.1+canary with the following in my controller.
export
default Ember.Controller.extend({
queryParams: ['project'],
project: null
});
I can't find a way to serialize/deserialize the ember-data object (project) to/from the url though. Is it possible yet?

I'm not sure why but it seems that the ember team don't want to support serialization of query-params. The best suggestion seems to be to do use a computed property like this:
App.MyController = Ember.ObjectController.extend({
queryParams: ['recordId']
recordId: null,
record: function(key, value) {
if (arguments.length > 1) {
//handle set by setting recordId
this.set('recordId', value.get('id');
}
return this.store.find('record', this.get('recordId'));
}.property('recordId')
});
It's workable but seems cludgy to say the least...

Related

Graphql mutation succeeds but displays return fields as null [duplicate]

I have an graphql/apollo-server/graphql-yoga endpoint. This endpoint exposes data returned from a database (or a REST endpoint or some other service).
I know my data source is returning the correct data -- if I log the result of the call to the data source inside my resolver, I can see the data being returned. However, my GraphQL field(s) always resolve to null.
If I make the field non-null, I see the following error inside the errors array in the response:
Cannot return null for non-nullable field
Why is GraphQL not returning the data?
There's two common reasons your field or fields are resolving to null: 1) returning data in the wrong shape inside your resolver; and 2) not using Promises correctly.
Note: if you're seeing the following error:
Cannot return null for non-nullable field
the underlying issue is that your field is returning null. You can still follow the steps outlined below to try to resolve this error.
The following examples will refer to this simple schema:
type Query {
post(id: ID): Post
posts: [Post]
}
type Post {
id: ID
title: String
body: String
}
Returning data in the wrong shape
Our schema, along with the requested query, defines the "shape" of the data object in the response returned by our endpoint. By shape, we mean what properties objects have, and whether those properties' values' are scalar values, other objects, or arrays of objects or scalars.
In the same way a schema defines the shape of the total response, the type of an individual field defines the shape of that field's value. The shape of the data we return in our resolver must likewise match this expected shape. When it doesn't, we frequently end up with unexpected nulls in our response.
Before we dive into specific examples, though, it's important to grasp how GraphQL resolves fields.
Understanding default resolver behavior
While you certainly can write a resolver for every field in your schema, it's often not necessary because GraphQL.js uses a default resolver when you don't provide one.
At a high level, what the default resolver does is simple: it looks at the value the parent field resolved to and if that value is a JavaScript object, it looks for a property on that Object with the same name as the field being resolved. If it finds that property, it resolves to the value of that property. Otherwise, it resolves to null.
Let's say in our resolver for the post field, we return the value { title: 'My First Post', bod: 'Hello World!' }. If we don't write resolvers for any of the fields on the Post type, we can still request the post:
query {
post {
id
title
body
}
}
and our response will be
{
"data": {
"post" {
"id": null,
"title": "My First Post",
"body": null,
}
}
}
The title field was resolved even though we didn't provide a resolver for it because the default resolver did the heavy lifting -- it saw there was a property named title on the Object the parent field (in this case post) resolved to and so it just resolved to that property's value. The id field resolved to null because the object we returned in our post resolver did not have an id property. The body field also resolved to null because of a typo -- we have a property called bod instead of body!
Pro tip: If bod is not a typo but what an API or database actually returns, we can always write a resolver for the body field to match our schema. For example: (parent) => parent.bod
One important thing to keep in mind is that in JavaScript, almost everything is an Object. So if the post field resolves to a String or a Number, the default resolver for each of the fields on the Post type will still try to find an appropriately named property on the parent object, inevitably fail and return null. If a field has an object type but you return something other than object in its resolver (like a String or an Array), you will not see any error about the type mismatch but the child fields for that field will inevitably resolve to null.
Common Scenario #1: Wrapped Responses
If we're writing the resolver for the post query, we might fetch our code from some other endpoint, like this:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json());
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
});
}
The post field has the type Post, so our resolver should return an object with properties like id, title and body. If this is what our API returns, we're all set. However, it's common for the response to actually be an object which contains additional metadata. So the object we actually get back from the endpoint might look something like this:
{
"status": 200,
"result": {
"id": 1,
"title": "My First Post",
"body": "Hello world!"
},
}
In this case, we can't just return the response as-is and expect the default resolver to work correctly, since the object we're returning doesn't have the id , title and body properties we need. Our resolver isn't needs to do something like:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data.result);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json())
.then(data => data.result);
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
})
.then(res => res.result);
}
Note: The above example fetches data from another endpoint; however, this sort of wrapped response is also very common when using a database driver directly (as opposed to using an ORM)! For example, if you're using node-postgres, you'll get a Result object that includes properties like rows, fields, rowCount and command. You'll need to extract the appropriate data from this response before returning it inside your resolver.
Common Scenario #2: Array Instead of Object
What if we fetch a post from the database, our resolver might look something like this:
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
}
where Post is some model we're injecting through the context. If we're using sequelize, we might call findAll. mongoose and typeorm have find. What these methods have in common is that while they allow us to specify a WHERE condition, the Promises they return still resolve to an array instead of a single object. While there's probably only one post in your database with a particular ID, it's still wrapped in an array when you call one of these methods. Because an Array is still an Object, GraphQL will not resolve the post field as null. But it will resolve all of the child fields as null because it won't be able to find the appropriately named properties on the array.
You can easily fix this scenario by just grabbing the first item in the array and returning that in your resolver:
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
.then(posts => posts[0])
}
If you're fetching data from another API, this is frequently the only option. On the other hand, if you're using an ORM, there's often a different method that you can use (like findOne) that will explicitly return only a single row from the DB (or null if it doesn't exist).
function post(root, args, context) {
return context.Post.findOne({ where: { id: args.id } })
}
A special note on INSERT and UPDATE calls: We often expect methods that insert or update a row or model instance to return the inserted or updated row. Often they do, but some methods don't. For example, sequelize's upsert method resolves to a boolean, or tuple of the the upserted record and a boolean (if the returning option is set to true). mongoose's findOneAndUpdate resolves to an object with a value property that contains the modified row. Consult your ORM's documentation and parse the result appropriately before returning it inside your resolver.
Common Scenario #3: Object Instead of Array
In our schema, the posts field's type is a List of Posts, which means its resolver needs to return an Array of objects (or a Promise that resolves to one). We might fetch the posts like this:
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
}
However, the actual response from our API might be an object that wraps the the array of posts:
{
"count": 10,
"next": "http://SOME_URL/posts/?page=2",
"previous": null,
"results": [
{
"id": 1,
"title": "My First Post",
"body" "Hello World!"
},
...
]
}
We can't return this object in our resolver because GraphQL is expecting an Array. If we do, the field will resolve to null and we'll see an error included in our response like:
Expected Iterable, but did not find one for field Query.posts.
Unlike the two scenarios above, in this case GraphQL is able to explicitly check the type of the value we return in our resolver and will throw if it's not an Iterable like an Array.
Like we discussed in the first scenario, in order to fix this error, we have to transform the response into the appropriate shape, for example:
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
.then(data => data.results)
}
Not Using Promises Correctly
GraphQL.js makes use of the Promise API under the hood. As such, a resolver can return some value (like { id: 1, title: 'Hello!' }) or it can return a Promise that will resolve to that value. For fields that have a List type, you may also return an array of Promises. If a Promise rejects, that field will return null and the appropriate error will be added to the errors array in the response. If a field has an Object type, the value the Promise resolves to is what will be passed down as the parent value to the resolvers of any child fields.
A Promise is an "object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value." The next few scenarios outline some common pitfalls encountered when dealing with Promises inside resolvers. However, if you're not familiar with Promises and the newer async/await syntax, it's highly recommended you spend some time reading up on the fundamentals.
Note: the next few examples refer to a getPost function. The implementation details of this function are not important -- it's just a function that returns a Promise, which will resolve to a post object.
Common Scenario #4: Not Returning a Value
A working resolver for the post field might looks like this:
function post(root, args) {
return getPost(args.id)
}
getPosts returns a Promise and we're returning that Promise. Whatever that Promise resolves to will become the value our field resolves to. Looking good!
But what happens if we do this:
function post(root, args) {
getPost(args.id)
}
We're still creating a Promise that will resolve to a post. However, we're not returning the Promise, so GraphQL is not aware of it and it will not wait for it to resolve. In JavaScript functions without an explicit return statement implicitly return undefined. So our function creates a Promise and then immediately returns undefined, causing GraphQL to return null for the field.
If the Promise returned by getPost rejects, we won't see any error listed in our response either -- because we didn't return the Promise, the underlying code doesn't care about whether it resolves or rejects. In fact, if the Promise rejects, you'll see an
UnhandledPromiseRejectionWarning in your server console.
Fixing this issue is simple -- just add the return.
Common Scenario #5: Not chaining Promises correctly
You decide to log the result of your call to getPost, so you change your resolver to look something like this:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
})
}
When you run your query, you see the result logged in your console, but GraphQL resolves the field to null. Why?
When we call then on a Promise, we're effectively taking the value the Promise resolved to and returning a new Promise. You can think of it kind of like Array.map except for Promises. then can return a value, or another Promise. In either case, what's returned inside of then is "chained" onto the original Promise. Multiple Promises can be chained together like this by using multiple thens. Each Promise in the chain is resolved in sequence, and the final value is what's effectively resolved as the value of the original Promise.
In our example above, we returned nothing inside of the then, so the Promise resolved to undefined, which GraphQL converted to a null. To fix this, we have to return the posts:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
return post // <----
})
}
If you have multiple Promises you need to resolve inside your resolver, you have to chain them correctly by using then and returning the correct value. For example, if we need to call two other asynchronous functions (getFoo and getBar) before we can call getPost, we can do:
function post(root, args) {
return getFoo()
.then(foo => {
// Do something with foo
return getBar() // return next Promise in the chain
})
.then(bar => {
// Do something with bar
return getPost(args.id) // return next Promise in the chain
})
Pro tip: If you're struggling with correctly chaining Promises, you may find async/await syntax to be cleaner and easier to work with.
Common Scenario #6
Before Promises, the standard way to handle asynchronous code was to use callbacks, or functions that would be called once the asynchronous work was completed. We might, for example, call mongoose's findOne method like this:
function post(root, args) {
return Post.findOne({ where: { id: args.id } }, function (err, post) {
return post
})
The problem here is two-fold. One, a value that's returned inside a callback isn't used for anything (i.e. it's not passed to the underlying code in any way). Two, when we use a callback, Post.findOne doesn't return a Promise; it just returns undefined. In this example, our callback will be called, and if we log the value of post we'll see whatever was returned from the database. However, because we didn't use a Promise, GraphQL doesn't wait for this callback to complete -- it takes the return value (undefined) and uses that.
Most more popular libraries, including mongoose support Promises out of the box. Those that don't frequently have complimentary "wrapper" libraries that add this functionality. When working with GraphQL resolvers, you should avoid using methods that utilize a callback, and instead use ones that return Promises.
Pro tip: Libraries that support both callbacks and Promises frequently overload their functions in such a way that if a callback is not provided, the function will return a Promise. Check the library's documentation for details.
If you absolutely have to use a callback, you can also wrap the callback in a Promise:
function post(root, args) {
return new Promise((resolve, reject) => {
Post.findOne({ where: { id: args.id } }, function (err, post) {
if (err) {
reject(err)
} else {
resolve(post)
}
})
})
I had the same issue on Nest.js.
If you like to solve the issue. You can add {nullable: true} option to your #Query decorator.
Here's an example.
#Resolver(of => Team)
export class TeamResolver {
constructor(
private readonly teamService: TeamService,
private readonly memberService: MemberService,
) {}
#Query(returns => Team, { name: 'team', nullable: true })
#UseGuards(GqlAuthGuard)
async get(#Args('id') id: string) {
return this.teamService.findOne(id);
}
}
Then, you can return null object for query.
Coming from Flutter here.
I couldn't find any flutter related solution to this so since my search always brought me here, lemme just add it here.
The exact error was:
Failure performing sync query to AppSync:
[GraphQLResponse.Error{message='Cannot return null for non-nullable
type: 'AWSTimestamp' within parent
So, in my schema (on the AppSync console) I had this:
type TypeName {
id: ID!
...
_version: Int!
_deleted: Boolean
_lastChangedAt: AWSTimestamp!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
I got the error from the field _lastChangedAt as AWSTimestamp couldn't be null.
All I had to do was remove the null-check (!) from the field and it was resolved.
Now, I don't know the implications of this in the long run but I'll update this answer if necessary.
EDIT: The implication of this as I have found out is anything I do, amplify.push that change is reversed. Just go back to your appsync console and change it again while you test. So this isn't a sustainable solution but chatter I've picked up online suggests improvements are coming to amplify flutter very soon.
#Thomas Hennes got it spot on for me
The title field was resolved even though we didn't provide a resolver for it because the default resolver did the heavy lifting -- it saw there was a property named title on the Object the parent field (in this case post) resolved to and so it just resolved to that property's value. The id field resolved to null because the object we returned in our post resolver did not have an id property. The body field also resolved to null because of a typo -- we have a property called bod instead of body!
Pro tip: If bod is not a typo but what an API or database actually returns, we can always write a resolver for the body field to match our schema. For example: (parent) => parent.bod
One important thing to keep in mind is that in JavaScript, almost everything is an Object. So if the post field resolves to a String or a Number, the default resolver for each of the fields on the Post type will still try to find an appropriately named property on the parent object, inevitably fail and return null. If a field has an object type but you return something other than object in its resolver (like a String or an Array), you will not see any error about the type mismatch but the child fields for that field will inevitably resolve to null.
In case anyone has used apollo-server-express and getting null value.
// This will return values, as you expect.
const typeDefs = require('./schema');
const resolvers = require('./resolver');
const server = new ApolloServer({typeDefs,resolvers});
// This will return null, since ApolloServer constructor is not using correct properties.
const withDifferentVarNameSchema = require('./schema');
const withDifferentVarNameResolver= require('./resolver');
const server = new ApolloServer({withDifferentVarNameSchema,withDifferentVarNameResolver});
Note: While creating an instance of Apolloserver pass the typeDefs and resolvers var name only.
If none of the above helped, and you have a global interceptor that envelopes all the responses for example inside a "data" field, you must disable this for graphql other wise graphql resolvers convert to null.
This is what I did to the interceptor on my case:
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
if (context['contextType'] === 'graphql') return next.handle();
return next
.handle()
.pipe(map(data => {
return {
data: isObject(data) ? this.transformResponse(data) : data
};
}));
}

grapqhql does not return null on null object [duplicate]

I have an graphql/apollo-server/graphql-yoga endpoint. This endpoint exposes data returned from a database (or a REST endpoint or some other service).
I know my data source is returning the correct data -- if I log the result of the call to the data source inside my resolver, I can see the data being returned. However, my GraphQL field(s) always resolve to null.
If I make the field non-null, I see the following error inside the errors array in the response:
Cannot return null for non-nullable field
Why is GraphQL not returning the data?
There's two common reasons your field or fields are resolving to null: 1) returning data in the wrong shape inside your resolver; and 2) not using Promises correctly.
Note: if you're seeing the following error:
Cannot return null for non-nullable field
the underlying issue is that your field is returning null. You can still follow the steps outlined below to try to resolve this error.
The following examples will refer to this simple schema:
type Query {
post(id: ID): Post
posts: [Post]
}
type Post {
id: ID
title: String
body: String
}
Returning data in the wrong shape
Our schema, along with the requested query, defines the "shape" of the data object in the response returned by our endpoint. By shape, we mean what properties objects have, and whether those properties' values' are scalar values, other objects, or arrays of objects or scalars.
In the same way a schema defines the shape of the total response, the type of an individual field defines the shape of that field's value. The shape of the data we return in our resolver must likewise match this expected shape. When it doesn't, we frequently end up with unexpected nulls in our response.
Before we dive into specific examples, though, it's important to grasp how GraphQL resolves fields.
Understanding default resolver behavior
While you certainly can write a resolver for every field in your schema, it's often not necessary because GraphQL.js uses a default resolver when you don't provide one.
At a high level, what the default resolver does is simple: it looks at the value the parent field resolved to and if that value is a JavaScript object, it looks for a property on that Object with the same name as the field being resolved. If it finds that property, it resolves to the value of that property. Otherwise, it resolves to null.
Let's say in our resolver for the post field, we return the value { title: 'My First Post', bod: 'Hello World!' }. If we don't write resolvers for any of the fields on the Post type, we can still request the post:
query {
post {
id
title
body
}
}
and our response will be
{
"data": {
"post" {
"id": null,
"title": "My First Post",
"body": null,
}
}
}
The title field was resolved even though we didn't provide a resolver for it because the default resolver did the heavy lifting -- it saw there was a property named title on the Object the parent field (in this case post) resolved to and so it just resolved to that property's value. The id field resolved to null because the object we returned in our post resolver did not have an id property. The body field also resolved to null because of a typo -- we have a property called bod instead of body!
Pro tip: If bod is not a typo but what an API or database actually returns, we can always write a resolver for the body field to match our schema. For example: (parent) => parent.bod
One important thing to keep in mind is that in JavaScript, almost everything is an Object. So if the post field resolves to a String or a Number, the default resolver for each of the fields on the Post type will still try to find an appropriately named property on the parent object, inevitably fail and return null. If a field has an object type but you return something other than object in its resolver (like a String or an Array), you will not see any error about the type mismatch but the child fields for that field will inevitably resolve to null.
Common Scenario #1: Wrapped Responses
If we're writing the resolver for the post query, we might fetch our code from some other endpoint, like this:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json());
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
});
}
The post field has the type Post, so our resolver should return an object with properties like id, title and body. If this is what our API returns, we're all set. However, it's common for the response to actually be an object which contains additional metadata. So the object we actually get back from the endpoint might look something like this:
{
"status": 200,
"result": {
"id": 1,
"title": "My First Post",
"body": "Hello world!"
},
}
In this case, we can't just return the response as-is and expect the default resolver to work correctly, since the object we're returning doesn't have the id , title and body properties we need. Our resolver isn't needs to do something like:
function post (root, args) {
// axios
return axios.get(`http://SOME_URL/posts/${args.id}`)
.then(res => res.data.result);
// fetch
return fetch(`http://SOME_URL/posts/${args.id}`)
.then(res => res.json())
.then(data => data.result);
// request-promise-native
return request({
uri: `http://SOME_URL/posts/${args.id}`,
json: true
})
.then(res => res.result);
}
Note: The above example fetches data from another endpoint; however, this sort of wrapped response is also very common when using a database driver directly (as opposed to using an ORM)! For example, if you're using node-postgres, you'll get a Result object that includes properties like rows, fields, rowCount and command. You'll need to extract the appropriate data from this response before returning it inside your resolver.
Common Scenario #2: Array Instead of Object
What if we fetch a post from the database, our resolver might look something like this:
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
}
where Post is some model we're injecting through the context. If we're using sequelize, we might call findAll. mongoose and typeorm have find. What these methods have in common is that while they allow us to specify a WHERE condition, the Promises they return still resolve to an array instead of a single object. While there's probably only one post in your database with a particular ID, it's still wrapped in an array when you call one of these methods. Because an Array is still an Object, GraphQL will not resolve the post field as null. But it will resolve all of the child fields as null because it won't be able to find the appropriately named properties on the array.
You can easily fix this scenario by just grabbing the first item in the array and returning that in your resolver:
function post(root, args, context) {
return context.Post.find({ where: { id: args.id } })
.then(posts => posts[0])
}
If you're fetching data from another API, this is frequently the only option. On the other hand, if you're using an ORM, there's often a different method that you can use (like findOne) that will explicitly return only a single row from the DB (or null if it doesn't exist).
function post(root, args, context) {
return context.Post.findOne({ where: { id: args.id } })
}
A special note on INSERT and UPDATE calls: We often expect methods that insert or update a row or model instance to return the inserted or updated row. Often they do, but some methods don't. For example, sequelize's upsert method resolves to a boolean, or tuple of the the upserted record and a boolean (if the returning option is set to true). mongoose's findOneAndUpdate resolves to an object with a value property that contains the modified row. Consult your ORM's documentation and parse the result appropriately before returning it inside your resolver.
Common Scenario #3: Object Instead of Array
In our schema, the posts field's type is a List of Posts, which means its resolver needs to return an Array of objects (or a Promise that resolves to one). We might fetch the posts like this:
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
}
However, the actual response from our API might be an object that wraps the the array of posts:
{
"count": 10,
"next": "http://SOME_URL/posts/?page=2",
"previous": null,
"results": [
{
"id": 1,
"title": "My First Post",
"body" "Hello World!"
},
...
]
}
We can't return this object in our resolver because GraphQL is expecting an Array. If we do, the field will resolve to null and we'll see an error included in our response like:
Expected Iterable, but did not find one for field Query.posts.
Unlike the two scenarios above, in this case GraphQL is able to explicitly check the type of the value we return in our resolver and will throw if it's not an Iterable like an Array.
Like we discussed in the first scenario, in order to fix this error, we have to transform the response into the appropriate shape, for example:
function posts (root, args) {
return fetch('http://SOME_URL/posts')
.then(res => res.json())
.then(data => data.results)
}
Not Using Promises Correctly
GraphQL.js makes use of the Promise API under the hood. As such, a resolver can return some value (like { id: 1, title: 'Hello!' }) or it can return a Promise that will resolve to that value. For fields that have a List type, you may also return an array of Promises. If a Promise rejects, that field will return null and the appropriate error will be added to the errors array in the response. If a field has an Object type, the value the Promise resolves to is what will be passed down as the parent value to the resolvers of any child fields.
A Promise is an "object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value." The next few scenarios outline some common pitfalls encountered when dealing with Promises inside resolvers. However, if you're not familiar with Promises and the newer async/await syntax, it's highly recommended you spend some time reading up on the fundamentals.
Note: the next few examples refer to a getPost function. The implementation details of this function are not important -- it's just a function that returns a Promise, which will resolve to a post object.
Common Scenario #4: Not Returning a Value
A working resolver for the post field might looks like this:
function post(root, args) {
return getPost(args.id)
}
getPosts returns a Promise and we're returning that Promise. Whatever that Promise resolves to will become the value our field resolves to. Looking good!
But what happens if we do this:
function post(root, args) {
getPost(args.id)
}
We're still creating a Promise that will resolve to a post. However, we're not returning the Promise, so GraphQL is not aware of it and it will not wait for it to resolve. In JavaScript functions without an explicit return statement implicitly return undefined. So our function creates a Promise and then immediately returns undefined, causing GraphQL to return null for the field.
If the Promise returned by getPost rejects, we won't see any error listed in our response either -- because we didn't return the Promise, the underlying code doesn't care about whether it resolves or rejects. In fact, if the Promise rejects, you'll see an
UnhandledPromiseRejectionWarning in your server console.
Fixing this issue is simple -- just add the return.
Common Scenario #5: Not chaining Promises correctly
You decide to log the result of your call to getPost, so you change your resolver to look something like this:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
})
}
When you run your query, you see the result logged in your console, but GraphQL resolves the field to null. Why?
When we call then on a Promise, we're effectively taking the value the Promise resolved to and returning a new Promise. You can think of it kind of like Array.map except for Promises. then can return a value, or another Promise. In either case, what's returned inside of then is "chained" onto the original Promise. Multiple Promises can be chained together like this by using multiple thens. Each Promise in the chain is resolved in sequence, and the final value is what's effectively resolved as the value of the original Promise.
In our example above, we returned nothing inside of the then, so the Promise resolved to undefined, which GraphQL converted to a null. To fix this, we have to return the posts:
function post(root, args) {
return getPost(args.id)
.then(post => {
console.log(post)
return post // <----
})
}
If you have multiple Promises you need to resolve inside your resolver, you have to chain them correctly by using then and returning the correct value. For example, if we need to call two other asynchronous functions (getFoo and getBar) before we can call getPost, we can do:
function post(root, args) {
return getFoo()
.then(foo => {
// Do something with foo
return getBar() // return next Promise in the chain
})
.then(bar => {
// Do something with bar
return getPost(args.id) // return next Promise in the chain
})
Pro tip: If you're struggling with correctly chaining Promises, you may find async/await syntax to be cleaner and easier to work with.
Common Scenario #6
Before Promises, the standard way to handle asynchronous code was to use callbacks, or functions that would be called once the asynchronous work was completed. We might, for example, call mongoose's findOne method like this:
function post(root, args) {
return Post.findOne({ where: { id: args.id } }, function (err, post) {
return post
})
The problem here is two-fold. One, a value that's returned inside a callback isn't used for anything (i.e. it's not passed to the underlying code in any way). Two, when we use a callback, Post.findOne doesn't return a Promise; it just returns undefined. In this example, our callback will be called, and if we log the value of post we'll see whatever was returned from the database. However, because we didn't use a Promise, GraphQL doesn't wait for this callback to complete -- it takes the return value (undefined) and uses that.
Most more popular libraries, including mongoose support Promises out of the box. Those that don't frequently have complimentary "wrapper" libraries that add this functionality. When working with GraphQL resolvers, you should avoid using methods that utilize a callback, and instead use ones that return Promises.
Pro tip: Libraries that support both callbacks and Promises frequently overload their functions in such a way that if a callback is not provided, the function will return a Promise. Check the library's documentation for details.
If you absolutely have to use a callback, you can also wrap the callback in a Promise:
function post(root, args) {
return new Promise((resolve, reject) => {
Post.findOne({ where: { id: args.id } }, function (err, post) {
if (err) {
reject(err)
} else {
resolve(post)
}
})
})
I had the same issue on Nest.js.
If you like to solve the issue. You can add {nullable: true} option to your #Query decorator.
Here's an example.
#Resolver(of => Team)
export class TeamResolver {
constructor(
private readonly teamService: TeamService,
private readonly memberService: MemberService,
) {}
#Query(returns => Team, { name: 'team', nullable: true })
#UseGuards(GqlAuthGuard)
async get(#Args('id') id: string) {
return this.teamService.findOne(id);
}
}
Then, you can return null object for query.
Coming from Flutter here.
I couldn't find any flutter related solution to this so since my search always brought me here, lemme just add it here.
The exact error was:
Failure performing sync query to AppSync:
[GraphQLResponse.Error{message='Cannot return null for non-nullable
type: 'AWSTimestamp' within parent
So, in my schema (on the AppSync console) I had this:
type TypeName {
id: ID!
...
_version: Int!
_deleted: Boolean
_lastChangedAt: AWSTimestamp!
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
I got the error from the field _lastChangedAt as AWSTimestamp couldn't be null.
All I had to do was remove the null-check (!) from the field and it was resolved.
Now, I don't know the implications of this in the long run but I'll update this answer if necessary.
EDIT: The implication of this as I have found out is anything I do, amplify.push that change is reversed. Just go back to your appsync console and change it again while you test. So this isn't a sustainable solution but chatter I've picked up online suggests improvements are coming to amplify flutter very soon.
#Thomas Hennes got it spot on for me
The title field was resolved even though we didn't provide a resolver for it because the default resolver did the heavy lifting -- it saw there was a property named title on the Object the parent field (in this case post) resolved to and so it just resolved to that property's value. The id field resolved to null because the object we returned in our post resolver did not have an id property. The body field also resolved to null because of a typo -- we have a property called bod instead of body!
Pro tip: If bod is not a typo but what an API or database actually returns, we can always write a resolver for the body field to match our schema. For example: (parent) => parent.bod
One important thing to keep in mind is that in JavaScript, almost everything is an Object. So if the post field resolves to a String or a Number, the default resolver for each of the fields on the Post type will still try to find an appropriately named property on the parent object, inevitably fail and return null. If a field has an object type but you return something other than object in its resolver (like a String or an Array), you will not see any error about the type mismatch but the child fields for that field will inevitably resolve to null.
In case anyone has used apollo-server-express and getting null value.
// This will return values, as you expect.
const typeDefs = require('./schema');
const resolvers = require('./resolver');
const server = new ApolloServer({typeDefs,resolvers});
// This will return null, since ApolloServer constructor is not using correct properties.
const withDifferentVarNameSchema = require('./schema');
const withDifferentVarNameResolver= require('./resolver');
const server = new ApolloServer({withDifferentVarNameSchema,withDifferentVarNameResolver});
Note: While creating an instance of Apolloserver pass the typeDefs and resolvers var name only.
If none of the above helped, and you have a global interceptor that envelopes all the responses for example inside a "data" field, you must disable this for graphql other wise graphql resolvers convert to null.
This is what I did to the interceptor on my case:
intercept(
context: ExecutionContext,
next: CallHandler,
): Observable<Response<T>> {
if (context['contextType'] === 'graphql') return next.handle();
return next
.handle()
.pipe(map(data => {
return {
data: isObject(data) ? this.transformResponse(data) : data
};
}));
}

vue.js - Cannot read property 'toLowerCase' of undefined

I am filtering projects with a computed property like this:
filtered_projects() {
return this.projects.filter( (project) => {
return project.title.toLowerCase().indexOf(this.project_filter.toLowerCase()) !== -1
})
}
When I add a new project using this
submitNewProject() {
let path = '/api/projects';
Vue.http.post(path, this.project)
.then( (rsp) => {
this.projects.push(rsp.data);
this.project = this.getSingleProject();
this.create_project = false;
return true;
});
}
This is giving me an error that I can't find
TypeError: Cannot read property 'toLowerCase' of undefined
It may just be that you are not correctly passing the projects data to the projects array.
Firstly vue-resource now uses body not data to get the response, therefore you may need to use:
this.projects.push(rsp.body)
then this will give you a single array item containing all projects which doesn't look like what you want. I believe instead you're after:
this.projects = rsp.body
Assuming the response body is an array of objects this will then allow:
this.projects.filter(project => {})
to work as expected. Meaning project.title should now be valid
EDIT
For a project title to be set to lowerCase you must be returning an object with a title param, i.e.
rsp.body = {
title: 'FOO',
}
which you'd then set on the projects array via:
this.projects.push(rsp.body)
so the first thing to fix is your response, sort your endpoint so it returns what you are expecting, then the rest of the above code should work
You need preserve "this" before Vue.http.post (self=this) and then in callback change this.projects to self.projects.
Explanation:
How to access the correct `this` context inside a callback?

ember data: customize serializer used by toJSON

In my ember-data-using application I have an application serializer (mainly to take care of polymorphic relationships properly). However, its not used when I call toJSON() on a model instance, its not used -- rather the default JSONSerializer is used instead.
How can I customize the serializer used by toJSON()?
First of all i hope i understood properly your question...
Well, If you want to get the same result as in your ApplicationSerializer just call this.serialize() in your model.
If you want absolutely use the toJSON method without overwriting the default DS.Model of your whole app you can still make something like that :
App.CustomModel = DS.Model.extend({
toJSON: function(){
return this.serialize();
}
});
and then make all the concerned model extend this CustomModel
App.Color = App.CustomModel.extend({
name : DS.attr("string")
});
here is a working jsbin
In case you are looking to customize toJSON output for a particular model, you can do the following in your models/user.js file:
DS.Model.extend({
toJSON: function(options){
let json = this._super(options);
// Do something with json
return json;
}
});
Magic of Ember Object structure. In my case, I had to remove a property from toJSON response if it doesn't have value and this worked.

Unwrapping breeze Entity properties

I'm very new to breeze/knockout, but I'm 99% of the way to doing what I need to do. I'm using the Hot Towel template, and I'm successfully retrieving a list of items via breeze. The entity (ITBAL) is a database first Entity Framework entity. When I look at the JSON coming back in Fiddler, I see the correct data. The problem is that all of the properties of data.results are dependentobservables, and not the raw values themselves.
We have a custom grid control that is trying to display the data.results array. Because it is not expecting observables, it is simply displaying "function dependentobservable" instead of the value.
I tried to unwrap the object, but keep getting the circular reference error. I don't know why that is, since ITBAL isn't associated with anything.
The data as Fiddler reports it:
[{"$id":"1","$type":"WebUIHtml5HotTowel.Models.ITBAL, WebUIHtml5HotTowel","IBITNO":"A100 ","IBWHID":"1 ","IBITCL":"50","IBITSC":"3 ","IBSUSP":" ","IBVNNO":"100 ","IBPRLC":" ","IBSCLC":" ","IBCCCD":"P","IBPICD":" ","IBSAFL":"Y","IBSTCS":399.99000,"IBUSCS":0.00000,"IBAVCS":414.95214,"IBLCST":7.00000,"IBLCCC":20.0,"IBLCDT":110923.0,"IBLSCC":20.0,"IBLSDT":130111.0,"IBLXCC":19.0,"IBLXDT":990102.0,"IBMXO1":2100.000,"IBMXO2":0.000,"IBMXO3":0.000,"IBMNO1":5.000,"IBMNO2":0.000,"IBMNO3":0.000,"IBFOQ1":0.000,"IBFOQ2":0.000,"IBFOQ3":0.000,"IBOHQ1":327.000,"IBOHQ2":0.000,"IBOHQ3":0.000,"IBAQT1":1576.000,"IBAQT2":0.000,"IBAQT3":0.000,"IBBOQ1":50.000,"IBBOQ2":0.000,"IBBOQ3":0.000,"IBPOQ1":448.000,"IBPOQ2":0.000,"IBPOQ3":0.000,"IBIQT1":1446.000,"IBIQT2":0.000,"IBIQT3":0.000,"IBRMD1":10.000,"IBRMD2":0.000,"IBRMD3":0.000,"IBRYD1":10.000,"IBRYD2":0.000,"IBRYD3":0.000,"IBISM1":0.000,"IBISM2":0.000,"IBISM3":0.000,"IBISY1":0.000,"IBISY2":0.000,"IBISY3":0.000,"IBAMD1":0.000,"IBAMD2":0.000,"IBAMD3":0.000,"IBAYD1":0.000,"IBAYD2":0.000,"IBAYD3":0.000,"IBMMD1":0.000,"IBMMD2":0.000,"IBMMD3":0.000,"IBMYD1":0.000,"IBMYD2":0.000,"IBMYD3":0.000,"IBSMD1":1.0,"IBSMD2":0.0,"IBSMD3":0.0,"IBSYD1":1.0,"IBSYD2":0.0,"IBSYD3":0.0,"IBBLME":335.000,"IBBLYO":2680.000,"IBBLLY":1441.000,"IBNMTY":8.0,"IBNMLY":11.0,"IBQSMD":21.000,"IBQSYD":21.000,"IBQSLY":20.000,"IBISMD":16318.19,"IBISYD":16318.19,"IBISLY":45714.87,"IBCSMD":373.46,"IBCSYD":373.46,"IBCSLY":67.00,"IBDQMD":0.000,"IBDQYD":0.000,"IBDQLY":0.000,"IBDSMD":0.00,"IBDSYD":0.00,"IBDSLY":0.00,"IBDCMD":0.00,"IBDCYD":0.00,"IBDCLY":0.00,"IBNOMD":18.0,"IBNOYD":18.0,"IBNOLY":18.0,"IBPKMD":15.0,"IBPKYD":15.0,"IBPKLY":14.0,"IBINUS":" ","IBIAID":0.0,"IBSAID":0.0,"IBCQT1":1527.000,"IBCQT2":0.000,"IBCQT3":0.000,"IBFCST":"Y","IBDRSH":" ","IBWMIU":"JP","IBFL15":" ","IBUS20":" ","IBLPR1":0.00000,"IBLPR2":0.00000,"IBLPR3":0.00000,"IBLPR4":0.00000,"IBLPR5":0.00000,"IBLPCD":" ","IBABCC":"B","IBPRCL":0.0,"IBQBCL":" ","IBACDC":"Y","IBTDCD":" ","IBDOUM":" ","IBTP01":0.0,"IBTP02":0.0,"IBTP03":0.0,"IBTP04":0.0,"IBLMCC":20.0,"IBLMDT":130513.0,"IBTMPH":"Y","IBCOMC":" ","IBCOMF":0.00000,"IBITCT":" ","IBEOQT":0.000,"IBITCM":0.0,"IBBRVW":" ","IBPTID":" ","IBQTLT":0.0000,"IBCTY1":"AUS","IBCTY2":"AUS","IBTXCD":"1","IBREVS":"Y","IBITXC":" ","IBMNOQ":0.000,"IBSTUS":0.000,"IBUS30":" ","IBPSLN":" ","IBPLIN":"N","IBUPDP":"Y","IBDFII":"2011-08-11T00:00:00.000","IBLHRK":"A","IBPLNC":" "}]
My Controller:
[BreezeController]
public class ItemInquiryController : ApiController
{
readonly EFContextProvider<AplusEntities> _contextProvider = new EFContextProvider<AplusEntities>();
[System.Web.Http.HttpGet]
public string Metadata()
{
return _contextProvider.Metadata();
}
[HttpGet]
public IQueryable<ITBAL> ItemBalances(string itemNumber, string warehouse)
{
return _contextProvider.Context.ITBALs.Where(i => i.IBITNO == itemNumber && i.IBWHID == warehouse)
.OrderBy(i => i.IBWHID)
.ThenBy(i => i.IBITNO);
}
}
The relevant portion from the viewmodel:
var manager = new breeze.EntityManager("api/ItemInquiry");
var store = manager.metadataStore;
var itbalInitializer = function (itbal) {
itbal.CompositeKey = ko.computed(function () {
return itbal.IBITNO() + itbal.IBWHID();
});
};
store.registerEntityTypeCtor("ITBAL", null, itbalInitializer);
var index = "0" + (args.pageNum * args.pageSize);
var query = new breeze.EntityQuery("ItemBalances")
.withParameters({ itemNumber: "A100", warehouse: "1" })
.take(args.pageSize);
if (index > 0) {
query = query.skip(index);
}
manager.executeQuery(query).then(function (data) {
vm.itbals.removeAll();
var itbals = data.results;//[0].Data;
itbals.forEach(function (itbal) {
vm.itbals.push(itbal);
});
vm.totalRecords(1);
itemBalancesGrid.mergeData(vm.itbals(), args.pageNum, parseInt(vm.totalRecords()));
}).fail(function (e) {
logger.log(e, null, loggerSource, true, 'error');
});
I figure I must be missing something fairly simple, but it is escaping me.
UPDATE: I removed the BreezeController attribute from the ApiController, and it works correctly.
Jon, removing the [Breeze] attribute effectively disables breeze for your application so I don't think that is the long term answer to your problem.
If you don't actually want entities for this scenario - you just want data - than a Breeze projection that mentions just the data to display in the grid would seem to be the best choice. Projections return raw data that are not wrapped in KO observables and are not held in the Breeze EntityManager cache.
If you want the data as cached entities and you also want to display them in a grid that doesn't like KO observable properties ... read on.
You can unwrap a KO'd object with ko.toJS. However, the grid is likely to complain about circular references (or throw an "out of memory" exception as some grids do) ... even if the entity has no circular navigation paths. The difficulty stems from the fact that every Breeze entity has an inherent circularity by way of its entityAspect property:
something.entityAspect.entity //'entity' points back to 'something'
Because you are using Knockout for your model library and because you say ITBAL has no navigation properties ("is not related to anything"), I think the following will work for you:
manager.executeQuery(query).then(success) ...
function success(data) {
var unwrapped = ko.toJS(data.results).map(
function(entity) {
delete entity.entityAspect;
return entity;
});
vm.itbals(unwrapped);
vm.totalRecords(1); // huh? What is that "parseInt ..." stuff?
itemBalancesGrid.mergeData(vm.itbals(), args.pageNum, parseInt(vm.totalRecords()));
})
ko.toJS is a Knockout function that recursively unwraps an object or collection of objects, returning copies of values. Then we iterate over the copied object graphs, deleting their entityAspect properties. The array of results is stuffed into the vm.itbals observable and handed along.
You can imagine how to generalize this to remove anything that is giving you trouble.
Extra
What the heck is vm.totalRecords? I sense that this is supposed to be the total number of matching records before paging. You can get that from Breeze by adding .inlineCount() to the breeze query definition. You get the value after the query returns from the data.inlineCount property.
Do you really need vm.itbals()? If all you do here is pass values to the grid, why not do that and cut out the middle man?
The following success callback combines these thoughts
function success(data) {
var unwrapped = ko.toJS(data.results).map(
function(entity) {
delete entity.entityAspect;
return entity;
});
itemBalancesGrid.mergeData(unwrapped, args.pageNum, data.inlineCount);
})