I can only query with primary keys in GraphQL on Appync? - graphql

This problem is boggling my mind.
I'm trying to query an RDS table with a non-primary key inside a graphql query.
Here is the example of two of my queries in appsync
query getloc{
getLocationByCounty(County: "County"){
LocationsID
State
County
}
}
query getLocations{
getLocation(LocationsID: 1){
LocationsID
State
County
}
}
The second query here works, and returns exactly the county with that LocationID.
The first returns the error message: "Cannot return null for non-nullable type: 'Int' within parent 'Locations' (/getLocationByCounty/LocationsID)"
If I change the schema for locations and make LocationsID non-nullable the error goes away, but it
returns null.
{
"data": {
"getLocationByCounty": {
"State": null
}
}
}
My request resolver for the getLocationsByCounty is:
"version": "2018-05-29",
"statements": ["select * from Locations where County = '$ctx.args.County'"]
Here is the response resolver:
## Raise a GraphQL field error in case of a datasource invocation error
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Is this just not allowed in graphQL or is am I doing wrong???
It's worth noting that if I just do this query:
select * from Locations where County = 'County'
in mySQL, it works exactly as intended.

Related

Passing variables from mutation to query

I have a GraphQL mutation that creates an item and returns the data that's created. I need to pass some of the created fields into a query. Is this possible? This is almost working but I can't figure out how to get the data between the mutation and the query:
mutation {
createToken(
input: { tokenname: "my token", tokendescription: "my valuable token" }
) {
id
randomdata
}
insert__helloworld_article(objects: [{randomdata: "Hello" , author_id: 1}]) {
returning {
id
}
}
}
So my problem is getting "randomdata" from the mutation to insert into the helloworld_article
You wouldn't be able to use the return value in the same mutation with GraphQL, however if those objects have a relationship you could do a nested insert.

Why can I execute mutation function with null parameter with type being `String!`?

Simple table with one two rows. ID (incrementing int) and test_value (TEXT, nullable).
1. Query
query getData($test_value:String!) {
testtable(where: {test_value: {_eq: $test_value}}) {
test_value
}
}
Variables
{"test_value":null}
Result
{
"errors": [
{
"extensions": {
"path": "$.selectionSet.testtable.args.where.test_value._eq",
"code": "validation-failed"
},
"message": "unexpected null value for type \"String\""
}
]
}
This is a correct that I expect.
2. Mutation
mutation InsertData($test_value: String!) {
insert_testtable(objects: {test_value: $test_value}) {
affected_rows
}
}
Variables
{"test_value":null}
Result
{
data: {
insert_testtable: {
affected_rows: 1
}
}
}
I expect and error (because of test_value:String! declaration), but I don't get it.
Why?
P.S.
testable schema looks like this:
id: Int!
test_value: String
My understanding of your issue: Your schema has a mutation insert_testtable that takes a nullable String argument. When you submit a named mutation operation with a non-nullable String! variable, the GraphQL server does not respond with an error.
The GraphQL spec says that is the expected behaviour for mutations and queries. The spec says that if the type in the schema is nullable and of the same type as the variable, the operation is to be considered valid. This is what's happening for your mutation.
If you are not seeing the same behaviour for the query, it is possible that your GraphQL server implementation differs from the spec. You could check your server docs or their GitHub Issues.
For what it's worth, I checked that AppSync, AWS's GraphQL implementation, produces the expected behaviour for both queries and mutations.

Postman, test Graphql response

I have this query:
query SessionQuery {
cliente {
id
clienteId
rut
porcentajeDeCompletitudDeInformacion
fichaCliente {
tipoPersona
razonSocial
}
representantesLegales {
edges {
node {
rutRepresentante
}
}
}
documentosRequeridos {
edges {
node {
iDDocumento
cargado
nombreDocumento
tipoDocumentoHQB
}
}
}
}
usuario {
id
usuarioId
email
nombre
rut
}
}
I'm testing for the first time GraphQL through Postman, like this way:
I'm having this response, I don't understand the error message:
{"data":{"cliente":{"id":"Q2xpZW50ZTow","clienteId":0,"rut":"XXX","porcentajeDeCompletitudDeInformacion":20,"fichaCliente":{"tipoPersona":2,"razonSocial":"ING. Y SISTEMAS BIZWARE (Empresa Relacionada)"},"representantesLegales":{"edges":[{"node":{"rutRepresentante":null}}]},"documentosRequeridos":{"edges":[]}},"usuario":{"id":"VXN1YXJpbzoyMDI4","usuarioId":2028,"email":"XXXX#gmail.com","nombre":"XXXX","rut":"XXXX"}},"errors":[{"message":"GraphQL.ExecutionError: Cannot return null for non-null type. Field: rutRepresentante, Type: String!.\r\n at GraphQL.Execution.ExecutionStrategy.ValidateNodeResult(ExecutionContext context, ExecutionNode node)\r\n at GraphQL.Execution.ExecutionStrategy.ExecuteNodeAsync(ExecutionContext context, ExecutionNode node)","locations":[{"line":14,"column":11}],"path":["cliente","representantesLegales","edges","0","node","rutRepresentante"]}]}
I not sure what it means the error. My problem is when I call this Graphql endpoint from JavaScript I have a CORS problem in my app, but I detected with Postman that maybe the problem is this one, and the query or something is broken. Any idea please, thanks.
xadm's comment is correct - in a standard GraphQL schema, the exclamation point means that the field is required. It's likely that the rutRepresentante field is NULL for the database record that your query retrieves.
Either remove the exclamation mark from String! in order to make the field nullable, or populate the row in the database for the rutRepresentante column (or key, if you're not using SQL...)

Handle graphql schema stitching error in child query

I am new to graphql and want to understand the concept here. I have this graphql schema (stitched using graphic-tools). Not all cars have registration. So if I query for 5 cars and one car doesn’t have a registration (no id to link between cars and registration), my whole query fails.
How do I handle this and return null for that 1 car and return registration details for the other 4?
{
Vehicles {
Cars {
id
registration {
id
}
}
}
}
If you mark a field as non-null (by appending ! to the type) and then resolve that field to null, GraphQL will always throw an error -- that's unavoidable. If it's possible for a field to end up null in the normal operation of your API, you should probably make it nullable.
However, errors "bubble up" to the nearest nullable field.
So given a schema like this:
type Query {
cars: [Car!]!
}
type Car {
registration: Registration!
}
and this query
{
cars {
registrations
}
}
resolving the registration field for any one Car to null will result in the following because the cars field is non-null and each individual Car must also not be null:
{
"data": null,
"errors": [...]
}
If you make the cars field nullable ([Car!]), the error will stop there:
{
"data": {
"cars": null
},
"errors": [...]
}
However, you can make each Car nullable (whether the field is or not), which will let the error stop there and result in an array of objects and nulls (the nulls being the cars that errored). So making the cars type [Car]! or [Car] will give us:
{
"data": {
"cars": [{...}, {...}, null]
},
"errors": [...]
}

Apollo GraphQL: Resolver not called on mutation subfield

I am trying to return a Query type from a mutation, which I could make work in some cases but not the way I want it. The problem is not particularly related to the Query type being used, as I found the same behaviour using other types than Query.
You can run and modify this code on https://codesandbox.io/s/1z8kjy8m93
Server
const { ApolloServer, gql } = require("apollo-server");
const typeDefs = gql`
type Query {
hello(msg: String): String
}
type Mutation {
someMutation(someArg: String): MutationResponse
}
type MutationResponse {
query: Query
status: String
}
`;
const resolvers = {
Query: {
hello: (root, args, context) => {
console.log("hello: args = ", args);
return `${args.msg}, world !`;
}
},
Mutation: {
someMutation: (root, args, context) => {
console.log("someMutation: args = ", args);
return { status: `Mute Mute: ${args.someArg}` };
}
}
};
const server = new ApolloServer({
typeDefs,
resolvers
});
server.listen().then(({ url }) => {
console.log(`🚀 Server ready at ${url}`);
});
Mutation
mutation mutateMe($mutationArg: String = "YoloMute !", $helloMsg: String = "Yolhello") {
someMutation(someArg: $mutationArg) {
status
query {
hello(msg: $helloMsg)
}
}
}
Response
{
"data": {
"someMutation": {
"status": "Mute Mute: YoloMute !",
"query": null
}
}
}
I don't understand why the hello resolver is not called and the query field is null.
The status field is duly filled by the someMutation resolver, but as the query field is not resolved there I would expect GraphQL to call an existing resolver for this field, which exists and should be called for the Query type.
I found other ways that technically work but are not satisfying:
Directly returning the Query type works:
https://codesandbox.io/s/ovr9zpwr7q
Duplicating lines in the schema
works: https://codesandbox.io/s/l4yrqzmq6l
This issue isn't really specific to the Query type, but rather deals with how you've set up your resolvers.
The status field is duly filled by the someMutation resolver, but as the query field is not resolved there I would expect GraphQL to call an existing resolver for this field, which exists and should be called for the Query type.
There is no resolver for the entire Query type, or any other type. Resolvers exist only for individual fields of a particular type. When a resolver isn't defined for a field, GraphQL will default to looking for a property on the parent object with the same name as the field, and will return the value of that property.
Let's walk through your document. The root-level field is:
someMutation(someArg: $mutationArg)
The parent value is the root value for all root-level mutations. Unless you're using a custom root value, this will typically be an empty object. If you didn't define a resolver for the someMutation field of the Mutation type, GraphQL would look for a property called someMutation in your root value and return that (i.e. undefined, which would be coerced to null in the response). We do have a resolver, though, and it returns:
{
status: `Mute Mute: ${args.someArg}`,
}
Now, let's resolve the status field. Our parent object is the result returned by the parent field's resolver. In this case, the object above. We have no resolver for status on MutationResponse, so GraphQL looks for a status property on the parent -- it finds one and uses that. status has a Scalar type, so whatever value is returned by the resolver will be coerced into the appropriate scalar value.
What about the query field? Again, we have no resolver for a query field on the MutationResponse. However, we also don't have a property called query on the parent object. So, all GraphQL can do is return null for that field.
Even though the return type for query is an ObjectType, because it resolves to null, any resolvers for fields on that ObjectType will not be fired. Returning null means the object doesn't exist, so we don't need to bother resolving any fields on it. Imagine if a field returned a User object. If it returned null, there would be no need to resolve the user's name, for example.
So... how do we get around this? There's two ways:
Either add a property for query to the object returned by someMutation's resolver, like this:
{
status: `Mute Mute: ${args.someArg}`,
query: {},
}
Or, add a resolver for the field:
MutationResponse: {
query: () => {},
},
Either way will ensure that the query field will resolve to a non-null value (in this case, just an empty object). Because the value resolved is not null and the return type is an ObjectType (in this case Query), now the resolvers for that type's fields will be triggered and hello will resolve as expected.

Resources