diff --git a/README.md b/README.md index cf461ae..d9f8000 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,9 @@ If you have to following env file `.env.staging` then you can pass it to Yoga us - [ ] Remove Unnecessary Abstraction - [x] Add GraphQL Shield Integration -- [ ] Add Examples - - [ ] GraphQL Shield - - [ ] Express Middleware +- [x] Add Examples + - [x] GraphQL Shield + - [x] Express Middleware - [ ] Add Tests **Help Wanted** - [ ] Serverless? diff --git a/examples/minimal-ejected/package.json b/examples/minimal-ejected/package.json index 0e12efd..60e4183 100644 --- a/examples/minimal-ejected/package.json +++ b/examples/minimal-ejected/package.json @@ -6,10 +6,14 @@ "build": "yoga build", "build:ci": "yarn build", "start": "yoga start", - "lint": "echo linting disabled" + "lint": "echo linting disabled", + "eject": "yoga eject" + }, "dependencies": { - "@atto-byte/yoga": "latest" + "@atto-byte/yoga": "latest", + "graphql-shield": "^5.3.4", + "rimraf": "^2.6.3" }, "devDependencies": { "@types/graphql": "^14.0.4", diff --git a/examples/minimal-ejected/src/graphqlMiddleware.ts b/examples/minimal-ejected/src/graphqlMiddleware.ts new file mode 100644 index 0000000..25177be --- /dev/null +++ b/examples/minimal-ejected/src/graphqlMiddleware.ts @@ -0,0 +1,27 @@ +import { and, or, rule, shield } from 'graphql-shield'; +import { ShieldRule } from 'graphql-shield/dist/types'; +import { NexusGenArgTypes } from './generated/nexus'; +type NexusPermissions = { + [T in keyof NexusGenArgTypes]?: { + [P in keyof NexusGenArgTypes[T]]?: ShieldRule + } +} +const isAuthenticated = rule('isAuthenticated')(async (parent, args, ctx, info) => { + console.log('You are not Authenticated') + return false +}) + + +const ruleTree: NexusPermissions = { + Query:{ + filterPosts: isAuthenticated + }, + Mutation:{ + createDraft: isAuthenticated, + deletePost: isAuthenticated + } +} + +const permissions = shield(ruleTree) + +export default [permissions] \ No newline at end of file diff --git a/examples/minimal-ejected/src/server.ts b/examples/minimal-ejected/src/server.ts index 6b66de6..610fdfa 100644 --- a/examples/minimal-ejected/src/server.ts +++ b/examples/minimal-ejected/src/server.ts @@ -1,51 +1,56 @@ -import { ApolloServer, express, makeSchema, yogaEject } from '@atto-byte/yoga' -import { Server } from 'http' import * as path from 'path' -import context from './context' +import { + ApolloServer, + makeSchema, + express, + yogaEject, + middleware, +} from '@atto-byte/yoga' import * as types from './graphql' +import context from './context' + +import graphqlMiddleware from './graphqlMiddleware' export default yogaEject({ async server() { - const app = express() - - const schema = makeSchema({ + let schema = makeSchema({ types, outputs: { - schema: path.join(__dirname, './schema.graphql'), + schema: path.join(__dirname, './generated/schema.graphql'), typegen: path.join(__dirname, './generated/nexus.ts'), }, + nonNullDefaults: { + input: true, + output: true, + }, typegenAutoConfig: { sources: [ { source: path.join(__dirname, './context.ts'), alias: 'ctx', }, + , ], contextType: 'ctx.Context', }, }) - + schema = middleware.applyMiddleware(schema, ...graphqlMiddleware) const apolloServer = new ApolloServer.ApolloServer({ schema, context, }) + const app = express() apolloServer.applyMiddleware({ app, path: '/' }) return app }, - async startServer(express) { - return new Promise((resolve, reject) => { - const httpServer = express - .listen({ port: 4000 }, () => { - console.log(`🚀 Server ready at http://localhost:4000/`) - - resolve(httpServer) - }) - .on('error', err => reject(err)) + async startServer(app) { + return app.listen({ port: 4000 }, () => { + console.log(`🚀 Server ready at http://localhost:4000/`) }) }, - async stopServer(httpServer) { - return httpServer.close() + async stopServer(http) { + http.close() }, }) diff --git a/examples/minimal/package.json b/examples/minimal/package.json index 587976b..043394d 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -6,10 +6,14 @@ "build": "yoga build", "build:ci": "yarn build", "start": "yoga start", - "lint": "echo linting disabled" + "lint": "echo linting disabled", + "eject": "yoga eject" + }, "dependencies": { - "@atto-byte/yoga": "latest" + "@atto-byte/yoga": "latest", + "graphql-shield": "^5.3.4", + "rimraf": "^2.6.3" }, "devDependencies": { "@types/graphql": "^14.0.4", diff --git a/examples/minimal/src/express.ts b/examples/minimal/src/express.ts new file mode 100644 index 0000000..c7138d3 --- /dev/null +++ b/examples/minimal/src/express.ts @@ -0,0 +1,21 @@ + +export default ({ app }) => { + app.post( + '/subscribe', + [ + (req, res, next) => console.log("Express Middleware - /subscribe") + ] + ) + + + // Graphql Post Handling + app.post( + '/', + [ + + //checkJwt, + //handleTokenError, + (req, res, next) => console.log("Express Middleware") + ] + ); +} \ No newline at end of file diff --git a/examples/minimal/src/graphqlMiddleware.ts b/examples/minimal/src/graphqlMiddleware.ts new file mode 100644 index 0000000..25177be --- /dev/null +++ b/examples/minimal/src/graphqlMiddleware.ts @@ -0,0 +1,27 @@ +import { and, or, rule, shield } from 'graphql-shield'; +import { ShieldRule } from 'graphql-shield/dist/types'; +import { NexusGenArgTypes } from './generated/nexus'; +type NexusPermissions = { + [T in keyof NexusGenArgTypes]?: { + [P in keyof NexusGenArgTypes[T]]?: ShieldRule + } +} +const isAuthenticated = rule('isAuthenticated')(async (parent, args, ctx, info) => { + console.log('You are not Authenticated') + return false +}) + + +const ruleTree: NexusPermissions = { + Query:{ + filterPosts: isAuthenticated + }, + Mutation:{ + createDraft: isAuthenticated, + deletePost: isAuthenticated + } +} + +const permissions = shield(ruleTree) + +export default [permissions] \ No newline at end of file diff --git a/examples/with-prisma-ejected/package.json b/examples/with-prisma-ejected/package.json index 25d72eb..088cd77 100644 --- a/examples/with-prisma-ejected/package.json +++ b/examples/with-prisma-ejected/package.json @@ -7,10 +7,14 @@ "build:ci": "npx nexus-prisma-generate --output ./src/generated/nexus-prisma && yarn prisma generate && yoga build", "start": "yoga start", "scaffold": "yoga scaffold", - "lint": "echo linting disabled" + "lint": "echo linting disabled", + "eject": "yoga eject" + }, "dependencies": { - "@atto-byte/yoga": "latest" + "@atto-byte/yoga": "latest", + "graphql-shield": "^5.3.4", + "rimraf": "^2.6.3" }, "devDependencies": { "@types/graphql": "^14.2.0", diff --git a/examples/with-prisma-ejected/src/graphqlMiddleware.ts b/examples/with-prisma-ejected/src/graphqlMiddleware.ts new file mode 100644 index 0000000..25177be --- /dev/null +++ b/examples/with-prisma-ejected/src/graphqlMiddleware.ts @@ -0,0 +1,27 @@ +import { and, or, rule, shield } from 'graphql-shield'; +import { ShieldRule } from 'graphql-shield/dist/types'; +import { NexusGenArgTypes } from './generated/nexus'; +type NexusPermissions = { + [T in keyof NexusGenArgTypes]?: { + [P in keyof NexusGenArgTypes[T]]?: ShieldRule + } +} +const isAuthenticated = rule('isAuthenticated')(async (parent, args, ctx, info) => { + console.log('You are not Authenticated') + return false +}) + + +const ruleTree: NexusPermissions = { + Query:{ + filterPosts: isAuthenticated + }, + Mutation:{ + createDraft: isAuthenticated, + deletePost: isAuthenticated + } +} + +const permissions = shield(ruleTree) + +export default [permissions] \ No newline at end of file diff --git a/examples/with-prisma-ejected/src/server.ts b/examples/with-prisma-ejected/src/server.ts index 47519d9..7d986eb 100644 --- a/examples/with-prisma-ejected/src/server.ts +++ b/examples/with-prisma-ejected/src/server.ts @@ -1,27 +1,28 @@ +import * as path from 'path' import { ApolloServer, - express, makePrismaSchema, + express, yogaEject, + middleware, } from '@atto-byte/yoga' -import { Server } from 'http' -import * as path from 'path' -import context from './context' import * as types from './graphql' +import context from './context' + +import graphqlMiddleware from './graphqlMiddleware' import datamodelInfo from './generated/nexus-prisma' import { prisma } from './generated/prisma-client' + export default yogaEject({ async server() { - const app = express() - - const schema = makePrismaSchema({ + let schema = makePrismaSchema({ types, prisma: { datamodelInfo, client: prisma, }, outputs: { - schema: path.join(__dirname, './schema.graphql'), + schema: path.join(__dirname, './generated/schema.graphql'), typegen: path.join(__dirname, './generated/nexus.ts'), }, nonNullDefaults: { @@ -38,32 +39,29 @@ export default yogaEject({ source: path.join(__dirname, './generated/prisma-client/index.ts'), alias: 'prisma', }, + , ], contextType: 'ctx.Context', }, }) + schema = middleware.applyMiddleware(schema, ...graphqlMiddleware) const apolloServer = new ApolloServer.ApolloServer({ schema, context, }) + const app = express() apolloServer.applyMiddleware({ app, path: '/' }) return app }, - async startServer(express) { - return new Promise((resolve, reject) => { - const httpServer = express - .listen({ port: 4000 }, () => { - console.log(`🚀 Server ready at http://localhost:4000/`) - - resolve(httpServer) - }) - .on('error', err => reject(err)) + async startServer(app) { + return app.listen({ port: 4000 }, () => { + console.log(`🚀 Server ready at http://localhost:4000/`) }) }, - async stopServer(httpServer) { - return httpServer.close() + async stopServer(http) { + http.close() }, }) diff --git a/examples/with-prisma/package.json b/examples/with-prisma/package.json index 65eec33..01e4a4d 100644 --- a/examples/with-prisma/package.json +++ b/examples/with-prisma/package.json @@ -6,11 +6,14 @@ "build": "yoga build", "build:ci": "npx nexus-prisma-generate --output ./src/generated/nexus-prisma && yarn prisma generate && yoga build", "start": "yoga start", + "eject": "yoga eject", "scaffold": "yoga scaffold", "lint": "echo linting disabled" }, "dependencies": { - "@atto-byte/yoga": "latest" + "@atto-byte/yoga": "latest", + "graphql-shield": "^5.3.4", + "rimraf": "^2.6.3" }, "devDependencies": { "@types/graphql": "^14.2.0", diff --git a/examples/with-prisma/prisma/graphqlMiddleware.ts b/examples/with-prisma/prisma/graphqlMiddleware.ts new file mode 100644 index 0000000..25177be --- /dev/null +++ b/examples/with-prisma/prisma/graphqlMiddleware.ts @@ -0,0 +1,27 @@ +import { and, or, rule, shield } from 'graphql-shield'; +import { ShieldRule } from 'graphql-shield/dist/types'; +import { NexusGenArgTypes } from './generated/nexus'; +type NexusPermissions = { + [T in keyof NexusGenArgTypes]?: { + [P in keyof NexusGenArgTypes[T]]?: ShieldRule + } +} +const isAuthenticated = rule('isAuthenticated')(async (parent, args, ctx, info) => { + console.log('You are not Authenticated') + return false +}) + + +const ruleTree: NexusPermissions = { + Query:{ + filterPosts: isAuthenticated + }, + Mutation:{ + createDraft: isAuthenticated, + deletePost: isAuthenticated + } +} + +const permissions = shield(ruleTree) + +export default [permissions] \ No newline at end of file diff --git a/examples/with-prisma/src/express.ts b/examples/with-prisma/src/express.ts new file mode 100644 index 0000000..c7138d3 --- /dev/null +++ b/examples/with-prisma/src/express.ts @@ -0,0 +1,21 @@ + +export default ({ app }) => { + app.post( + '/subscribe', + [ + (req, res, next) => console.log("Express Middleware - /subscribe") + ] + ) + + + // Graphql Post Handling + app.post( + '/', + [ + + //checkJwt, + //handleTokenError, + (req, res, next) => console.log("Express Middleware") + ] + ); +} \ No newline at end of file diff --git a/examples/with-prisma/src/graphqlMiddleware.ts b/examples/with-prisma/src/graphqlMiddleware.ts new file mode 100644 index 0000000..25177be --- /dev/null +++ b/examples/with-prisma/src/graphqlMiddleware.ts @@ -0,0 +1,27 @@ +import { and, or, rule, shield } from 'graphql-shield'; +import { ShieldRule } from 'graphql-shield/dist/types'; +import { NexusGenArgTypes } from './generated/nexus'; +type NexusPermissions = { + [T in keyof NexusGenArgTypes]?: { + [P in keyof NexusGenArgTypes[T]]?: ShieldRule + } +} +const isAuthenticated = rule('isAuthenticated')(async (parent, args, ctx, info) => { + console.log('You are not Authenticated') + return false +}) + + +const ruleTree: NexusPermissions = { + Query:{ + filterPosts: isAuthenticated + }, + Mutation:{ + createDraft: isAuthenticated, + deletePost: isAuthenticated + } +} + +const permissions = shield(ruleTree) + +export default [permissions] \ No newline at end of file diff --git a/src/cli/commands/build/renderers.ts b/src/cli/commands/build/renderers.ts index bc8bcb2..6f1d3d5 100644 --- a/src/cli/commands/build/renderers.ts +++ b/src/cli/commands/build/renderers.ts @@ -171,7 +171,7 @@ ${renderImportIf('graphqlMiddleware', fileDir, info.yogaConfig.graphqlMiddleware export default yogaEject({ async server() { - const schema = makeSchema({ + let schema = makeSchema({ types, outputs: { schema: ${info.yogaConfig.output.schemaPath && diff --git a/src/cli/commands/new/scaffold.ts b/src/cli/commands/new/scaffold.ts index 75b3f67..4b74311 100644 --- a/src/cli/commands/new/scaffold.ts +++ b/src/cli/commands/new/scaffold.ts @@ -25,7 +25,7 @@ const PACKAGE_JSON = `\ "scaffold": "yoga scaffold" }, "dependencies": { - "@atto-byte/yoga": "0.0.6" + "@atto-byte/yoga": "latest" }, "devDependencies": { "@types/graphql": "^14.0.4",