У меня есть приложение Next.js, и я использую apollo-server-micro и apollo-client. Я не могу установить сеанс cookie, когда пользователь попадает в мутацию входа в систему. Вот моя настройка server.js (npm start)
const express = require('express');
const next = require('next');
const { apolloServer } = require('pages/api/graphql');
const cookieSession = require('cookie-session');
const dev = process.env.NODE_ENV !== 'production';
const app = nextApp({ dev });
const handle = app.getRequestHandler();
app.prepare().then(() => {
const server = express();
server.use(express.static('./public'));
server.use(
'/api',
cookieSession({
httpOnly: false,
keys: ['super-secret-key'],
maxAge: 24 * 60 * 60 * 1000,
name: 'xyz',
})
);
server.get('*', handle);
server.listen(8000, () => {
console.log('Server running on port 8000');
})
})
В pages/api/graphql.js
у меня есть следующий фрагмент кода (прямо из документации Next.js)
import { ApolloServer } from 'apollo-server-micro'
import { schema } from '../../apollo/schema'
export const apolloServer = new ApolloServer({
schema,
context: (ctx) => {
return ctx.req;
}
})
export const config = {
api: {
bodyParser: false
}
}
export default apolloServer.createHandler({ path: '/api/graphql' })
Вотмутация для входа в систему
const jobs = require('../data/jobs');
const users = require('../data/users');
const getUserByEmail = email => users.find(user => user.email === email);
export const resolvers = {
Query: {
viewer (_parent, _args, _context, _info) {
return { id: 1, name: 'John Smith', status: 'cached' }
},
jobs: (parent, args, context, info) => {
return jobs;
}
},
Mutation: {
login: (parent, args, context, info) => {
const { email } = args;
const user = getUserByEmail(email);
console.log(context.headers);
if (user) {
context.req = {
...context.req,
session: user
}
return user;
}
}
}
}
Пока нет шифрования, и все, я просто хочу сейчас запустить это. Как настроить сеанс (чтобы файл cookie появлялся в Chrome и был доступен для будущих входящих запросов)
Обновление: конфигурация клиента Apollo
import React from 'react'
import Head from 'next/head'
import { ApolloProvider } from '@apollo/react-hooks'
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
let apolloClient = null
/**
* Creates and provides the apolloContext
* to a next.js PageTree. Use it by wrapping
* your PageComponent via HOC pattern.
* @param {Function|Class} PageComponent
* @param {Object} [config]
* @param {Boolean} [config.ssr=true]
*/
export function withApollo (PageComponent, { ssr = true } = {}) {
const WithApollo = ({ apolloClient, apolloState, ...pageProps }) => {
const client = apolloClient || initApolloClient(apolloState)
return (
<ApolloProvider client={client}>
<PageComponent {...pageProps} />
</ApolloProvider>
)
}
// Set the correct displayName in development
if (process.env.NODE_ENV !== 'production') {
const displayName =
PageComponent.displayName || PageComponent.name || 'Component'
if (displayName === 'App') {
console.warn('This withApollo HOC only works with PageComponents.')
}
WithApollo.displayName = `withApollo(${displayName})`
}
if (ssr || PageComponent.getInitialProps) {
WithApollo.getInitialProps = async ctx => {
const { AppTree } = ctx
// Initialize ApolloClient, add it to the ctx object so
// we can use it in `PageComponent.getInitialProp`.
const apolloClient = (ctx.apolloClient = initApolloClient())
// Run wrapped getInitialProps methods
let pageProps = {}
if (PageComponent.getInitialProps) {
pageProps = await PageComponent.getInitialProps(ctx)
}
// Only on the server:
if (typeof window === 'undefined') {
// When redirecting, the response is finished.
// No point in continuing to render
if (ctx.res && ctx.res.finished) {
return pageProps
}
// Only if ssr is enabled
if (ssr) {
try {
// Run all GraphQL queries
const { getDataFromTree } = await import('@apollo/react-ssr')
await getDataFromTree(
<AppTree
pageProps={{
...pageProps,
apolloClient
}}
/>
)
} 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 = apolloClient.cache.extract()
return {
...pageProps,
apolloState
}
}
}
return WithApollo
}
/**
* Always creates a new apollo client on the server
* Creates or reuses apollo client in the browser.
* @param {Object} initialState
*/
function initApolloClient (initialState) {
// 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 (typeof window === 'undefined') {
return createApolloClient(initialState)
}
// Reuse client on the client-side
if (!apolloClient) {
apolloClient = createApolloClient(initialState)
}
return apolloClient
}
/**
* Creates and configures the ApolloClient
* @param {Object} [initialState={}]
*/
function createApolloClient (initialState = {}) {
const ssrMode = typeof window === 'undefined'
const cache = new InMemoryCache().restore(initialState)
// Check out https://github.com/zeit/next.js/pull/4611 if you want to use the AWSAppSyncClient
return new ApolloClient({
ssrMode,
link: createIsomorphLink(),
cache
})
}
function createIsomorphLink () {
if (typeof window === 'undefined') {
const { SchemaLink } = require('apollo-link-schema')
const { schema } = require('./schema')
return new SchemaLink({ schema })
} else {
const { HttpLink } = require('apollo-link-http')
return new HttpLink({
uri: '/apii/graphql',
credentials: 'same-origin'
})
}
}
Обновлено: конфигурация сервера Apollo с использованием apolloмикро
import { ApolloServer } from 'apollo-server-micro'
import { schema } from '../../apollo/schema'
export const apolloServer = new ApolloServer({
schema,
context: (ctx) => {
return ctx.req;
}
})
export const config = {
api: {
bodyParser: false
}
}
export default apolloServer.createHandler({ path: '/api/graphql' })