What is the best way to divide a GraphQL schema to avoid circular dependencies?

I have a question that is similar to the issue of circular dependency in GraphQL code discussed on Stack Overflow, but my problem lies within JavaScript (ES6).

The size of my schema definition has become too large, and I am struggling to find a way to break it into manageable pieces. One approach could be to split the file based on different object types, but this often leads to circular dependencies. This simplified example illustrates the issue:

    // -- file A.js

    import { bConnection, getBs } from 'B';

    export class A { /*...*/ };
    export var getA = (a) => { /*...*/ };
    export var getAs = (array_of_as) => { /*...*/ };

    export var aType = new GraphQLObjectType ({
      name: 'A',
      fields: () => ({
        bs: {
          type: bConnection,
          /*...*/
        },
        resolve: (a, args) => connectionFromPromisedArray (
          getBs (a.bs)
        ),
        /*...*/
      }),
      interfaces: () => [ require ('./nodeDefs').nodeInterface ],
      /*...*/
    })

    export var {
        connectionType: aConnection,
        edgeType: aEdge
      } = connectionDefinitions ({
        name: 'A',
        nodeType: aType
      });

    // -- file B.js

    import { aConnection, getAs } from 'A';

    export class B { /*...*/ };
    export var getB = (b) => { /*...*/ };
    export var getBs = (array_of_bs) => { /*...*/ };

    export var bType = new GraphQLObjectType ({
      name: 'B',
      fields: () => ({
        as: {
          type: aConnection,
          /*...*/
        },
        resolve: (b, args) => connectionFromPromisedArray (
          getAs (b.bs)
        ),
        /*...*/
      }),
      interfaces: () => [ require ('./nodeDefs').nodeInterface ],
      /*...*/
    })

    export var {
        connectionType: bConnection,
        edgeType: bEdge
      } = connectionDefinitions ({
        name: 'B',
        nodeType: bType
      });

    // -- file nodeDefs.js

    import {
      fromGlobalId,
      nodeDefinitions,
    } from 'graphql-relay';

    import { A, getA, aType } from 'A'
    import { B, getB, bType } from 'B'

    export var {nodeInterface, nodeField} = nodeDefinitions (
      (globalId) => {
        var {type, id} = fromGlobalId (globalId);
        if (type === 'A') {
          return getA (id);
        } else if (type === 'B') {
          return getB (id);
        }
      },
      (obj) => {
        if (obj instanceof A) {
          return aType;
        } else if (obj instanceof B) {
          return bType;
        }
      }
    )

    // -- file schema.js

    import {
      GraphQLObjectType,
      GraphQLSchema,
    } from 'graphql';

    import { nodeField } from './nodeDefs';

    var queryType = new GraphQLObjectType ({
      name: 'Query',
      fields: () => ({
        node: nodeField,
        /*...*/
      }),
    });

I'm looking for advice or best practices on how to handle this situation. Any common approaches?

Answer №1

I am encountering the same issue and I believe a more efficient solution would be to utilize gruntjs concat.

grunt.initConfig({
  concat: {
    js: {
      src: ['lib/before.js', 'lib/*', 'lib/after.js'],
      dest: 'schema.js',
    }
  }
});

By configuring this setup, you can segment your schema into multiple files and merge them into a final schema.js file.

The contents of before.js could look like this:

 import {
    GraphQLObjectType,
    GraphQLInt,
    GraphQLString,
    GraphQLSchema,
    GraphQLList,
    GraphQLNonNull
} from 'graphql';
import db from '../models/index.js';
import Auth from '../classes/auth';

The structure of after.js might resemble the following:

const Schema = new GraphQLSchema({
    query: Query,
    mutation: Mutation
})
export default Schema;

Other files will consist of Objects such as:

const Funcionario = new GraphQLObjectType({
name: 'Funcionario',
description: 'This represent a Funcionario',
fields: () => {
    return {
        id: {
            type: GraphQLInt,
            resolve(funcionario, args) {
                return funcionario.id;
            }
        },
        CPF: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.CPF;
            }
        },
        nome: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.nome;
            }
        },
        sobrenome: {
            type: GraphQLString,
            resolve(funcionario, args) {
                return funcionario.sobrenome;
            }
        },
        sessions: {
            type: new GraphQLList(Session),
            resolve(funcionario, args) {
                return funcionario.getSessions();
            }
        }
    }
}
})

Answer №2

To find more information, visit this link

Within todoType.js, there is a connection to viewerType which can be found in viewerType.js

viewerType.js also makes imports from todoType

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

Activate the Click in the Span Element with no Matching ID to the Final Segment of the URL

I'm facing an issue with triggering the click event on a specific span that lacks an id attribute. This particular span has an empty ID and doesn't respond when I try to click the back or forward buttons in the browser. All other spans trigger th ...

Event listeners can only be removed within the useEffect hook

I have encountered an issue when trying to remove an event listener added inside the useEffect hook. The listener is set up to run once after the first rerender, thanks to the empty array passed as the second argument in the useEffect call. I attempted t ...

Differences between Creating and Updating Objects in JavaScript

When working with JavaScript, it is important to consider the best practices for performance optimization. Take a look at these two examples: Example 1: var x = {}; x.a = 10; Example 2: var x = {}; x = {a: 10}; Are there any noticeable differences in ...

Steps for modifying the CSS style of a div element following an onclick event:

<html> <head> <style type="text/css"> .step_box { border: 1.0px solid rgb(204, 204, 204); border-radius: 10.0px 10.0px 10.0px 10.0px; } .step_box:hover{ background: rgb(184, 225, 252); } .selected { background-color : #fff000; ...

JavaScript will continue to process the submit to the server even after validation has been completed

My current challenge involves implementing form validation using JavaScript. The goal is to prevent the form from being sent to the server if any errors are found. I have made sure that my JavaScript function returns false in case of an error, like so: ...

Express: How to Define Route Parameters from the Client Side

app.get('login/:id', function (request, response) { … }); I am curious about how the :id parameter is assigned from the user in a request like this. Since each user will have a unique id on my site, I wonder how it works. Does the user need ...

Is there a way to trigger a confirmation function for form submission exclusively when clicking one specific submit button, and not the other?

Here is the layout of my form: <form action="newsletter.php" name="newsletter" id="newsletter" method="post"> <input type="submit" value="Submit" class="c-btn" id="submit_value" name="submit_value"> <input type="submit" value="Send" cla ...

Compiling modal window content in AngularJS can lead to the creation of controllers that are left disconnected

I implemented a modal window triggered by fancybox in my project. Once the modal is displayed, fancybox triggers a "modalShown" event that is listened for by AppController. In this listener, $compile is called on the modal content to create the ModalContro ...

Evaluating the Material ui Select element without relying on test identifiers

Currently, I am working with Material UI and react-testing-library to test a form. The form includes a Select component that is populated by an array of objects. import React, { useState } from 'react'; import { Select, MenuItem, FormControl, Inp ...

Is it possible to have a field automatically calculate its value based on another field?

Consider the following data structure: { "rating": 0, "reviews": [ {"name": "alice", rating: 4}, {"name": "david", rating: 2} ] } What is the best way to recalculate the overall rating when new reviews are added or existing reviews are upda ...

What would be more efficient for designing a webpage - static HTML or static DOM Javascript?

My burning question of the day is: which loads faster, a web page designed from static html like this: <html> <head> <title>Web page</title> </head> <body> <p>Hi community</p> </bo ...

Tips for creating a horizontal list within a collapsible card

When a user clicks on a button, I am dynamically populating a list of items. Despite using list-group-horizontal, I am unable to make it display horizontally. HTML code <div id="textarea_display" class="mt-2 "> <label&g ...

How can we display the first letter of the last name and both initials in uppercase on the JavaScript console?

I'm a new student struggling with an exercise that requires writing multiple functions. The goal is to create a function that prompts the user for their first and last name, separates the names using a space, and then outputs specific initials in diff ...

Aligning text vertically to the top with material UI and the TextField component

Seeking guidance on adjusting vertical alignment of text in <TextField /> const styles = theme => ({ height: { height: '20rem', }, }); class Foo extends React.component { ... <TextField InputProps={{ classes: ...

In order to successfully utilize Node.js, Async.js, and Listeners, one must ensure

Here is the log output from the code below, I am unsure why it is throwing an error. It seems that the numbers at the end of each line represent line number:char number. I will highlight some important line numbers within the code. Having trouble with t ...

Asynchronous operations in Node.js with Express

Hey, I'm still pretty new to using async functions and I could really use some help understanding how to pass callbacks in async.each for each item to the next level (middleware). Here's the logic: I want to iterate through all items, and if an ...

Execute the script before the Vue.js framework initiates the HTML rendering

In order to determine if the user is logged in or not, and redirect them to the login page if they are not, I am looking for a way to check the user's login status before the HTML (or template) loads. I have attempted to use beforeCreate() and variou ...

Is there a way to place my searchbox in the top right corner of the page?

I am currently working on creating a search function for my list of products. However, I have encountered an issue where the searchBox is not appearing in the top right corner as intended. Despite trying various solutions, I have been unsuccessful in movin ...

What is the reason for placing a ReactJS component, defined as a function, within tags when using the ReactDom.render() method?

As someone who is brand new to ReactJS and JavaScript, I am struggling to grasp the syntax. The component I have created is very basic: import React from 'react' import ReactDom from 'react-dom' function Greetings() { return <h1&g ...

Transforming a canvas into a div element

Hey there, I'm looking to swap out one canvas for another but I'm not sure how it will look on the browser. Any help would be greatly appreciated. <div id="juego"> <canvas width="203" height="256" id="1" class="bloque"></canvas& ...