If graphql query schema is like this:
user(user_id: Int): User
Will apollo run resolver if in query will be additional (email) argument not defined in query schema?
I want iterate arguments in resolver, but not sure if it possible to pollute them.
P.S. If there is documentation of how apollo parcing arguments, will appreciate.
In GraphQL, a schema defines what fields are available to the client, including what arguments are available for that field and what the types of those arguments are. Any query submitted to a GraphQL service will first be validated before it's executed. If the query includes any extraneous arguments, it will fail validation and won't be executed. This is explained here in the spec:
Formal Specification
For each argument in the document
Let argumentName be the Name of argument.
Let argumentDefinition be the argument definition provided by the parent field or definition named argumentName.
argumentDefinition must exist.
Explanatory Text
Every argument provided to a field or directive must be defined in the set of possible arguments of that field or directive.
For a better idea of how GraphQL works, I would suggest taking at least a cursory look through the spec.
Related
I have an AppSync API that's mostly backed by a DynamoDB store. Most of the resolvers are hooked up directly to the DynamoDB sources, not using lambdas.
Some of the fields should have validation constraints, such as length or a regexp. In one particular case I would like to require that a state field contain an ISO 3166-2 value like US-NY. (GraphQL enums values can't contain hyphens, so that isn't an option here.)
Other than replacing some resolvers with lambdas, the only way I can think of to apply these sorts of validation rules is to do it in VTL in the RequestMappingTemplate. That would work, but it would be tedious and likely result in duplicate code. Are there alternatives?
Unfortunately, only way without lambda is VTL , I suggest that instead of writing validation directly inside RequestMappingTemplate, using pipeline resolver.(less duplicated)
Pipeline Resolvers contain one or more Functions which are executed in order.
Functions allow you to write common logic for reuse across multiple Resolvers in your schema. They are attached directly to a data source and like a Unit resolver, contain the same request and response mapping template format.
You can find a good example here.
I am in the process of learning GraphQL and have stumbled upon understanding the difference between Operation Arguments and GraphQL variables. Because IMO, both provide, client, the facility to pass in dynamic data to either mutations or queries etc.
Can someone enlighten me ?
Cheers!
Arguments and variables serve completely different functions.
Every field in a GraphQL schema can be configured to accept one or more arguments. For example:
query FilmQuery {
film (id: "ZmlsbXM6MQ==") {
id
title
}
}
Here the film field accepts an argument named id. Arguments are used to alter the value a field resolves to. In our example above, the server returns a different Film object based on the id value the client provides.
Arguments accept inputs, which can be either scalars, enums or more complex Input Object Types. Here, we're passing a String value of "ZmlsbXM6MQ==" to the argument. By writing out the value inside the query, we are said to be using a literal value.
There is nothing wrong with using literal values in your queries, but when the value passed to the argument needs to be dynamic, we need something more -- we need variables.
Variables allow us to parameterize and reuse queries. Here's our example, rewritten using a variable:
query FilmQuery($myId: ID!) {
film (id: $myId) {
id
title
}
}
Variables must first be defined at the top of your document, as part of the operation definition. Here we've defined a single variable ($myId) and told GraphQL it's type is ID!. Once defined, variables can then be used anywhere inside the operation. The actual values of any variables used in your document must be sent along with the query itself when the client actually makes the request to the server.
Again, arguments only provide a way to change how a request is executed, while using variables as inputs to those arguments is what makes a particular query dynamic and reusable.
Please note that you could use string concatenation or template literals client-side to achieve a similar effect to what variables do. You should generally avoid doing so, however, because 1) it unnecessarily creates additional work for the client and 2) serializing inputs yourself, especially complex ones like Input Object Types, can quickly become complicated and error-prone.
I am learning GraphQL and one basic point has me puzzled. I know there is an easy explanation, but I can't find it. Specifically, from the Apollo documentation (https://www.apollographql.com/docs/apollo-server/essentials/data.html#operation):
...it makes sense to name the operation in order to quickly identify
operations during debugging or to aggregate similar operations
together...Operations can be named by placing an identifier after the
query or mutation keyword, as we’ve done with HomeBookListing here:
query HomeBookListing {
getBooks {
title
}
}
If HomeBookListing is the name of the query, what, then, is getBooks? The name of the resolver?
Similarly, when you pass variables to a query, why are there "two levels" of parameters, like this
mutation HomeQuickAddBook($title: String, $author: String = "Anonymous") {
addBook(title: $title, author: $author) {
title
}
}
So, would $title: String, $author: String = "Anonymous" be the variables passed to the query, and title: $title, author: $author variables passed to the resolver?
Of course I can memorise the pattern, but I'm keen to understand, conceptually, what the different pieces are doing here. Any insights much appreciated!
You may find it helpful to review the spec, but what follows is a somewhat shorter explanation:
What is an operation?
There are three operations in GraphQL (query, mutation and subscription). Typically, a GraphQL request consists of only one of these three operations, and it forms the root of the request, or the entry point into the rest of the schema.
Each operation has a single object type associated with it. By convention, these types are named Query, Mutation and Subscription, but their naming is functionally irrelevant to your schema. Other than their association with a particular operation, there's nothing special about these object types -- each has a name, description and fields just like any other object type in your schema. Collectively, we call these three types root operation types.
In your example, the query root type has a field called getBooks. That field is resolved according to the same rules as any other field in your schema. The only special thing about this field is that it's at the root -- there is no "parent" field that was resolved before it.
Operation names are optional because they do not impact the data returned by the server -- they are there generally for debugging purposes (although some clients and tools use them to provide other features, so it's always good to have them). Specifying at least one field name for your root operation type, however, is necessary, otherwise your operation would not actually do anything (i.e. query the server for the data). Again, these fields are your entry point into the rest of the schema and the starting point for your data graph.
Ok, but what about the variables?
According to the spec:
Variables must be defined at the top of an operation and are in scope throughout the execution of that operation.
While we do not initialize a variable inside the document with a value, we do need to define it by telling GraphQL what the type of the variable it is. This allows GraphQL to then validate the usages of your variables throughout the document. For example, if you define a variable as a String and then attempt to use it at an input field that is an Int, validation will fail and your request will blow up before it is even executed.
Variables are always defined as part of the operation definition -- they can be used anywhere in the document, though, even multiple times. So there are no "two levels of parameters" here -- one line is simply the definition, the other line is usage.
A word on semantics
Even though we have a spec, the language around GraphQL has evolved past the terms outlined inside it. The term "query" has taken on multiple meanings that you may encounter while reviewing various docs and articles. It helps to keep these definitions in mind to avoid getting confused:
By convention, we name the root operation type associated with the query operation the Query type
Informally, the fields on that Query (i.e. getBooks) that are often referred to as the "queries" of your schema (just like the fields on the Mutation type are often called the "mutations" of your schema.
The complete request string we send to the server, which includes the whole operation and any relevant fragments is officially called the document. However, we often refer to making a request as querying your server. This has led to the document itself often being called a query, whether the operation is contains is actually a query or a different operation like a mutation.
Let's say I have a mutation which has a type arg. Depending on the value of type I can either make a mutation accept another arg which is an input type or call mutation without it.
How to implement it in graphql? I know that for queries there're #skip and #include directives (for fields, not for args). Is there something similar for mutations? Or should I just specify the additional arg as optional and then do the validation on the server?
There'll be a range of opinions on this. The main problem is that because you can't define unions for input types, you can't model inputs exhaustively at the schema level. By this I mean that if you need deeper validation than just required/not-required, GraphQL's type system won't help you.
At the moment I lean towards handling all complex validation in the mutation function itself. Essentially mark all input arguments as not required and let it fall through to a validation method of your choosing.
For simple mutations, like do_foo_with_bar(bar_id: Int!), i'd still let the schema handle validation. But for more complex things (like an elaborate form), you're going to have an easier time if you do things in code.
I have a schema that receive a timeInterval iput on root query and the pass it to nested levels/resolvers. I'm trying to add validation to that input on root level, so if the validation fails then I should return and error and return null for other fields. The issue is that if I do this on root level then I don't know how to avoid graphql-tools calling nested resolvers (which fails because they don't have the timeInterval variable defined in the obj of each resolver).
Let me know know if you need and schema example and more details, thanks!
This is built in to how GraphQL.js, the reference implementation from Facebook, works. GraphQL-Tools is just a library on top that makes writing resolvers and schemas a bit nicer.
In GraphQL.js, the child resolvers are called whenever the parent resolver returns anything other than null or undefined, or if it throws an error.
So it sounds like in your case you are returning some data but with a single field missing, in which case GraphQL.js has no idea that it should avoid calling nested fields. Having more detail about your schema and resolvers would definitely help me come up with a specific solution.