Last active
December 19, 2020 17:02
-
-
Save neil-gebbie-smarterley/cd8356df4c786c4c9dacfc9d46e890ac to your computer and use it in GitHub Desktop.
Apollo client, apollo server, next js with cookies
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const typeDefs = require('./schema/schema') | |
const someRestAPI = require('./someRestAPI') | |
const resolvers = require('./resolvers') | |
const apolloServer = { | |
typeDefs, | |
resolvers, | |
dataSources: () => ({ | |
someRestAPI: new someRestAPI(), | |
}), | |
context: ({ req }) => { | |
return { req } | |
} | |
} | |
module.exports = apolloServer |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ApolloClient } from 'apollo-client' | |
import { createHttpLink } from 'apollo-link-http' | |
import { InMemoryCache } from 'apollo-cache-inmemory' | |
import { setContext } from 'apollo-link-context' | |
import fetch from 'isomorphic-unfetch' | |
let apolloClient = null | |
// Polyfill fetch() on the server (used by apollo-client) | |
if (!process.browser) { | |
global.fetch = fetch | |
} | |
const graphqlEndpoint = | |
process.env.NODE_ENV !== 'production' | |
? 'http://localhost:3000' | |
: process.env.BASE_URL | |
const create = (initialState, cookie) => { | |
const httpLink = createHttpLink({ | |
uri: `${graphqlEndpoint}/graphql`, | |
credentials: 'include' | |
}) | |
const authLink = setContext((_, { headers }) => { | |
return { | |
headers: { | |
...headers, | |
Cookie: cookie ? cookie : '', | |
} | |
} | |
}) | |
return new ApolloClient({ | |
connectToDevTools: process.browser, | |
ssrMode: !process.browser, // Disables forceFetch on the server (so queries are only run once) | |
link: authLink.concat(httpLink), | |
cache: new InMemoryCache().restore(initialState || {}) | |
}) | |
} | |
const initApollo = (initialState, cookie) => { | |
// Make sure to create a new client for every server-side request so that data | |
// isn't shared between connections (which would be bad) | |
if (!process.browser) { | |
return create(initialState, cookie) | |
} | |
// Reuse client on the client-side | |
if (!apolloClient) { | |
apolloClient = create(initialState, document.cookie) | |
} | |
return apolloClient | |
} | |
export default initApollo |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const express = require('express') | |
const next = require('next') | |
const cors = require('cors') | |
const cookieParser = require('cookie-parser') | |
const connect = require('connect') | |
const { ApolloServer } = require('apollo-server-express') | |
const apolloServer = require('./apolloServer') | |
const dev = process.env.NODE_ENV !== 'production' | |
const port = process.env.PORT || 3000 | |
const app = next({ dev }) | |
const handle = app.getRequestHandler() | |
var corsOptions = { | |
origin: | |
process.env.NODE_ENV !== 'production' | |
? 'http://localhost:3000' | |
: process.env.BASE_URL, | |
credentials: true | |
} | |
app | |
.prepare() | |
.then(() => { | |
const server = express() | |
.use(connect()) | |
.use(cookieParser()) | |
.use(cors(corsOptions)) | |
new ApolloServer({ ...apolloServer }).applyMiddleware({ | |
app: server, | |
cors: corsOptions | |
}) | |
// your next config | |
server.get('*', (req, res) => { | |
return handle(req, res) | |
}) | |
server.listen(port, err => { | |
if (err) throw err | |
// eslint-disable-next-line no-console | |
console.log(`> Ready on http://localhost:${port} at ${Date.now()}`) | |
}) | |
}) | |
.catch(ex => { | |
// eslint-disable-next-line no-console | |
console.error(ex.stack) | |
process.exit(1) | |
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class someRestAPI extends RESTDataSource { | |
constructor() { | |
super() | |
this.baseURL = getConfig.env.API_ENDPOINT | |
} | |
willSendRequest(request) { | |
request.headers.set('cookie', this.context.req.headers.cookie) | |
} | |
// your functions | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable no-console */ | |
import React from 'react' | |
import PropTypes from 'prop-types' | |
import initApollo from './init-apollo' | |
import Head from 'next/head' | |
import idx from 'idx' | |
import { getDataFromTree } from 'react-apollo' | |
export default App => { | |
return class Apollo extends React.Component { | |
static displayName = 'withApollo(App)' | |
static async getInitialProps(ctx) { | |
const { Component, router } = ctx | |
// get the cookies sent on the initial request | |
const cookie = idx(ctx, _ => _.ctx.req.headers.cookie) | |
// Run all GraphQL queries in the component tree and extract the resulting data | |
const apollo = initApollo({}, cookie) | |
let appProps = {} | |
if (App.getInitialProps) { | |
appProps = await App.getInitialProps(ctx) | |
} | |
if (!process.browser) { | |
try { | |
// Run all GraphQL queries | |
await getDataFromTree( | |
<App | |
{...appProps} | |
Component={Component} | |
router={router} | |
apolloClient={apollo} | |
/> | |
) | |
} catch (error) { | |
// Prevent Apollo Client GraphQL errors from crashing SSR. | |
// Handle them in components via the data.error prop: | |
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error | |
console.error('Error while running `getDataFromTree`', error) | |
} | |
// getDataFromTree does not call componentWillUnmount | |
// head side effect therefore need to be cleared manually | |
Head.rewind() | |
} | |
// Extract query data from the Apollo store | |
const apolloState = apollo.cache.extract() | |
return { | |
...appProps, | |
apolloState, | |
cookie | |
} | |
} | |
static propTypes = { | |
apolloState: PropTypes.object, | |
cookie: PropTypes.string | |
} | |
constructor(props) { | |
super(props) | |
this.apolloClient = initApollo(props.apolloState, props.cookie) | |
} | |
render() { | |
return <App {...this.props} apolloClient={this.apolloClient} /> | |
} | |
} | |
} |
This one worked for me: https://gist.github.com/lionelyoung/6f9020de23f257599bdabfdb0bf40bff found in another github thread
How do I pass getServerSideProp
contexts? i.e.
export async function getServerSideProps(context) {
const myVars = {
orderId: context["params"]["order"]
}
return {
props: {
myVars: myVars,
},
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@josuevalrob Are you expecting a different response based on the logged-in status of the user? How are you handling that on the server side? Do something simple like (this is pseudo code) - IF has cookie return a response {cookie: true} from the server. I suspect your trying to do many things at once and you need to just slow down and do one thing at a time.
Also add the authlink I have got here: https://gist.github.com/neil-gebbie-smarterley/cd8356df4c786c4c9dacfc9d46e890ac#file-initapollo-js-L25