Conditional args in GraphQL mutations? - graphql

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.

Related

What's the difference between Operation Arguments and GraphQL variables?

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.

Why are there "two names" for each GraphQL query/mutation?

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.

GraphQL custom scalar type for HTML structure

During her brilliant presentation about scaling GraphQL, Leanne Shapton showed some best practices.
One of the most attractive for me was the custom scalar type for HTML structure. On the video it's [10:16]
She proposed using the custom HTML instead of simple String.
I wish you could show your implementation of this scalar or how do you handle these cases as I'm using only String for any HTML structure which doesn't seem to be a perfect way.
I'm asking not for creating scalar types or general information what is it scalar type and so on. Wondering if someone else has HTML handling already and does someone has any working solutions
At a pure GraphQL level, the only thing you can (and must) do is include a definition for the scalar type:
scalar HTML
Once you done that, you can use it as a type as shown in the slide you cite. In queries and results it will appear as some sort of scalar (string or numeric) value.
Different server and client libraries have different ways of dealing with this; there may be a uniform way to map a specific GraphQL scalar type to a native-language object. In graphql-js, a GraphQLScalarType object takes parseValue and serialize functions to convert between the two representations, for example. If you're just using a custom scalar type as a tagged string these can be very simple functions.

Validate a GraphQL schema against another reference schema

I'm not quite sure the wording I should be searching for on this.
I have a GraphQL schema which wraps a group of services using graphql-link-schema to perform the data resolution on the client side. The schema is intended to be built against a separate reference schema. How can I programmatically validate that my implementation matches the reference?
For bonus points- is it possible to determine whether a schema is a superset of another?
Thanks in advance (:
It's an interesting use case, but it's a bit unclear how validation like that would work. What causes validation to fail? Any differences between the two schemas? Extra types? Extra fields on existing types? Differences in return types? Differences in arguments or argument types?
Depending on your answer to the above questions, though, you may be able to cobble together your own validation function using the utility functions available here. Outside the main findBreakingChanges function, some of the utility functions available in that module:
findRemovedTypes
findTypesThatChangedKind
findFieldsThatChangedTypeOnObjectOrInterfaceTypes
findFieldsThatChangedTypeOnInputObjectTypes
findTypesRemovedFromUnions
findValuesRemovedFromEnums
findArgChanges
findInterfacesRemovedFromObjectTypes
If you have a reference or base schema available, though, rather than validating against it, you might also consider extending it when building the second schema. In doing so, you would effectively guarantee that the second schema matches the first except in whatever ways you intentionally deviate from it (by extending existing types, etc.). You could use extendSchema for relatively simply changes, or something like graphql-tool's mergeSchemas for more complicated changes.

validate request input phoenix elixir

I'm struggling to find something in the documentation that seems like it should be there...
In Phoenix I see validation at the point of trying to create an Ecto change set, but I'm not seeing much prior to that, upon validating the actual user input.
I'm not really a fan of exposing my data models across API boundaries, and I would rather just have structs representing the requests and responses, as they are likely very different shapes to my actual data models.
I'd like a way of converting user input to a struct and using some kind of validation framework to determine if the input is valid before I even think about hitting a database.
I've found https://github.com/CargoSense/vex and have gone down the route of converting the input to a struct, and using their validation, but there are a few things that worry me about this approach, namely:
I hear that there are issues with atoms in Elixir, and as structs are basically atom keyed maps, am I going to run into this atom exhaustion issue converting user input to these?
I also have some structs that would have nested structs. I'm currently checking the default value provided. If it's a struct doing some magic, based on the answers here In Elixir how do you initialize a struct with a map variable, to automatically convert a nested map to my nested struct. But again, I'm not sure if this is sensible.
The validations I'm defining in one DSL will be very similar in my Ecto models, and I would rather be using this for both.
Basically, how would you go about validating user input correctly in a Phoenix app. Am I on the right lines, or way off?

Resources