GraphQL: Apollo Server subscription with namespace - apollo-server

I know it's somehow best practice to keep mutations and subscription on top-level and not introduce namespace types.
But anyway I would be interested how a subscription with a namespace could be implemented in Apollo Server.
For example the following case:
type Subscription {
imageAPI: ImageAPISubscriptions!
contentAPI: ContentAPISubscriptions!
}
type ImageAPISubscriptions {
subscribeImageChanges(imageId: ID!): ImageChanges!
}
...
Now apollo complains that in the resolver for this subscription, the top-level function e.g. imageAPI doesn't return an AsyncIterator because this happens in the nested subscribeImageChanges function.
How can this be technically solved?
I'm using apollo-server-express 2.4.8.

Related

Sending dynamic number of mutations at once

Is there a standard way to send a dynamic number of mutations in the same request with Apollo client ?
I have to deal with a Graphql API that only expose a single delete mutation, and I'd like to call it with multiple ids. Here's how it's defined:
mutation DeleteItemById($id: Int) {
delete_item(id: $id) {
id
}
}
From what I read, I could do something like
mutation DeleteItemById($id_1: Int, $id_2: Int) {
delete_item_1: delete_item(id: $id_1) {
id
}
delete_item_2: delete_item(id: $id_2) {
id
}
}
But how could I generate such a query dynamically ? Is it a good practice anyway ? I always read it was not a good idea to dynamically generate graphql queries.
Plus, I'm using graphql-codegen and statically defining queries in .graphql files, so I imagine it will have trouble parsing dynamic ones.
In general it's a bad idea to generate GraphQL queries dynamically. A good way to deal with this is to create a new mutation that supports multiple ids, validate and delete all in the same batch, like:
type Mutation {
deleteItems(ids: [String!]!): Boolean!
}

Ability to extend all Apollo/GraphQL mutations with same fields. "Generic fragments" wanted

Problem definition
In the project I'm currently working on we're using React with Apollo Client.
On all our mutations, we have the following fields in our response:
ok
errors {
field
messages
}
The back-end extends all mutations with these fields, hence it would be nice to have a good, short way to include these fields on all mutations in the front-end, as well as be able to change this "fragment" in the future.
Hence I'm interested in shortening these same 4 lines into 1 across all my mutations.
What I've tried so far:
I've tried looking into Apollo fragments, however they seem to require a type that the fields are on or "relating to", eg.
fragment NameParts on Person {
firstName
lastName
}
Here, the frament NameParts is created using Person. However, I'm interested in extending ALL mutations.
It would be nice if I could make a generic fragment like so:
fragment OkAndErrors {
ok
errors {
field
messages
}
}
This does not seem to be possible.
I've also tried making a string, and importing it into my mutation like so:
export const OK_AND_ERRORS: string = `
ok
errors {
field
messages
}
`;
import { gql } from "apollo-boost";
import { OK_AND_ERRORS } from "./OK_AND_ERRORS";
export const CREATE_API = gql`
mutation CreateApi($newApi: ApiCreateGenericType!) {
createDrugapi(newDrugapi: $newDrugapi) {
${OK_AND_ERRORS}
(...rest of mutation is omitted for brevity)
}
}
`;
Again, it did not work.
I'm not sure if I can use gql function in a smart way with strings or JSON?
There's also inline fragments but I'm in doubt if it can be used for what I need, and the documentation of inline-fragments in Apollo is scarce.
In essence: Is there a smart way to extend Apollo mutations? Does generic fragments exist?
First of all, fragments aren't limited to Apollo but are part of just regular GraphQL queries. The GraphQL site itself actually has a nice explanation of them: https://graphql.org/learn/queries/#fragments
Essentially we can put fragments onto any query to extract data dependencies, but they're also useful for matching types using their on X type conditions.
In your case, you're saying that each mutation returns a kind of result type that has a common errors field. This tells me that you may have a MutationError kind of type already. However these MutationResult types that all have an errors fields should all implement an interface, if they don't already.
Interfaces are a great tool in the schema language to define explicitly that a type implementing it must always include a certain set of fields, in this case the errors fields. This means that we'd write our results like so:
interface MutationResult {
errors: [MutationError!]
}
type ExampleMutationResult implements MutationResult {
ok: Boolean
errors: [MutationError!]
}
type UserMutationResult implements MutationResult {
user: User
errors: [MutationError!]
}
As you can see above, the MutationResult interface is now implemented by several results, which allows me to write a reusable fragment that can be applied to any type that implements it, e.g.
fragment MutationResultErrors on MutationResult {
errors {
field
messages
}
}
Which I can then start using for all mutation queries that I'm defining. This is more predictable and expected in GraphQL rather than doing some client-side document transformations, string interpolations in a query, or something similar, as it'll be baked into your schema.
Side note: What I'd also say is, I've found that it's commonly seen that people have started to split their mutations into "errors" and "results" and made some kind of union or interface to differentiate between the two. But often they then implement generic errors with messages. It's important to say that errors that don't carry any relational data are actually already baked into GraphQL: https://spec.graphql.org/June2018/#sec-Errors

Apollo GraphQL fails to invoke resolver for a nested field

I've the following structure in my schema:
type gn_Feature implements Some_Interface {
s_description: String
s_id: URL!
some_parent: gn_Feature
}
As you can see, each gn_Feature has an another linked gn_Feature object (the linking is handled elsewhere, it doesn't really matter). By my current understanding, you only need to define the resolvers for the return types, so my resolvers look like the following:
export const resolvers = Object.assign(
{},
{
DateTime: DateTime,
Date: DateTime,
Time: RegularExpression("Time", /^\d{2}:\d{2}(:\d{2})?$/),
URL,
Query: {
gn_Feature: gn_FeatureResolver
},
gn_Feature: gn_FeatureResolver
}
);
But, my queries fail with the following error if I don't explicitly define the resolver for the nested field, like so:
gn_Feature: {some_parent: gn_FeatureResolver}
Error:
"message": "Resolve function for \"gn_Feature.s_description\"
returned undefined"
My resolver function doesn't even get invoked for my nested object when I don't specify it like the above.
My backend consists of some voodoo transpiling of GraphQL queries into SparQL queries which return data back so I won't post the resolver code as I utilize one universal resolver for many fields. I'd like to avoid having to specify resolvers for each nested field as that's going be extremely tedious (I have dozens of types with dozens of fields). Any clarifications are welcome, as I'm completely baffled.
Example GraphQL query:
gn_Feature(some_field:"AD", last:2){
s_description,
s_id
some_parent{
s_description
}
}
When executing a query, only the value of any particular field is initially unknown and needs to be resolved... everything else, like the types, selection sets, etc. is already known. A resolver is a function called to resolve a specific field. In GraphQL.js, there are no resolvers for types.
Apollo muddies the waters a bit in this regard, since for convenience, the API for makeExecutableSchema allows you to define custom scalars by including them in the resolver map. Additionally, even though interfaces and unions don't have resolvers either, Apollo lets you use the resolver map to specify a __resolveType function for these abstract types as well. Apollo's docs actually define a resolver as "a function that connects schema fields and types to various backends." However, in the context of GraphQL in general, you should think of a resolvers as "a functions that resolves the value of a field".
So, given a type called gn_Feature and a field called some_parent, this is the correct way to structure your resolvers:
const resolvers = {
gn_Feature: {
some_parent: someResolverFunction
}
}
Also note that Query and Mutation are both types themselves, so if you have a query called gn_Feature, you are actually resolving a field called gn_Feature for the Query type.

Graphql, nodejs, how to resolve non-root level query field based on if it is queried?

I'd like to resolve a field called 'outstandingBalance' in Client type. If front-end query:
query {
Client {
id
name
outstandingBalance
}
}
The resolver function for outstandingBalance is expensive to run. If front-end query:
query {
Client {
id
name
}
}
Then, don't trigger the resolver for 'outstandingBalance'. I have basic understanding of graphql and read most of its official document. But have not seen an answer to this pattern, or this way of using Graphql is not allowed?
Question
Is there a thing called "Nont-root level resolver" for graphql? like the 'outstandingBalance' field in Client type?
Question: How to implement in graphql? Especially using resolver:
async function outstandingBalance(obj, args, context, info) {
console.log('called...')
}
to query one field in one type based on if this field is queried?

naming your graphql mutations in react-apollo

consider the following
const createBob1 = gql`
mutation createBob2($var: data) {
createBob3(var: $var) {
id
}
}
`
at three levels, we're naming the mutation:
createBob1 defines the graphql document
createBob2 defines the apollo mutation
createBob3 defines the graphql resolver function to call
(I think?)
Has anyone settled on a naming convention for how to keep all three names consistent? Do you name them all the same?

Resources