From f6c36b4b5368fd89af9582048fe4d83487225ac3 Mon Sep 17 00:00:00 2001 From: Arda TANRIKULU Date: Fri, 29 Jul 2022 02:49:59 +0300 Subject: [PATCH] Lazy Schema Plugin --- .changeset/healthy-waves-sing.md | 5 ++ packages/common/src/graphiqlHTML.ts | 1 + packages/plugins/lazy-schema/package.json | 47 ++++++++++++++++ packages/plugins/lazy-schema/src/index.ts | 33 ++++++++++++ .../test/lazy-schema-plugin.test.ts | 53 +++++++++++++++++++ 5 files changed, 139 insertions(+) create mode 100644 .changeset/healthy-waves-sing.md create mode 100644 packages/common/src/graphiqlHTML.ts create mode 100644 packages/plugins/lazy-schema/package.json create mode 100644 packages/plugins/lazy-schema/src/index.ts create mode 100644 packages/plugins/lazy-schema/test/lazy-schema-plugin.test.ts diff --git a/.changeset/healthy-waves-sing.md b/.changeset/healthy-waves-sing.md new file mode 100644 index 0000000000..788af55bf2 --- /dev/null +++ b/.changeset/healthy-waves-sing.md @@ -0,0 +1,5 @@ +--- +'@graphql-yoga/plugin-lazy-schema': major +--- + +New Lazy Schema diff --git a/packages/common/src/graphiqlHTML.ts b/packages/common/src/graphiqlHTML.ts new file mode 100644 index 0000000000..715613b45d --- /dev/null +++ b/packages/common/src/graphiqlHTML.ts @@ -0,0 +1 @@ +export default '__TITLE__
' diff --git a/packages/plugins/lazy-schema/package.json b/packages/plugins/lazy-schema/package.json new file mode 100644 index 0000000000..dd89acf41c --- /dev/null +++ b/packages/plugins/lazy-schema/package.json @@ -0,0 +1,47 @@ +{ + "name": "@graphql-yoga/plugin-lazy-schema", + "version": "0.0.0", + "description": "Lazy Schema plugin for GraphQL Yoga.", + "repository": { + "type": "git", + "url": "https://github.com/dotansimha/graphql-yoga.git", + "directory": "packages/plugins/apq" + }, + "main": "dist/cjs/index.js", + "module": "dist/esm/index.js", + "scripts": { + "check": "tsc --pretty --noEmit" + }, + "author": "Arda TANRIKULU ", + "license": "MIT", + "exports": { + ".": { + "require": { + "types": "./dist/typings/index.d.ts", + "default": "./dist/cjs/index.js" + }, + "import": { + "types": "./dist/typings/index.d.ts", + "default": "./dist/esm/index.js" + }, + "default": { + "types": "./dist/typings/index.d.ts", + "default": "./dist/esm/index.js" + } + }, + "./package.json": "./package.json" + }, + "typings": "dist/typings/index.d.ts", + "typescript": { + "definition": "dist/typings/index.d.ts" + }, + "publishConfig": { + "directory": "dist", + "access": "public" + }, + "peerDependencies": { + "graphql-yoga": "^2.13.4", + "graphql": "*" + }, + "type": "module" +} diff --git a/packages/plugins/lazy-schema/src/index.ts b/packages/plugins/lazy-schema/src/index.ts new file mode 100644 index 0000000000..abe5210dc9 --- /dev/null +++ b/packages/plugins/lazy-schema/src/index.ts @@ -0,0 +1,33 @@ +import { GraphQLError, GraphQLSchema } from 'graphql' +import { Plugin, PromiseOrValue, YogaInitialContext } from 'graphql-yoga' + +export const useLazySchema = ( + schemaFactory: (request: Request) => PromiseOrValue, +): Plugin => { + const schemaByRequest = new WeakMap() + return { + async onRequest({ request }) { + const schema = await schemaFactory(request) + schemaByRequest.set(request, schema) + }, + onEnveloped({ setSchema, context }) { + if (context?.request) { + const schema = schemaByRequest.get(context.request) + if (schema) { + setSchema(schema) + } + } else { + throw new GraphQLError( + 'Request object is not available in the context. Make sure you use this plugin with GraphQL Yoga.', + { + extensions: { + http: { + status: 500, + }, + }, + }, + ) + } + }, + } +} diff --git a/packages/plugins/lazy-schema/test/lazy-schema-plugin.test.ts b/packages/plugins/lazy-schema/test/lazy-schema-plugin.test.ts new file mode 100644 index 0000000000..9514bcbfe6 --- /dev/null +++ b/packages/plugins/lazy-schema/test/lazy-schema-plugin.test.ts @@ -0,0 +1,53 @@ +import { makeExecutableSchema } from '@graphql-tools/schema' +import { parse } from 'graphql' +import { createYoga, YogaInitialContext } from 'graphql-yoga' +import { useLazySchema } from '../src' + +describe('useLazySchema', () => { + it('should work', async () => { + let count = 0 + const schemaFactory = async (request: Request) => { + const countFromContext = request.headers.get('count') + return makeExecutableSchema({ + typeDefs: /* GraphQL */ ` + type Query { + foo${countFromContext}: Boolean + } + `, + resolvers: { + Query: { + [`foo${countFromContext}`]: (_, __, { request }) => + countFromContext === request.headers.get('count'), + }, + }, + }) + } + const yoga = createYoga({ + plugins: [useLazySchema(schemaFactory)], + }) + while (true) { + if (count === 3) { + break + } + count++ + const query = /* GraphQL */ ` + query { + foo${count} + } + ` + const result = await yoga.fetch('http://localhost:3000/graphql', { + method: 'POST', + body: JSON.stringify({ query }), + headers: { + count: count.toString(), + 'Content-Type': 'application/json', + }, + }) + const { data } = await result.json() + expect(data).toEqual({ + [`foo${count}`]: true, + }) + } + expect.assertions(3) + }) +})