-
-
Save neil-gebbie-smarterley/cd8356df4c786c4c9dacfc9d46e890ac to your computer and use it in GitHub Desktop.
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} /> | |
} | |
} | |
} |
God... why it is soooo complicated??
@josuevalrob Just take it one step it at a time, log values out along the way, and everything will fall into place. You only need to set it up once then everything will be fine.
Thanks
@josuevalrob Just take it one step it at a time, log values out along the way, and everything will fall into place. You only need to set it up once then everything will be fine.
But the problem is that I have a different server configuration. Can you check it, please?
Client: https://github.com/josuevalrob/CLE
Server: https://github.com/josuevalrob/cle_api
Just a quick look to know if this approach is fine for me. It means to refactor a lot of code.
So far it is impossible to send the cookie in the login and validate it in the context of my graphQl.
Please if you can give me a hand, contact me: [email protected]
@josuevalrob I'm giving you a hand by providing this gist.
What have you tried? I've looked at your repo and you haven't implemented any of the code above. I don't know if the approach will work for you, this gist is for NextJS and Apollo. I can't determine what's possible or not possible as I know nothing about your local, development or production environments. But it seems like a fairly common scenario to pass cookies, so I can't see why it would be an issue.
Best of luck.
Thanks @neil-gebbie-smarterley for share the repo and you help.
I had explain a little more about my issue in this question from StackOverflow.
My problem is that I need to understand what is happening, this is not magic you know(?).
Thanks to the comments from the StackOverflow questions, it looks like yes, the cookie is traveling in both direction, I have access to if I inspect the network request, but I am lost in the validation from the client and server-side.
I really appreciate your help, any comment is welcome.
@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
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,
},
}
}
Wow thanks a lot