Skip to content

Commit 1870996

Browse files
committed
feat(examples): add example that illustrates modular typeDef and resolver file organization
1 parent 85f11c3 commit 1870996

File tree

11 files changed

+242
-0
lines changed

11 files changed

+242
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Modular Resolvers and TypeDefs
2+
3+
This `graphql-yoga` example written in Typescript illustrates how you can have complete freedom
4+
over the structure of your **typeDef** and **resolver** files by using the
5+
[`merge-graphql-schemas` utility library](https://github.com/okgrow/merge-graphql-schemas).
6+
7+
## Get Started
8+
9+
**Clone the repository:**
10+
11+
```sh
12+
git clone https://github.com/graphcool/graphql-yoga.git
13+
cd graphql-yoga/examples/modular-resolvers
14+
```
15+
16+
**Install dependencies and run the app:**
17+
18+
```sh
19+
npm install # or yarn install
20+
npm start # or yarn start
21+
```
22+
23+
## Run the Queries
24+
25+
Open your browser at [http://localhost:4004](http://localhost:4004) and start sending queries in the Playground.
26+
27+
**In the left pane, run the `welcome` Query:**
28+
29+
```graphql
30+
{
31+
welcome(yourNickname:"Superstar")
32+
}
33+
```
34+
35+
The server returns the following response:
36+
37+
```json
38+
{
39+
"data": {
40+
"welcome": "Welcome, Superstar!"
41+
}
42+
}
43+
```
44+
45+
**Query a specific `user` by id:**
46+
47+
```graphql
48+
{
49+
user(id:2){
50+
id
51+
userName
52+
firstName
53+
lastName
54+
}
55+
}
56+
```
57+
58+
The server returns the following response:
59+
60+
```json
61+
{
62+
"data": {
63+
"user": {
64+
"id": 2,
65+
"firstName": "Kimberly",
66+
"lastName": "Jones",
67+
"userName": "kim"
68+
}
69+
}
70+
}
71+
```
72+
73+
**Query all `users`:**
74+
75+
```graphql
76+
{
77+
users{
78+
userName
79+
}
80+
}
81+
```
82+
83+
The server returns the following response:
84+
85+
```json
86+
{
87+
"data": {
88+
"users": [
89+
{
90+
"userName": "john"
91+
},
92+
{
93+
"userName": "kim"
94+
}
95+
]
96+
}
97+
}
98+
```
99+
100+
## Implementation
101+
102+
The merging takes place in the [/resolvers/index.ts](./resolvers/index.ts)
103+
and the [/typeDefs/index.ts](./typeDefs/index.ts) files.
104+
105+
Using this approach, you're free to structure resolver and typeDef files as you see fit.
106+
107+
>To avoid issues, unique naming of Queries, Mutations and Subscriptions is your responsibility.
108+
109+
Now you can structure by **function**...
110+
```
111+
+-- graphql
112+
| +-- resolvers
113+
| | +-- user.resolvers.js/ts
114+
| | +-- welcome.resolvers.js/ts
115+
| | +-- index.ts << Merges all `*.resolvers.*` files
116+
| +-- typeDefs
117+
| | +-- user.graphql
118+
| | +-- welcome.graphql
119+
| | +-- index.ts <<< Merges all `typeDef` files
120+
```
121+
122+
Or by **type**...
123+
```
124+
+-- graphql
125+
| +-- entity
126+
| | +-- user
127+
| | | +-- user.graphql
128+
| | | +-- user.resolvers.js/ts
129+
| | +-- welcome
130+
| | | +-- welcome.graphql
131+
| | | +-- welcome.resolvers.js/ts
132+
| | +-- index.ts << Merges all `*.resolvers.*` and typeDef files
133+
```
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default {
2+
3+
users: [
4+
{ id: 1, userName: 'john', firstName: 'John', lastName: 'Smith' },
5+
{ id: 2, userName: 'kim', firstName: 'Kimberly', lastName: 'Jones' },
6+
],
7+
8+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { GraphQLServer } from "graphql-yoga";
2+
import { default as typeDefs } from './typeDefs'
3+
import { default as resolvers } from './resolvers'
4+
5+
const options = { port: 4004 };
6+
7+
const server = new GraphQLServer({
8+
typeDefs,
9+
resolvers
10+
});
11+
12+
server.start(options, () =>
13+
console.log(`Server is running ⚡ on localhost:${options.port}`))
14+
.catch(err => console.error('connection Error', err));
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "modular-resolvers",
3+
"main": "index.js",
4+
"scripts": {
5+
"start": "nodemon --exec ts-node index.ts"
6+
},
7+
"dependencies": {
8+
"graphql": "^0.13.1",
9+
"graphql-yoga": "^1.6.1",
10+
"merge-graphql-schemas": "^1.5.0"
11+
},
12+
"devDependencies": {
13+
"@types/node": "^8.0.29",
14+
"nodemon": "^1.17.1",
15+
"ts-node": "5.0.1",
16+
"typescript": "2.7.2"
17+
}
18+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import * as path from "path";
2+
import { mergeResolvers, fileLoader } from "merge-graphql-schemas";
3+
4+
/* MANUAL APPROACH: Update this file manually with each resolver file */
5+
// import userResolvers from "./user.resolvers";
6+
// import welcomeResolvers from "./welcome.resolvers";
7+
// const resolversArray = [userResolvers, welcomeResolvers];
8+
9+
/* AUTOMATED APPROACH: Put your resolvers anywhere
10+
with ".resolvers.[js/ts]" naming convention */
11+
const resolversArray = fileLoader(path.join(__dirname, "./**/*.resolvers.*"));
12+
13+
const resolvers = mergeResolvers(resolversArray);
14+
15+
export default resolvers;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import data from './../data/data';
2+
3+
export default {
4+
Query: {
5+
user: async (_, { id }) => {
6+
const user = await data.users.find(user => user.id === id)
7+
return user;
8+
},
9+
users: () => data.users
10+
}
11+
};
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
Query: {
3+
welcome: (_, { yourNickname }) => `Welcome, ${yourNickname || "here"}!`
4+
}
5+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"compilerOptions": {
3+
"lib": [
4+
"dom",
5+
"es2017",
6+
"esnext.asynciterable"
7+
],
8+
"target": "es5",
9+
"module": "commonjs",
10+
"moduleResolution": "node",
11+
"outDir": "./dist",
12+
"sourceMap": true,
13+
"noImplicitAny": false,
14+
"emitDecoratorMetadata": true,
15+
"experimentalDecorators": true,
16+
}
17+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as path from "path";
2+
import { fileLoader, mergeTypes } from "merge-graphql-schemas";
3+
4+
const typesArray = fileLoader(path.join(__dirname, "./"));
5+
const typesMerged = mergeTypes(typesArray);
6+
7+
export default typesMerged;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
type User {
2+
id: Int!
3+
userName: String!
4+
firstName: String!
5+
lastName: String!
6+
}
7+
8+
type Query {
9+
user(id: Int!): User!
10+
users: [User!]!
11+
}

0 commit comments

Comments
 (0)