Graphql-yoga: Expose express library to end users?

Created on 24 Nov 2017  路  16Comments  路  Source: dotansimha/graphql-yoga

I would like to serve my build/dist folder for my static assets when developing/deploying to now or any server. For that I need to install express again and use the static function from there.
It would be great if graphql-yoga had this inbuilt for my static assets otherwise it would good enough to re-export the express library for public use.

This is what I'm doing now

import express from 'express';
server.express.use(express.static('dist'));

Something like this would be more easier,

import GraphQLYoga from 'graphql-yoga';
const { GraphQLServer, express } = GraphQLYoga;

const server = new GraphQLServer({ typeDefs, resolvers, options })
server.express.use(express.static('dist'));

else more like this,

const server = new GraphQLServer({ typeDefs, resolvers, options: {
  static: 'dist',
 }});

BTW Great library. I had the same amount of code throughout my projects. This unifies it and also the apollo-upload-server is a plus that too it got recently released too.

kindiscussion

Most helpful comment

@geminiyellow this worked for me

// Serve static files
server.express.use(express.static(path.join(__dirname, '../client/build')));
// Serve other routes to index...typical for Angular frontend app
server.express.get('*', (req, res, next) => {
   // Handle graphql-yoga specific routes
   if(req.url == options.playground ||
    req.url == options.subscriptions ||
    req.url == options.endpoint) {
      // Return next() so that the GraphQLServer will handle it
      return next();
    }
   res.sendFile(path.join(__dirname, '../client/build/index.html'))
});

I know this issue is closed, but I felt like contributing a solution that worked for me.

All 16 comments

+1

I like server.express.use(express.static('dist')); better.
more flexible

Hi @pyros2097, isn't what you suggested already possible?

I needed to install the express library and then use the static option from it. I understand the express server is exposed by the server but not the library. So I need to install express additionally to use say ... express.Router() if I needed to add a route or something like that.
That's why I made this change
https://github.com/pyros2097/graphql-yoga/blob/master/src/index.ts#L15
I just wanted it to be consistent on what express library I used.

Installing the express library is the way to go for now.

Yes, I saw that in the PR too. I agree with @schickling that if you need anything from express, you should add that dependency yourself, instead of having graphql-yoga export it.

Ok. I understand now. I just thought, that way we could make graphql-yoga a single dependency for all your server needs. Maybe that's now what graphql-yoga is trying to solve. Again it was just my reasoning. @kbrandwijk I initially followed that approach.

hi all, is really can add static folder to yoga?

what i do is,

//**********************************************************
server.express.use(express.static(path.join(__dirname, '../client/build')));
// server.express.get('/', res => res.sendFile(path.join(__dirname, '../client/build/index.html')));
//**********************************************************

const options = {
  port: 3000,
  endpoint: '/graphql',
  subscriptions: '/subscriptions',
  playground: '/playground',
};
server.start(options, ({ port }) => console.log(`Server is running at http://localhost:${port}`));

when i add the static folder, i cannot access /playground and /graphql anymore.
who can tell me why ?

@geminiyellow I don't know if this is the right place to ask this question. But anyways the /graphql, /playground paths will get caught by the static middleware since it is a middleware.

You can try to mount the static assets to a path like this,
server.express.use('/build', express.static(path.join(__dirname, '../client/build')));
and then you will be able to access your assets from the build path like this /build/index.html

@pyros2097 thank you

For anyone else stumbling upon this and wanting to have 1 app that serves both your backend and frontend, I suggest you do:

- backend
  - yoga.js
- frontend
  - react.js
- package.json
- server.js
// ./package.json
{
  "scripts": {
    "dev": "npm-run-all --parallel dev:*",
    "dev:frontend": "nodemon ./server.js", // catch-all routes --> your react app's index.html 
    "dev:backend": "nodemon ./backend/yoga.js"
  }
}
// ./server.js
const port = process.env.PORT || 5000
app.listen(port)
console.log(`./server.js: http://localhost:${port}`)
// ./backend/yoga.js
// ...
const port = 1337
server.start({ port }, () => console.log(`./backend/yoga.js: http://localhost:${port}`))

Replace "dev" scripts with "start", and nodemon with node, and this should work on Heroku as well.

The idea is Heroku can run 1 start script. Within that start script we're parallel running both servers (our generic Express app to catch-all towards React _and_ our graphql-yoga app).

React will run on Heroku's default port so example.herokuapp.com will be your React app. Since your graphql-yoga server is on a different port, example.herokuapp.com:1337 will display your Playground.

@geminiyellow this worked for me

// Serve static files
server.express.use(express.static(path.join(__dirname, '../client/build')));
// Serve other routes to index...typical for Angular frontend app
server.express.get('*', (req, res, next) => {
   // Handle graphql-yoga specific routes
   if(req.url == options.playground ||
    req.url == options.subscriptions ||
    req.url == options.endpoint) {
      // Return next() so that the GraphQLServer will handle it
      return next();
    }
   res.sendFile(path.join(__dirname, '../client/build/index.html'))
});

I know this issue is closed, but I felt like contributing a solution that worked for me.

looks good

@newtmex That feels like the correct way how to do this! Kudos!

@newtmex Thank you!

I don't fully understand the above solution, as I can't seem to get this working. I'm using next.js and apollo. How might I do this when using next.js as my front end framework?

this worked for me

const { GraphQLServer } = require('graphql-yoga');
const serveStatic = require('serve-static');
const { join } = require('path');

const server = new GraphQLServer({ typeDefs, resolvers, options });
server.express.use(
  serveStatic(join(__dirname + '/../public/'), {
    cacheControl: false,
  }),
);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

SebastianEdwards picture SebastianEdwards  路  4Comments

chakrihacker picture chakrihacker  路  5Comments

bellomusodiq picture bellomusodiq  路  3Comments

ramonmulia picture ramonmulia  路  3Comments

2wce picture 2wce  路  4Comments