How to execute GraphQL query from server

8.8k views Asked by At

I am using graphql-express to create an endpoint where I can execute graphql queries in. Although I am using Sequelize with a SQL database it feels wrong to use it directly from the server outside of my graphql resolve functions. How do I go about querying my graphql API from the same server as it was defined in?

This is how I set up my graphql endpoint:

const express = require('express');
const router = express.Router();
const graphqlHTTP = require('express-graphql');
const gqlOptions = {
   schema: require('./schema')
};
router.use('/', graphqlHTTP(gqlOptions));

modules.exports = router;

Basically what I want is to be able to do something like this:

query(`
  {
    user(id: ${id}) {
      name
    }
  }
`)

How would I create this query function?

3

There are 3 answers

3
Aᴍɪʀ On BEST ANSWER

GraphQL.js itself does not require a http server to run. express-graphql is just a helper to mount the query resolver to a http endpoint.

You can pass your schema and the query to graphql, it'll return a Promise that'll resolve the query to the data.

graphql({schema, requestString}).then(result => {
  console.log(result);
});

So:

const {graphql} = require('graphql');
const schema = require('./schema');
function query (requestString) {
  return graphql({schema, requestString});
}

query(`
  {
    user(id: ${id}) {
      name
    }
  }
`).then(data => {
  console.log(data);
})
1
Vincent Cantin On

I would like to complete the answer from @aᴍɪʀ by providing the pattern for properly doing a query / mutation with parameters:

const params = {
  username: 'john',
  password: 'hello, world!',
  userData: {
    ...
  }
}

query(`mutation createUser(
          $username: String!,
          $password: String!,
          $userData: UserInput) {
  createUserWithPassword(
    username: $username,
    password: $password,
    userData: $userData) {
    id
    name {
      familyName
      givenName
    }
  }
}`, params)

This way, you don't have to deal with the string construction bits " or ' here and there.

0
Nhon Ha On

Thanks for the other answers, this is for Nextjs inside getServerSideProps, getStaticProps, getStaticPaths and getStaticProps, includes context for MongoDB. Need this because if you have your graphql sever in api route, when you build it wont build because your server in api route is not running.

Mongo file: plugin/zDb/index:

import {MongoClient} from "mongodb"

export const connectToDatabase = async() => {
  const client = new MongoClient(process.env.MONGODB_URI, {useNewUrlParser: true, useUnifiedTopology: true})
  let cachedConnection
  if(cachedConnection) return cachedConnection
  try {
    const connection = await client.connect()
    cachedConnection = connection
    return connection
  } catch(error) {
    console.error(error)
  }
}

export const mongoServer = async() => {
  const connect = await connectToDatabase()
  return connect.db(process.env.DB_NAME)
}

In pages folder, eg index.js file homepage:

import {graphql} from 'graphql'
import {schema} from '@/plugin/zSchema/schema'
import {mongoServer} from '@/plugin/zDb/index'
async function query(source, variableValues) {
  return graphql({schema, source, contextValue: {mongo: await mongoServer()}, variableValues})
}
export async function getServerSideProps(ctx) {
  const listingCurrent = await query(`query($keyField: String, $keyValue: String) {
    ListingRQlistingListKeyValue(keyField: $keyField, keyValue: $keyValue) {
      address
      urlSlug
      imageFeature {
        photoName
      }
    }
  }`, {
    keyField: 'offerStatus'
    , keyValue: 'CURRENT'
  })
  return {props: {
    listingCurrent: listingCurrent.data.ListingRQlistingListKeyValue
  }
}
}

Please note: the graphql call field names is from: https://github.com/graphql/graphql-js/blob/fb27b92a5f66466fd8143efc41e1d6b9da97b1f4/src/graphql.js#L62

export type GraphQLArgs = {|
  schema: GraphQLSchema,
  source: string | Source,
  rootValue?: mixed,
  contextValue?: mixed,
  variableValues?: ?ObjMap<mixed>,
  operationName?: ?string,
  fieldResolver?: ?GraphQLFieldResolver<any, any>,
|};

And my schema file: plugin/zSchema/schema.js

import { makeExecutableSchema } from '@graphql-tools/schema'
import {resolvers} from '@/plugin/zSchema/resolvers'
import {typeDefs} from '@/plugin/zSchema/typeDefs'

export const schema = makeExecutableSchema({resolvers, typeDefs})

The @/plugin folder: I'm using this in root file called jsconfig.json, and I put all my folders inside root/plugin, and I call it with @/plugin. You can use your own folder structure importing them as how you normally do it.

{
  "compilerOptions": {
    "baseUrl": "."
    , "paths": {
      "@/*": ["./*"]
    }
  }
}