How to execute GraphQL query from server
Asked Answered
D

3

17

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?

Diarthrosis answered 2/1, 2017 at 10:8 Comment(0)
T
24

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);
})
Tetravalent answered 5/1, 2017 at 5:37 Comment(3)
To get more options, see the source code at github.com/graphql/graphql-js/blob/…Hibbert
Also here is the official documentation page for the graphql function: graphql.org/graphql-js/graphql/#graphqlDunedin
graphql 16 dropped support for positional argumentsCannibalize
H
3

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.

Hibbert answered 12/3, 2018 at 2:29 Comment(1)
Doesn't the query function have to change as well? Your call passes 2 parameters and not one.Laryngo
S
1

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": {
      "@/*": ["./*"]
    }
  }
}
Subdual answered 17/10, 2022 at 5:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.