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?

Hoffmann
  • 14,369
  • 16
  • 76
  • 91

3 Answers3

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);
})
Aᴍɪʀ
  • 7,623
  • 3
  • 38
  • 52
  • To get more options, see the source code at https://github.com/graphql/graphql-js/blob/fb27b92a5f66466fd8143efc41e1d6b9da97b1f4/src/graphql.js#L62 – Vincent Cantin Mar 09 '18 at 06:47
  • Also here is the official documentation page for the graphql function: https://graphql.org/graphql-js/graphql/#graphql – mossjm Aug 21 '19 at 14:13
  • 1
    graphql 16 dropped support for positional arguments – jonS90 Mar 02 '23 at 17:06
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.

Vincent Cantin
  • 16,192
  • 2
  • 35
  • 57
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": {
      "@/*": ["./*"]
    }
  }
}
Nhon Ha
  • 433
  • 4
  • 5