Obtain unfinished designs from resolver using GraphQL Code Generator

In order to allow resolvers to return partial data and have other resolvers complete the missing fields, I follow this convention:

type UserExtra {
  name: String!
}

type User {
  id: ID!
  email: String!
  extra: UserExtra!
}

type Query {
  user(id: ID!): User!
  users: [User!]!
}
const getUser = (id: string): { id: string, email: string, extra: { name: string } => fetchUser(id);

// `fetchUsers` only returns `id` and `email`, but not `extra`
const getUsers = (): { id: string, email: string }[] => fetchUsers();

// we can use this function to fetch the extra field for a given user
const getUserExtra = (id: string): { name: string }  => fetchUserExtra();

export default {
  Query: {
    user: (parent, args) => getUser(args.id),
    users: () => getUsers(),
  },
  User: {
    // here we fetch the `extra` field anytime an `User` is requested
    // in real-life I would check if the query is requesting the `extra`
    // field or not, and only fetch the data if requested by the query
    extra: (parent) => {
      return getUserExtra(parent.id)
    },
  }
}

I am faced with a challenge where GraphQL Code Generator expects the Resolver type to have Query#users return the complete shape of User, even though it may be returned partially due to User#extra eventually completing the shape for the client.

To address this issue while satisfying TypeScript requirements, what approach should I take?

Answer №1

When faced with similar situations, I opt to make the extra field nullable by replacing extra: UserExtra! with extra: UserExtra. There are numerous resources available on how to handle nullability in your Graphql schema (One source and another article that have greatly influenced my approach).

It is likely that the extra fields are handled separately in a different resolver because additional steps are required to retrieve them, such as requesting data from another service or data store. By designating the type as nullable, if the request fails, the schema can still return the rest of the user data with extra set to null instead of discarding all user data due to extra being null which would violate the schema type. The concept of

Non-null fields exaggerating small failures
discussed in this article provides a detailed explanation of this issue. As a tradeoff, client code will need to account for whether extra is null or not, but one could argue that this prompts more graceful handling of potential failure scenarios in client code.

This adjustment also resolves the initial problem at hand, as extra will be an optional type in the generated graphql-code-generator types and your primary user resolver is no longer obligated to include it in its return.

Answer №2

One useful option in the configuration is known as mapper. This allows you to define the specific return type of your resolver to accurately match the output from your code.

It's worth mentioning that GraphQL gives you the flexibility to return different types of data in resolvers. That's where mappers come into play, helping you specify the types for these returns.

To delve deeper into this topic, check out https://github.com/dotansimha/graphql-code-generator/discussions/4030

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leverage the TypeScript Compiler API to verify whether an interface property signature permits the value of undefined (for example, prop1?:

Currently, I am utilizing the TypeScript Compiler API to extract Interface information in order to generate database tables. The process is functioning effectively, however, I am seeking a method to determine if certain fields are nullable, or as it is phr ...

The specified type cannot be assigned to the type 'IntrinsicAttributes & MoralisProviderProps'

I'm brand new to TypeScript and I have a question about setting initializeOnMount to true. Why does it only allow me to set it to false? Here is the error message: Type '{ children: Element; appId: string | undefined; serverUrl: string | undefine ...

Is there a beginner's pack or trial version available for utilizing TypeScript with IBM Cloud Functions / OpenWhisk?

While working on developing actions in IBM Cloud Functions, I have been primarily using Node.js / Javascript and Python for coding. However, I haven't come across specific instructions on how to incorporate TypeScript into IBM Cloud Functions. I am c ...

What is the best way to set the generics attribute of an object during initialization?

Below is the code that I have: class Eventful<T extends string> { // ↓ How can I initialize this attribute without TypeScript error? private eventMap: Record<T, (args?: any) => void> = ? } Alternatively, class Eventful<T extends st ...

Show Timing on the Y-Axis - Bubble Graph

Recently, I stumbled upon the Bubble Chart feature in ng2-charts. I am trying to display data based on time on the Y-axis and values on the X-axis. My dataset consists of x:[10,35,60], y:["7.00 AM"], with r having the same value as x. However, the sample d ...

Using Angular 2 to convert and display data as a particular object type in

I have recently developed a basic application using the Angular2 tutorial as my guide. Initially, I established a straightforward "Book" model: /** * Definition of book model */ export class Book { public data; /** * Constructor for Book ...

Incorporating D3.js into Angular 6 for interactive click events

Currently working on building a visual representation of a tree/hierarchy data structure using d3.js v4 within an Angular environment. I've taken inspiration from this particular implementation https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5e ...

Testing the number of times module functions are called using Jest

As someone who is relatively new to JavaScript and Jest, I am faced with a particular challenge in my testing. jest.mock('./db' , ()=>{ saveProduct: (product)=>{ //someLogic return }, updateProduct: (product)=>{ ...

What is the best way to choose a key from a discriminated union type?

I have a discriminated union with different types type MyDUnion = { type: "anonymous"; name: string } | { type: "google"; idToken: string }; I am trying to directly access the 'name' key from the discriminator union, like thi ...

What is the best way to rid ourselves of unwanted values?

In the laravel-vue-boilerplate package, there is a User CRUD feature. I duplicated this functionality to create an Item CRUD by making some changes and adjustments. Everything is working fine except for one issue: after editing an item, when trying to add ...

The functionality of arguments in the whenAllDone promise/deferred javascript helper seems to fail when attempting to encapsulate existing code within a Deferred

My goal is to implement the solution provided in TypeScript from Stack Overflow: UPDATE 2 - The issue with the original answer is that it does not support a single deferred. I have made modifications to reproduce the error in his fiddle. http://jsfiddle.n ...

Typescript is failing to perform type checking

I'm encountering an issue while trying to utilize TypeScript type checking with the following code snippet: abstract class Mammal { abstract breed(other: Mammal); } class Dog extends Mammal { breed(other: Dog) {} } class Cat extends Mammal { ...

The connection named "Default" could not be located for use with TypeOrm and Express

I am currently facing an issue with my setup involving TypeORM. It seems that Express is being initialized before the connection to the database is established with TypeORM, causing an error message "Connection default not found." Here is a snippet of the ...

Utilize key-value pairs to reference variables when importing as a namespace

Is it feasible to utilize a string for performing a lookup on an imported namespace, or am I approaching this the wrong way? Consider a file named my_file.ts with contents similar to: export const MyThing: CustomType = { propertyOne: "name", ...

Deciphering key-value pairs that are separated by commas

I am looking to convert the following format: realm="https://api.digitalocean.com/v2/registry/auth",service="registry.digitalocean.com",scope="registry:catalog:*" Into this JSON object: { realm: "https://api.digitaloce ...

In JavaScript, constructors do not have access to variables

Currently, I am attempting to implement Twilio Access Token on Firebase Functions using TypeScript. export const generateTwilioToken = functions.https.onRequest((req, res) => { const twilioAccessToken = twilio.jwt.AccessToken; const envConfig = fun ...

Rxjs: Making recursive HTTP requests with a condition-based approach

To obtain a list of records, I use the following command to retrieve a set number of records. For example, in the code snippet below, it fetches 100 records by passing the pageIndex value and increasing it with each request to get the next 100 records: thi ...

retrieve the checkbox formgroup using the Response API

After following a tutorial on creating dynamic checkboxes, I now need to implement dynamic checkboxes using an API request. In my implementation so far, I have defined the structure as shown below: inquiry-response.ts interface Item { // Item interface ...

Tips for implementing the handleChange event with CalendarComponent from the PrimeReact library

Hey there! I'm currently working with the CalendarComponent from the PrimeReact library in my app. I want to update the type of event being typed in the handleChange function instead of leaving it as :any. Can anyone provide some suggestions on what s ...

What is the best way to manage data types using express middleware?

In my Node.js project, I am utilizing Typescript. When working with Express middleware, there is often a need to transform the Request object. Unfortunately, with Typescript, it can be challenging to track how exactly the Request object was transformed. If ...