create-root-schema
Advanced tools
Comparing version 1.2.0 to 2.0.0
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports.default = createRootSchema; | ||
var _graphqlTools = require("graphql-tools"); | ||
var _lodash = _interopRequireDefault(require("lodash.merge")); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function createRootSchema(schemas, options) { | ||
// Query and Mutation must be non-empty, even if they will be extended | ||
const rootTypes = | ||
/* GraphQL */ | ||
` | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const graphql_tools_1 = require("graphql-tools"); | ||
const unchanged_1 = require("unchanged"); | ||
function extendIfExists(obj, part) { | ||
return part ? unchanged_1.merge(null, obj, part) : obj; | ||
} | ||
function mergeSchemaPart(schema, part) { | ||
return { | ||
// deeply merge the resolver with the rest of the schema | ||
resolvers: extendIfExists(schema.resolvers, part.resolvers), | ||
// deeply merge the schemaDirectives | ||
schemaDirectives: extendIfExists(schema.schemaDirectives, part.schemaDirectives), | ||
// append type definitions to existing type definitions | ||
typeDefs: part.typeDefs | ||
? schema.typeDefs.concat(part.typeDefs) | ||
: schema.typeDefs | ||
}; | ||
} | ||
function combineSchemaDefinitions(schemaParts) { | ||
// Query and Mutation must be non-empty, even if they will be extended | ||
const rootTypes = /* GraphQL */ ` | ||
type Mutation { | ||
_: String | ||
_bootstrap_: String | ||
} | ||
type Query { | ||
_: String | ||
_bootstrap_: String | ||
} | ||
`; // Combine types and resolvers into an object usable by `makeExecutableSchema` | ||
const { | ||
resolvers, | ||
typeDefs | ||
} = schemas.reduce((schemaList, schema) => ({ | ||
resolvers: (0, _lodash.default)(schemaList.resolvers, schema.resolvers), | ||
typeDefs: [...schemaList.typeDefs, ...(Array.isArray(schema.type) ? schema.type : [schema.type])] | ||
}), { | ||
typeDefs: [rootTypes] | ||
}); | ||
return (0, _graphqlTools.makeExecutableSchema)({ | ||
resolvers, | ||
typeDefs, | ||
...options | ||
}); | ||
} | ||
`; | ||
// Combine types and resolvers into an object usable by `makeExecutableSchema` | ||
return schemaParts.reduce(mergeSchemaPart, { | ||
resolvers: {}, | ||
schemaDirectives: {}, | ||
typeDefs: [rootTypes] | ||
}); | ||
} | ||
exports.combineSchemaDefinitions = combineSchemaDefinitions; | ||
function makeExecutableSchema(schemaParts, options) { | ||
const combinedSchema = combineSchemaDefinitions(schemaParts); | ||
return graphql_tools_1.makeExecutableSchema({ ...combinedSchema, ...options }); | ||
} | ||
exports.makeExecutableSchema = makeExecutableSchema; | ||
//# sourceMappingURL=index.js.map |
100
package.json
{ | ||
"name": "create-root-schema", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"main": "dist/index.js", | ||
"module": "src/index.js", | ||
"repository": "https://github.com/gsandf/create-root-schema", | ||
@@ -10,72 +9,33 @@ "author": "GS&F Devs <mindreactor@gsandf.com> (https://gsandf.com/)", | ||
"files": [ | ||
"src/index.js", | ||
"dist/index.js" | ||
"dist/**" | ||
], | ||
"types": "dist/index.d.ts", | ||
"ava": { | ||
"babel": { | ||
"testOptions": { | ||
"presets": [ | ||
"@babel/preset-env" | ||
] | ||
} | ||
}, | ||
"extensions": [ | ||
"ts" | ||
], | ||
"files": [ | ||
"src/**/*.test.ts" | ||
], | ||
"ignoredByWatcher": [ | ||
"!src/**" | ||
], | ||
"require": [ | ||
"@babel/polyfill", | ||
"@babel/register" | ||
"ts-node/register" | ||
] | ||
}, | ||
"babel": { | ||
"presets": [ | ||
[ | ||
"@babel/preset-env", | ||
{ | ||
"targets": { | ||
"node": true | ||
} | ||
} | ||
] | ||
], | ||
"plugins": [ | ||
"@babel/plugin-proposal-export-default-from", | ||
"@babel/plugin-proposal-export-namespace-from", | ||
"@babel/plugin-syntax-dynamic-import", | ||
"@babel/plugin-syntax-import-meta", | ||
"@babel/plugin-proposal-class-properties", | ||
"@babel/plugin-proposal-json-strings", | ||
[ | ||
"@babel/plugin-proposal-decorators", | ||
{ | ||
"legacy": true | ||
} | ||
], | ||
"@babel/plugin-proposal-function-sent", | ||
"@babel/plugin-proposal-numeric-separator", | ||
"@babel/plugin-proposal-throw-expressions" | ||
] | ||
"dependencies": { | ||
"graphql": "^14.0.0", | ||
"graphql-tools": "^4.0.0", | ||
"unchanged": "^2.0.0" | ||
}, | ||
"eslintConfig": { | ||
"extends": "gsandf", | ||
"parser": "babel-eslint" | ||
}, | ||
"devDependencies": { | ||
"@babel/cli": "^7.0.0", | ||
"@babel/core": "^7.0.0", | ||
"@babel/plugin-proposal-class-properties": "^7.0.0", | ||
"@babel/plugin-proposal-decorators": "^7.0.0", | ||
"@babel/plugin-proposal-export-default-from": "^7.0.0", | ||
"@babel/plugin-proposal-export-namespace-from": "^7.0.0", | ||
"@babel/plugin-proposal-function-sent": "^7.0.0", | ||
"@babel/plugin-proposal-json-strings": "^7.0.0", | ||
"@babel/plugin-proposal-numeric-separator": "^7.0.0", | ||
"@babel/plugin-proposal-throw-expressions": "^7.0.0", | ||
"@babel/plugin-syntax-dynamic-import": "^7.0.0", | ||
"@babel/plugin-syntax-import-meta": "^7.0.0", | ||
"@babel/polyfill": "^7.4.4", | ||
"@babel/preset-env": "^7.0.0", | ||
"@babel/register": "^7.4.4", | ||
"ava": "^2.2.0", | ||
"babel-eslint": "^9.0.0", | ||
"eslint": "^4.19.1", | ||
"eslint-config-gsandf": "^1.0.1", | ||
"graphql": "^14.0.0" | ||
"@typescript-eslint/eslint-plugin": "^2.23.0", | ||
"@typescript-eslint/parser": "^2.23.0", | ||
"amper-scripts": "^1.0.0-0", | ||
"ava": "^3.5.0", | ||
"nodemon": "^2.0.2", | ||
"prettier": "^1.19.1", | ||
"ts-node": "^8.6.2", | ||
"typescript": "^3.8.3" | ||
}, | ||
@@ -85,9 +45,7 @@ "peerDependencies": { | ||
}, | ||
"dependencies": { | ||
"graphql-tools": "^4.0.4", | ||
"lodash.merge": "^4.6.2" | ||
}, | ||
"scripts": { | ||
"build": "babel --only src/index.js -d dist src", | ||
"lint": "eslint src", | ||
"build": "rm -rf dist && tsc", | ||
"format-check": "amper-scripts format-check", | ||
"format": "amper-scripts format-write", | ||
"lint": "amper-scripts lint --config ./.eslintrc.js src", | ||
"prepublish": "yarn build", | ||
@@ -94,0 +52,0 @@ "test": "ava" |
129
README.md
@@ -12,3 +12,3 @@ # create-root-schema | ||
ℹ️ This is just a very thin wrapper extending/replacing [`makeExecutableSchema`](https://www.apollographql.com/docs/graphql-tools/generate-schema.html). | ||
ℹ️ This is just a very thin wrapper extending/replacing [`makeExecutableSchema`](https://www.apollographql.com/docs/graphql-tools/generate-schema/). | ||
See [`graphql-tools`](https://www.apollographql.com/docs/graphql-tools/) for more documentation. | ||
@@ -18,16 +18,26 @@ | ||
First, all your schema files can export `type` and `resolvers` (both are optional). | ||
All your schema files can export `typeDefs`, `resolvers`, and | ||
`schemaDirectives`. All are optional. | ||
To add functionality, each file may: | ||
* extend one of the root types (i.e. `Query` and/or `Mutation`) | ||
* extend another custom type | ||
* add resolvers to one of the root types | ||
* extend resolvers of a custom type | ||
* add a custom scalar/enum. See [`graphql-tools` docs](https://www.apollographql.com/docs/graphql-tools/scalars.html) for more info or [`timestamp.js`](./src/testHelpers/schemas/timestamp.js) for an example. | ||
- Extend a root type: `Query` and/or `Mutation` | ||
- Add or extend custom typesD | ||
- Add resolvers for the types | ||
- Add a custom scalar/enum | ||
- [Example usage](./src/testHelpers/schemas/timestamp.js) | ||
- Read the [`graphql-tools` | ||
documentation](https://www.apollographql.com/docs/graphql-tools/scalars/) | ||
more more information | ||
- Add a custom schema directive | ||
- [Example usage](./src/testHelpers/schemas/upperCase.js) | ||
- Read the [`graphql-tools` | ||
documentation](https://www.apollographql.com/docs/apollo-server/schema/directives/) | ||
more more information | ||
```js | ||
// Example Users schema file | ||
import users from './users'; | ||
import { fetchUser, fetchUsers } from './users'; | ||
export const type = /* GraphQL */ ` | ||
export const typeDefs = /* GraphQL */ ` | ||
type User { | ||
@@ -38,7 +48,3 @@ lastSeen: Timestamp | ||
# Just extend the root types to expose logic... | ||
extend type Mutation { | ||
seen (id: ID!): User | ||
} | ||
# Extend the root types to expose logic... | ||
extend type Query { | ||
@@ -51,11 +57,5 @@ user(id: ID!): User | ||
export const resolvers = { | ||
Mutation: { | ||
seen: (_, { id }) => { | ||
const user = userList.findById(id); | ||
user.lastSeen = Date.now(); | ||
return user; | ||
} | ||
}, | ||
Query: { | ||
user: (_, { id }) => users.findById(id) | ||
user: (_, { id }) => fetchUser(id), | ||
users: () => fetchUsers() | ||
} | ||
@@ -65,8 +65,10 @@ }; | ||
Then, import whatever files used into a single file and create the root schema: | ||
Then, import the schema parts into a single file and create a root schema: | ||
```js | ||
import createRootSchema from 'create-root-schema'; | ||
import { | ||
combineSchemaDefinitions, | ||
makeExecutableSchema | ||
} from 'create-root-schema'; | ||
import * as brand from './brand'; | ||
import * as device from './device'; | ||
@@ -76,17 +78,17 @@ import * as notification from './notification'; | ||
export default createRootSchema([brand, device, notification, user]); | ||
``` | ||
// NOTE: Choose one of these options… | ||
As an alternative, you may opt to use a package that requires all matching files. | ||
That should work fine; we've just opted to be explicit here. | ||
// - option 1: get the combined schema: | ||
export default combineSchemaDefinitions([device, notification, user]); | ||
### Usage with a Server | ||
// - option 2: both combine the schema and convert to an executable schema: | ||
export default makeExecutableSchema([device, notification, user]); | ||
``` | ||
We use `apollo-server-express`, but any Node.js server should be similar: | ||
### Usage with [`apollo-server-express` v2](https://github.com/apollographql/apollo-server) | ||
```js | ||
// ./schemas/index.js | ||
import createRootSchema from 'create-root-schema'; | ||
import { combineSchemaDefinitions } from 'create-root-schema'; | ||
import * as brand from './brand'; | ||
import * as device from './device'; | ||
@@ -96,3 +98,3 @@ import * as notification from './notification'; | ||
export default createRootSchema([brand, device, notification, user]); | ||
export default combineSchemaDefinitions([brand, device, notification, user]); | ||
``` | ||
@@ -102,37 +104,36 @@ | ||
// ./index.js | ||
import { graphqlExpress } from 'apollo-server-express'; | ||
import { ApolloServer, gql } from 'apollo-server-express'; | ||
import express from 'express'; | ||
import schema from './schemas'; | ||
app.use('/graphql', graphqlExpress(req => ({ schema }))); | ||
const app = express(); | ||
const server = new ApolloServer(schema); | ||
server.applyMiddleware({ app }); | ||
app.listen({ port: 4000 }, () => | ||
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`) | ||
); | ||
``` | ||
### Separate Files | ||
### Usage with [`graphql-yoga`](https://github.com/prisma-labs/graphql-yoga) | ||
Sometimes types & resolvers make sense broken out into more files. You can do | ||
this however you like. Here's one possibility: | ||
```js | ||
// ./schemas/index.js | ||
import { combineSchemaDefinitions } from 'create-root-schema'; | ||
```graphql | ||
# ./schemas/product/type.graphql | ||
import * as device from './device'; | ||
import * as notification from './notification'; | ||
import * as user from './user'; | ||
type Product { | ||
id: ID! | ||
name: String | ||
stock: Int | ||
# | ||
# ...so many fields | ||
# | ||
} | ||
export default combineSchemaDefinitions([brand, device, notification, user]); | ||
``` | ||
```js | ||
// ./schemas/product/index.js | ||
import { GraphQLServer } from 'graphql-yoga'; | ||
import schema from './schemas'; | ||
// using something like `babel-plugin-inline-import` | ||
import userType from './type.graphql'; | ||
export const type = userType; | ||
export const resolvers = { | ||
// ... | ||
}; | ||
const server = new GraphQLServer(schema); | ||
server.start(() => console.log('Server is running on localhost:4000')); | ||
``` | ||
@@ -142,9 +143,9 @@ | ||
This is just a thin wrapper around [`makeExecutableSchema`](https://www.apollographql.com/docs/graphql-tools/generate-schema.html). Any options passed as the second argument will be forwarded directly to `makeExecutableSchema`. | ||
This is just a thin wrapper around [`makeExecutableSchema`](https://www.apollographql.com/docs/graphql-tools/generate-schema/). Any options passed as the second argument will be forwarded directly to `makeExecutableSchema`. | ||
```js | ||
import createRootSchema from 'create-root-schema'; | ||
import { makeExecutableSchema } from 'create-root-schema'; | ||
// See `makeExecutableSchema` docs for more information | ||
createRootSchema([...schemas], { allowUndefinedInResolve: false }); | ||
// See `graphql-tools` docs for more information | ||
makeExecutableSchema([...schemas], { allowUndefinedInResolve: false }); | ||
``` | ||
@@ -163,8 +164,4 @@ | ||
## See Also | ||
* [`okgrow/merge-graphql-schemas`](https://github.com/okgrow/merge-graphql-schemas) - A utility library to facilitate merging of modularized GraphQL schemas and resolver objects. | ||
## License | ||
MIT |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
306994
8
6
4
61
158
1
+ Addedgraphql@^14.0.0
+ Addedunchanged@^2.0.0
+ Addedcurriable@1.3.0(transitive)
+ Addedpathington@1.1.7(transitive)
+ Addedunchanged@2.2.1(transitive)
- Removedlodash.merge@^4.6.2
- Removedlodash.merge@4.6.2(transitive)
Updatedgraphql-tools@^4.0.0