Skip to content

Commit

Permalink
[examples/with-typescript-graphql] Add "createResolverContext" hook, …
Browse files Browse the repository at this point in the history
…etc. (vercel#11681)

* Update deps

* Run "node-check-update -u"
* "graphql" keeps ^14 since other libs expect it
* Install apollo-link and apollo-cache because @apollo/react-common
wants it as peer-deps

* Add graphql-let/schema/loader

* This enables HMR from modifying *.graphqls.

* Add resolver context

* Remove JSDoc, respect TypeScript defs

* ncu -u

* Keep using graphql@^14.6.0 for the other deps

* fix: Migrate to [email protected]

* Removed duplicated deps

* Updated check

Co-authored-by: Luis Alvarez <[email protected]>
  • Loading branch information
piglovesyou and Luis Alvarez authored May 4, 2020
1 parent ed86e2d commit 7908003
Show file tree
Hide file tree
Showing 7 changed files with 78 additions and 34 deletions.
1 change: 0 additions & 1 deletion examples/with-typescript-graphql/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.next
node_modules
__generated__
*.graphql.d.ts
*.graphqls.d.ts
3 changes: 1 addition & 2 deletions examples/with-typescript-graphql/.graphql-let.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
generateDir: __generated__
schema: '**/*.graphqls'
schema: lib/type-defs.graphqls
documents: '**/*.graphql'
plugins:
- typescript
Expand Down
3 changes: 2 additions & 1 deletion examples/with-typescript-graphql/lib/resolvers.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { QueryResolvers } from './type-defs.graphqls'
import { ResolverContext } from './with-apollo'

const Query: Required<QueryResolvers> = {
const Query: Required<QueryResolvers<ResolverContext>> = {
viewer(_parent, _args, _context, _info) {
return { id: String(1), name: 'John Smith', status: 'cached' }
},
Expand Down
59 changes: 49 additions & 10 deletions examples/with-typescript-graphql/lib/with-apollo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { IncomingMessage, ServerResponse } from 'http'
import { NextPage, NextPageContext } from 'next'
import { ContextFunction } from 'apollo-server-core'
import React from 'react'
import Head from 'next/head'
import { ApolloProvider } from '@apollo/react-hooks'
Expand All @@ -16,12 +18,29 @@ type WithApolloPageContext = {
apolloClient: TApolloClient
} & NextPageContext

export type ResolverContext = { req: IncomingMessage; res: ServerResponse }

let globalApolloClient: TApolloClient

export const createResolverContext: ContextFunction<
{ req: IncomingMessage; res: ServerResponse },
ResolverContext
> = async ({ req, res }) => {
// If you want to pass additional data to resolvers as context
// such as session data, you can do it here. For example:
//
// const user = await resolveUser(req.header.cookie)
// return { req, res, user }
//
return { req, res }
}

/**
* Creates and provides the apolloContext
* to a next.js PageTree. Use it by wrapping
* your PageComponent via HOC pattern.
* By passing `{ssr: false}`, it could be statically optimized
* instead of being exported as a serverless function.
*/
export default function withApollo(
PageComponent: NextPage,
Expand Down Expand Up @@ -54,11 +73,24 @@ export default function withApollo(

if (ssr || PageComponent.getInitialProps) {
WithApollo.getInitialProps = async (ctx: WithApolloPageContext) => {
const { AppTree } = ctx
// Resolver context here is only set on server. For client-side,
// "/api/graphql" route creates and pass it to resolver functions.
let resolverContext: ResolverContext | undefined
// Keep the "isServer" check inline, so webpack removes the block
// for client-side bundle.
if (typeof window === 'undefined') {
resolverContext = await createResolverContext({
req: ctx.req!,
res: ctx.res!,
})
}

// Initialize ApolloClient, add it to the ctx object so
// we can use it in `PageComponent.getInitialProp`.
const apolloClient = (ctx.apolloClient = initApolloClient())
const apolloClient = (ctx.apolloClient = initApolloClient(
undefined,
resolverContext
))

// Run wrapped getInitialProps methods
let pageProps = {}
Expand All @@ -77,6 +109,7 @@ export default function withApollo(
// Only if ssr is enabled
if (ssr) {
try {
const { AppTree } = ctx
// Run all GraphQL queries
const { getDataFromTree } = await import('@apollo/react-ssr')
await getDataFromTree(
Expand Down Expand Up @@ -116,13 +149,15 @@ export default function withApollo(
/**
* Always creates a new apollo client on the server
* Creates or reuses apollo client in the browser.
* @param {Object} initialState
*/
function initApolloClient(initialState?: any) {
function initApolloClient(
initialState?: any,
resolverContext?: ResolverContext
) {
// 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)
return createApolloClient(initialState, resolverContext)
}

// Reuse client on the client-side
Expand All @@ -135,25 +170,29 @@ function initApolloClient(initialState?: any) {

/**
* Creates and configures the ApolloClient
* @param {Object} [initialState={}]
*/
function createApolloClient(initialState = {}) {
function createApolloClient(
initialState = {},
resolverContext?: ResolverContext
) {
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(),
link: createIsomorphLink(resolverContext),
cache,
})
}

function createIsomorphLink() {
function createIsomorphLink(resolverContext?: ResolverContext) {
if (typeof window === 'undefined') {
const { SchemaLink } = require('apollo-link-schema')
const schema = require('./schema').default
return new SchemaLink({ schema })

// "resolverContext" is passed only before calling "getDataFromTree".
return new SchemaLink({ schema, context: resolverContext })
} else {
const { HttpLink } = require('apollo-link-http')
return new HttpLink({
Expand Down
2 changes: 1 addition & 1 deletion examples/with-typescript-graphql/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ module.exports = {
config.module.rules.push({
test: /\.graphqls$/,
exclude: /node_modules/,
loader: 'graphql-tag/loader',
use: ['graphql-tag/loader', 'graphql-let/schema/loader'],
})

return config
Expand Down
38 changes: 20 additions & 18 deletions examples/with-typescript-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,34 @@
"start": "next start"
},
"dependencies": {
"@apollo/react-common": "^3.1.3",
"@apollo/react-components": "^3.1.3",
"@apollo/react-hooks": "^3.1.3",
"@apollo/react-ssr": "^3.1.3",
"@apollo/react-common": "3.1.4",
"@apollo/react-components": "^3.1.5",
"@apollo/react-hooks": "3.1.5",
"@apollo/react-ssr": "3.1.5",
"apollo-cache": "1.3.4",
"apollo-cache-inmemory": "1.6.5",
"apollo-client": "2.6.8",
"apollo-link-http": "1.5.16",
"apollo-link-schema": "1.2.4",
"apollo-server-micro": "2.10.1",
"apollo-link": "1.2.14",
"apollo-link-http": "1.5.17",
"apollo-link-schema": "1.2.5",
"apollo-server-micro": "2.12.0",
"apollo-utilities": "^1.3.3",
"graphql": "^14.6.0",
"graphql-tag": "^2.10.3",
"next": "latest",
"react": "^16.12.0",
"react-dom": "^16.12.0"
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@graphql-codegen/cli": "1.12.2",
"@graphql-codegen/plugin-helpers": "1.12.2",
"@graphql-codegen/typescript": "^1.12.2",
"@graphql-codegen/typescript-operations": "^1.12.2",
"@graphql-codegen/typescript-react-apollo": "^1.12.2",
"@graphql-codegen/typescript-resolvers": "1.12.2",
"@types/react": "^16.9.22",
"@types/react-dom": "^16.9.5",
"@graphql-codegen/cli": "1.13.3",
"@graphql-codegen/plugin-helpers": "1.13.3",
"@graphql-codegen/typescript": "^1.13.3",
"@graphql-codegen/typescript-operations": "^1.13.3",
"@graphql-codegen/typescript-react-apollo": "^1.13.3",
"@graphql-codegen/typescript-resolvers": "1.13.3",
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.7",
"graphql-let": "0.x",
"typescript": "^3.8.2"
"typescript": "^3.8.3"
}
}
6 changes: 5 additions & 1 deletion examples/with-typescript-graphql/pages/api/graphql.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { ApolloServer } from 'apollo-server-micro'
import schema from '../../lib/schema'
import { createResolverContext } from '../../lib/with-apollo'

const apolloServer = new ApolloServer({ schema })
const apolloServer = new ApolloServer({
schema,
context: createResolverContext,
})

export const config = {
api: {
Expand Down

0 comments on commit 7908003

Please sign in to comment.