Skip to content

Commit

Permalink
setup apollo cors and graphql-voyager
Browse files Browse the repository at this point in the history
  • Loading branch information
eric-burel committed Jun 18, 2020
1 parent b715f2e commit 076643d
Show file tree
Hide file tree
Showing 7 changed files with 479 additions and 46 deletions.
25 changes: 23 additions & 2 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

[Relevant Next doc](https://nextjs.org/docs/basic-features/typescript)

## Apollo
## Apollo Client

### Optional, per-page Apollo Provider and SSR

Expand All @@ -24,6 +24,22 @@ With have a non-regression test for SSR, so no surprise with component that sudd

We currently use Apollo Client v2. At the time of writing, v3 is still in beta.

## Apollo Server

### Demo of a simple server

See `src/pages/api/graphql` for a demo server built with Apollo and Express

**NOTE:** Expect drastic enhancement of the way the server is set up, thanks to [VulcanJS](http://vulcanjs.org/) declarative approach.

### GraphQL Playground

GraphQL Playground is available on `api/graphql`. All API routes of Next are located in the `src/pages/api` folder, hence the `api` prefix.

### Graphql Voyager

Open `api/debug/graphql-voyager` and explore your API visually.

## Code architecture and build

### Code in `src`
Expand Down Expand Up @@ -217,15 +233,20 @@ Automatically enable debug in Cypress
### GraphQL

Graphql code generator
Demo support of multiple graphQL API using Link split

### Demo custom server?
### Demo custom server for SSR

NOTE: Using a custom server to serve Next pages is not recommended. We may choose not to support this feature.

ts-node, nodemon to have hot reload
Jest for the custom server
Fullstack cypress testing/coverage of the custom server

### Apollo server

Demo a Mongodb connection with Mongoose (maybe we could find a demo database online?)

 ### Others

Redirection demo for private pages => demo a page that is not available for Example, and redirect to home with an HTTP request
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"apollo-server-express": "2.14.2",
"babel-jest": "26.0.1",
"babel-plugin-istanbul": "6.0.0",
"cors": "^2.8.5",
"cross-env": "7.0.2",
"debug": "4.1.1",
"eslint-plugin-cypress": "2.11.1",
Expand Down Expand Up @@ -97,6 +98,7 @@
"eslint": "^6.8.0",
"eslint-plugin-react": "^7.18.3",
"eslint-plugin-react-hooks": "^2.5.0",
"graphql-voyager": "^1.0.0-rc.31",
"jest": "^26.0.1",
"nyc": "^15.1.0",
"shelljs": "^0.8.4",
Expand Down
23 changes: 23 additions & 0 deletions src/lib/api/cors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { parseEnvVariableArray } from "~/lib/utils";

const corsWhitelist = parseEnvVariableArray(
process.env.APOLLO_SERVER_CORS_WHITELIST
);

/**
* Accept same origin queries, and
*/
const corsOptions = {
origin: function (origin, callback) {
if (!origin) {
// same origin
callback(null, true);
} else if (corsWhitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error(`Not allowed by CORS ${origin}`));
}
},
};

export default corsOptions;
9 changes: 9 additions & 0 deletions src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* Example:
* APOLLO_SERVER_CORS_WHITELIST=http://localhost:5000,https://www.my-client.org
* => parse the string and makes it an array
* @param {*} variable Env array variables, with values separated by a comma (spaces allowed)
*/
export const parseEnvVariableArray = (variable = "") => {
return variable.split(",").map((s) => s.trim());
};
22 changes: 22 additions & 0 deletions src/pages/api/debug/graphql-voyager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// @see https://github.com/zeit/next.js/tree/master/examples/api-routes-apollo-server-and-client-auth
import express from "express";
import cors from "cors";
import corsOptions from "~/lib/api/cors";
import getConfig from "next/config";
import { express as voyagerMiddleware } from "graphql-voyager/middleware";

export const config = {
api: {
bodyParser: false,
},
};

const app = express();

const voyagerPath = "/api/debug/graphql-voyager";
app.use(voyagerPath, cors(corsOptions));
if (process.env.NODE_ENV !== "production") {
app.use(voyagerPath, voyagerMiddleware({ endpointUrl: "/api/graphql" }));
}

export default app;
64 changes: 39 additions & 25 deletions src/pages/api/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,60 @@
import express from 'express'
import { ApolloServer, gql } from 'apollo-server-express'

import express from "express";
import cors from "cors";
import corsOptions from "~/lib/api/cors";
import { ApolloServer, gql } from "apollo-server-express";
import { makeExecutableSchema } from "graphql-tools";

/**
* Sample, naive, Apollo server. You can move this code in `src/server`
* and code your own API.
*
* Check our GraphQL framework Vulcan.js to build your server using a declarative approach
* http://vulcanjs.org/
*/
const typeDefs = gql`
type Query {
users: [User!]!
}
type User {
name: String
}
`

`;
const resolvers = {
Query: {
users() {
return [{ name: 'Vulcanjs' }]
return [{ name: "Rick" }, { name: "Morty" }];
},
},
}
};
const schema = makeExecutableSchema({ typeDefs, resolvers });

// Define the server (using Express for easier middleware usage)
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV !== 'production',
playground: process.env.NODE_ENV !== 'production'
? {
settings: {
'request.credentials': 'include'
}
}
: false,
})
schema,
introspection: process.env.NODE_ENV !== "production",
playground:
process.env.NODE_ENV !== "production"
? {
settings: {
"request.credentials": "include",
},
}
: false,
});

const app = express();

const app = express()
app.set("trust proxy", true);

app.set('trust proxy', true)
const gqlPath = "/api/graphql";
app.use(gqlPath, cors(corsOptions));
// You could init the db connection here too
server.applyMiddleware({ app, path: "/api/graphql" });

server.applyMiddleware({ app, path: '/api/graphql' })
export default app;

export const config = {
api: {
bodyParser: false,
}
}

export default app
},
};
Loading

0 comments on commit 076643d

Please sign in to comment.