Skip to content

Instantly share code, notes, and snippets.

@neil-gebbie-smarterley
Last active December 19, 2020 17:02
Show Gist options
  • Save neil-gebbie-smarterley/cd8356df4c786c4c9dacfc9d46e890ac to your computer and use it in GitHub Desktop.
Save neil-gebbie-smarterley/cd8356df4c786c4c9dacfc9d46e890ac to your computer and use it in GitHub Desktop.
Apollo client, apollo server, next js with cookies
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
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
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)
})
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
}
/* 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} />
}
}
}
@neil-gebbie-smarterley
Copy link
Author

@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

@lionelyoung
Copy link

This one worked for me: https://gist.github.com/lionelyoung/6f9020de23f257599bdabfdb0bf40bff found in another github thread

@lionelyoung
Copy link

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