Tips for combining data from various sources in GraphQL

Need some guidance on setting up GraphQL as a beginner. I am facing challenges in efficiently setting up resolvers for my schema, especially when dealing with fields from different backend APIs.

type User {
   name: String
   address: String
   dateOfBirth: String
   department: String
   function: String
   manager: String
}

Fields like name, address, and dateOfBirth are retrieved from a basic administration system, while the other fields come from an organizational database.

Query {
  User(parent, args, ctx) {
    return {
       name: '....',
       address: '...',
       dateOfBirth: '.....'
    }
  }
} 

If each subfield is resolved individually, it would result in multiple requests when all fields are requested. To optimize this, I want to structure my schema in a way where similar fields can be fetched together in one API call.

type User {
   name: String
   address: String
   dateOfBirth: String
   organisation: Organisation
} 
type Organisation {
   department: String
   function: String
   manager: String
}

This approach reduces the number of requests made to the Organization API. However, it does make the schema look a bit unusual as these fields should ideally belong to a nested object structure. Additionally, any future changes in the data sources could potentially break the schema.

I experimented with using a dataloader to batch the fields, but it seems more suited for resolving n+1 problems rather than batching different field types.

Looking for suggestions on how to tackle this challenge effectively. Any advice would be greatly appreciated.

Answer №1

In the context of resolving data in GraphQL, whatever is resolved on the parent resolver will be passed down to the child resolvers. For example, in the User resolver, you can simply do:

Query {
  User(parent, args, ctx) {
    //Call your API here that returns the organization fields
    const organization = getOrganizationFields();
    return {
       ...organization,
       name: '....',
       address: '...',
       dateOfBirth: '.....'
    }
  }
} 

Then, in the child resolvers (field resolvers), this information will be accessible and you can retrieve it like so:

User {
   department(parent, args, ctx) {
     return parent.department
   }
   manager(parent, args, ctx) {
     return parent.manager
   }
}

Some implementations like graphql-js handle these "unitary" resolvers implicitly, saving you from having to write them out explicitly. However, if you need to batch or cache API requests, using a DataLoader would be recommended.

Answer №2

Here is a potential schema to consider:

type User {
   name: String
   address: String
   dateOfBirth: String
   organisation: Organisation
} 
type Organisation {
   department: String
   function: String
   manager: String
}

These are my resolvers for the subfield:

User {
   organisation {

      // retrieve data from organisation service using parent.id
      
      return {
         department: '...',
         function: '...'
         manager: '...'
      }
   }
} 

The request to the Organisation API is now only made once.

You're making good progress with GraphQL where you can request only necessary information.

Albert's [user level resolver] observation about overfetching may be correct with a single datasource (one SQL request with joins).

Nevertheless, the schema seems odd: those fields should belong to a sub-object.

True, but there are ways to resolve it in this manner.

If we were to separate manager data into its own API, changing the schema would cause issues if it's taken out of the sub-object Organisation.

Yes... you probably need a more structured schema.

... you might be:

  • considering this schema from an existing service/BE perspective;
  • adding the complexity of breaking changes/API versioning to this context;

... however, you can already define 'the right schema', for example

type User {
  name: String
  address: String
  dateOfBirth: String
  role: Role
} 
type Role {
  organisation: Organisation
  function: String
}
type Organisation {
  department: String
  manager: User

}

... assuming only one role per user ... use array otherwise

In this scenario, role and organisation subobject can be resolved with just one call to the organisation service - simple

return {
  function: "team lead",
  organisation: {
    id: "someDeptID",
    department: "some",
  }
}

...if your query requires the manager field, then it should (must) be resolved by the Organisation.manager resolver. Of course, you can also handle it there (in the role resolver) if the data has already been fetched/available.

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

In JavaScript, use the href property to redirect to an external URL and then automatically scroll to a specific class on the page

I have a specific scenario where I need to create a link that redirects to an external website, of which I do not own. However, I am aware that there is a div with a particular class located at the bottom of their page, linking to an article. My goal is to ...

Guide on how to return a JSON result as a Dictionary instead of an Array using Express.js

I need to format my response as a dictionary with specific key-value pairs, like so: { "id": 5928101, "category": "animal welfare", "organizer": "Adam", "title": "Cat Cabaret& ...

A TypeScript method for accessing deeply nested properties within an object

I'm currently working on a function that utilizes typings to extract values from a nested object. With the help of this post, I managed to set up the typing for two levels successfully. However, when I introduce a third (known) level between the exis ...

Can you tell if there are any distinctions between the two code snippets?

Initial Code console.log('Begin'); // output 1 await axios({ method: 'post', url: '<HTTP_URL>' data: <SOME_DATA>, }).then ((response) => { // Performing some action... This may take a few seconds. con ...

What could be causing SVG to not render in a NEXTJS project upon deployment on Vercel?

Recently, I created a standout single-page nextJS application that was beautifully styled with Tailwind CSS. One interesting feature I added was incorporating the background of a component called SectionWrapper as an svg file. To achieve this, I crafted a ...

Utilize Vue.js methods to reverse the string within a paragraph using the appropriate function

Hello everyone, I've been attempting to implement a function to reverse a string within a paragraph text in vue.js. I've created a method called reverseword to reverse the words and added it to a card using :rule="reverseword()", but un ...

The method of inserting a JSON dates object to deactivate specific days

I am currently utilizing a date picker component that can be found at the following link: While attempting to use the disabledDays section below, I have encountered an issue where I am unable to apply all three options. The blockedDatesData option works o ...

Issues with Fetch API and CORS in Web Browsers

Hello, I'm encountering an issue related to CORS and the Fetch API when using browsers. Currently, my setup involves running a NodeJS server built with Express on localhost:5000. This server responds to a GET request made to the URL /get_a, serving ...

Managing VueJS components and Observers during the rendering process to ensure smooth functionality in a multi-phase environment

Situation: As part of my development work, I am creating a Vue scroll component that encompasses a variable number of HTML sections. This component dynamically generates vertical page navigation, allowing users to either scroll or jump to specific page lo ...

Displaying content on a webpage using PHP, AJAX, and HTML

Looking to update my current form setup. I have a basic Form below: <form action="" method="POST"> <input type="button" value="Generate Numbers" onclick="on_callPhp1()"/> </form> Accompanied by this javascript code: <script type="te ...

Position a dynamic <div> in the center of the screen

My goal is to design a gallery page with a list of thumbnails, where clicking on a thumbnail will open the related image in a popup div showing its full size. The issue I'm facing is how to center the popup div on the screen, especially when each pic ...

Manipulating DropDownList Attributes in ASP.NET using JavaScript

I am facing an issue with populating a Dropdownlist control on my ASCX page. <asp:DropDownList ID="demoddl" runat="server" onchange="apply(this.options[this.selectedIndex].value,event)" onclick="borderColorChange(this.id, 'Click')" onblur="bo ...

Utilizing Javascript to initiate an AJAX call to the server

I am creating an application similar to JSbin / JS fiddle. My goal is to update my database by making an ajax request to the server when the user clicks on the save code button and submits the values entered in the textarea. However, I seem to be encount ...

Tips for switching images in a grid using jQuery

I have implemented an image grid using flexbox on a website I am developing. The grid consists of 8 boxes, and my goal is to randomly select one box every 2 seconds and assign it one of 12 random images. My strategy involves creating an array containing UR ...

Only display entries with no content

When attempting to filter data from a search, all results are being displayed on the submit button even when entering 1, 2, or 3. Here is my code below. Please let me know if I am making a mistake somewhere. ...

Utilizing PUG for Iterating Through Multiple Items in Express Framework using JSON Data

I'm currently working on a small application using Express and PUG, aiming to achieve the following: https://i.stack.imgur.com/ZDyTK.png index.pug ul#restaurants-list li img.restaurant-img(alt='Mission Chinese Food', sr ...

Is it possible to display a React Component code within a <code> tag?

I am in the process of creating a tester page that allows users to interact with a library component and document how it is being used. Here is the library component: render = () => { let component = ( <Slider onSlid ...

How to use JQuery to parse an external JSON file with array elements in Javascript

My goal is to extract information from an external JSON file using JavaScript, specifically an array and other elements. The JSON file I am working with is called 'TotalUsers.json' {"@version":"1.0", "@generatedDate":"12/20/10 5:24 PM", "day":[{ ...

Unable to eliminate the default styling of Material UI table using an external CSS file

Currently, I am incorporating a Material Ui table into my project. My goal is to eliminate the border and adjust the padding of the table. Upon investigation, I came across a default className for material ui table known as MuiTableCell-root-40. Below is t ...

What is the mechanism behind angular2's spa routing functioning seamlessly without the need for the hash character in the url?

During my experience with the Angular2 "Tour of Heroes" tutorial, I made an interesting observation about how their single page application router functions without a trailing hash symbol (#) in the URL. This differs from the Kendo SPA router, which typica ...