Skip to content

Commit 2c479ce

Browse files
committed
improve express starter, can correctly load models and dataSources
1 parent e42379e commit 2c479ce

File tree

4 files changed

+157
-109
lines changed

4 files changed

+157
-109
lines changed

src/app.ts

Lines changed: 16 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -4,128 +4,28 @@
44
import express, { Request } from "express";
55
// import cors from "cors";
66
import mongoose from "mongoose";
7-
import { ApolloServer, gql } from "apollo-server-express";
7+
import { ApolloServer } from "apollo-server-express";
88
import { makeExecutableSchema } from "@graphql-tools/schema";
99

10-
import { MongoMemoryServer } from "mongodb-memory-server"; // @see https://github.com/nodkz/mongodb-memory-server
1110
import {
12-
buildDefaultQueryResolvers,
13-
createGraphqlModelServer,
1411
buildApolloSchema,
1512
createContext,
1613
createDataSources,
1714
} from "@vulcanjs/graphql/server";
18-
import { createMongooseConnector } from "@vulcanjs/mongo";
1915
import { addDefaultMongoConnector } from "@vulcanjs/mongo-apollo";
2016

2117
import http from "http";
2218

23-
// Init an in-memory Mongo server
24-
// TODO: use a real db like in Vulcan Next
25-
let mongod;
26-
let mongoUri;
27-
const startMongo = async () => {
28-
// Spin up a dummy mongo server
29-
mongod = await MongoMemoryServer.create();
30-
mongoUri = mongod.getUri();
31-
console.log("MongoUri", mongoUri);
32-
// const port = await mongod.getPort();
33-
// const dbPath = await mongod.getDbPath();
34-
// const dbName = await mongod.getDbName();
35-
// Connect mongoose client
36-
await mongoose.connect(mongoUri);
37-
};
38-
const closeMongo = async () => {
39-
console.log("Exiting, close Mongo connection");
40-
// remove the collection
41-
// disconnect the client
42-
await mongoose.disconnect();
43-
console.log("Disconneced mongoose");
44-
// stop mongo server
45-
await mongod.stop();
46-
console.log("Closed connection");
47-
process.exit(0);
48-
};
49-
50-
// Demo model
51-
/**
52-
* Demo model
53-
*
54-
* Try this query for example:
55-
*
56-
* query contribs {
57-
contributors {
58-
results {
59-
name
60-
myself {
61-
name
62-
}
63-
}
64-
}
65-
}
66-
*/
67-
const Contributor = createGraphqlModelServer({
68-
name: "Contributor",
69-
schema: {
70-
_id: {
71-
type: String,
72-
optional: true,
73-
canRead: ["guests"],
74-
canCreate: ["guests"],
75-
canUpdate: ["guests"],
76-
//canDelete: ["guests"],
77-
},
78-
name: {
79-
type: String,
80-
optional: true,
81-
canRead: ["guests"],
82-
canCreate: ["guests"],
83-
canUpdate: ["guests"],
84-
//canDelete: ["guests"],
85-
},
86-
// Virtual field that queries the contributor itself
87-
// This is just a dumb demo for dataSources
88-
myselfVirtual: {
89-
type: String,
90-
canRead: ["guests"],
91-
canCreate: [],
92-
canUpdate: [],
93-
resolveAs: {
94-
fieldName: "myself",
95-
typeName: "Contributor",
96-
resolver: async (root /*: ContributorDocument*/, args, context) => {
97-
return await context.dataSources["Contributor"].findOneById(root._id);
98-
},
99-
},
100-
},
19+
import { startMongo, closeMongo } from "./inMemoryMongo";
20+
import { Contributor, models } from "./models";
10121

102-
// TODO: add resolved field using data source
103-
},
104-
graphql: {
105-
typeName: "Contributor",
106-
multiTypeName: "Contributors",
107-
queryResolvers: buildDefaultQueryResolvers({
108-
typeName: "Contributor",
109-
}),
110-
},
111-
permissions: {
112-
canRead: ["guests"],
113-
canCreate: ["guests"],
114-
},
115-
});
116-
const contributorConnector = createMongooseConnector(Contributor, {
117-
// Passing an instance is only needed in local development or if you have multiple mongoose connections
118-
// Otherwise the default export of "mongoose" is always the default connection
119-
mongooseInstance: mongoose,
120-
});
121-
Contributor.graphql.connector = contributorConnector;
122-
//await mongoose.models["contributors"].deleteMany();
123-
const models = [Contributor];
124-
// Will add relevant data sources where necessary
22+
// Will add relevant data sources and connectors if necessary
23+
// Using Mongo as a default
12524
addDefaultMongoConnector(models);
12625

127-
// Graphql schema
26+
// Graphql resolvers and typedefs
12827
const vulcanRawSchema = buildApolloSchema(models);
28+
// Executable graphq schema
12929
const vulcanSchema = makeExecutableSchema(vulcanRawSchema);
13030

13131
const contextForModels = createContext(models);
@@ -165,8 +65,15 @@ const startServer = async () => {
16565
const seedDb = async () => {
16666
// insert some dummy data just for testing
16767
console.log("Seeding...");
168-
await contributorConnector.delete({});
169-
await contributorConnector.create({ name: "John Doe" });
68+
/**
69+
* NOTE: calling the mongoose model directly WON'T run
70+
* the model callbacks.
71+
*
72+
* You may instead want to use a "mutator"
73+
*/
74+
const contributorMongooseModel = mongoose.models[Contributor.name];
75+
await contributorMongooseModel.remove({});
76+
await contributorMongooseModel.create({ name: "John Doe" });
17077
console.log("Done seeding db with 1 contributor");
17178
};
17279
const start = async () => {

src/inMemoryMongo.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import mongoose from "mongoose";
2+
import { MongoMemoryServer } from "mongodb-memory-server"; // @see https://github.com/nodkz/mongodb-memory-server
3+
/**
4+
* Set up a dummy, in-memory Mongo database,
5+
* just for testing.
6+
*/
7+
8+
// Init an in-memory Mongo server
9+
// TODO: use a real db like in Vulcan Next
10+
let mongod;
11+
let mongoUri;
12+
export const startMongo = async () => {
13+
// Spin up a dummy mongo server
14+
mongod = await MongoMemoryServer.create();
15+
mongoUri = mongod.getUri();
16+
console.log("MongoUri", mongoUri);
17+
// const port = await mongod.getPort();
18+
// const dbPath = await mongod.getDbPath();
19+
// const dbName = await mongod.getDbName();
20+
// Connect mongoose client
21+
await mongoose.connect(mongoUri);
22+
};
23+
export const closeMongo = async () => {
24+
console.log("Exiting, close Mongo connection");
25+
// remove the collection
26+
// disconnect the client
27+
await mongoose.disconnect();
28+
console.log("Disconneced mongoose");
29+
// stop mongo server
30+
await mongod.stop();
31+
console.log("Closed connection");
32+
process.exit(0);
33+
};

src/models.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import mongoose from "mongoose";
2+
import {
3+
buildDefaultQueryResolvers,
4+
createGraphqlModelServer,
5+
} from "@vulcanjs/graphql/server";
6+
// Optional: Vulcan will do that for you already
7+
// but here we show how you can provide your own connector if necessary
8+
// (eg for supporting SQL)
9+
import { createMongooseConnector } from "@vulcanjs/mongo";
10+
import { createMongooseDataSource } from "@vulcanjs/mongo-apollo";
11+
12+
/**
13+
* Demo model
14+
*
15+
* Try this query for example:
16+
17+
query contribs {
18+
contributors {
19+
results {
20+
name
21+
myself {
22+
name
23+
}
24+
}
25+
}
26+
}
27+
*/
28+
export const Contributor = createGraphqlModelServer({
29+
name: "Contributor",
30+
schema: {
31+
_id: {
32+
type: String,
33+
optional: true,
34+
canRead: ["guests"],
35+
canCreate: ["guests"],
36+
canUpdate: ["guests"],
37+
//canDelete: ["guests"],
38+
},
39+
name: {
40+
type: String,
41+
optional: true,
42+
canRead: ["guests"],
43+
canCreate: ["guests"],
44+
canUpdate: ["guests"],
45+
//canDelete: ["guests"],
46+
},
47+
// Virtual field that queries the contributor itself
48+
// This is just a dumb demo for Apollo dataSources
49+
myselfVirtual: {
50+
type: String,
51+
canRead: ["guests"],
52+
canCreate: [],
53+
canUpdate: [],
54+
resolveAs: {
55+
fieldName: "myself",
56+
typeName: "Contributor",
57+
resolver: async (root /*: ContributorDocument*/, args, context) => {
58+
return await context.dataSources["Contributor"].findOneById(root._id);
59+
},
60+
},
61+
},
62+
},
63+
graphql: {
64+
typeName: "Contributor",
65+
multiTypeName: "Contributors",
66+
queryResolvers: buildDefaultQueryResolvers({
67+
typeName: "Contributor",
68+
}),
69+
// Optionnaly, pass a connector
70+
// /!\ This just an example, necessary if you want to support SQL.
71+
// You can remove this field if you use Mongo
72+
createConnector: (contributorModel) =>
73+
createMongooseConnector(contributorModel, {
74+
// Passing an instance is only needed in local development or if you have multiple mongoose connections
75+
// Otherwise the default export of "mongoose" is always the default connection
76+
mongooseInstance: mongoose,
77+
}),
78+
79+
// Generate a data source for you
80+
// /!\ This just an example, necessary if you want to support SQL.
81+
// You can remove this field if you use Mongo
82+
makeCreateDataSource: (contributorModel) => () => {
83+
if (contributorModel.graphql.connector) {
84+
return createMongooseDataSource(
85+
contributorModel,
86+
contributorModel.graphql.connector
87+
);
88+
} else {
89+
console.warn(
90+
"Model",
91+
contributorModel.name,
92+
"had no connector, cannot create Apollo data source automatically."
93+
);
94+
}
95+
},
96+
},
97+
permissions: {
98+
canRead: ["guests"],
99+
canCreate: ["guests"],
100+
},
101+
});
102+
103+
//await mongoose.models["contributors"].deleteMany();
104+
export const models = [Contributor];

tsconfig.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@
1313
],
1414
"exclude": [
1515
"node_modules"
16+
],
17+
"typeRoots": [
18+
"./types",
19+
"./node_modules/@types"
1620
]
1721
}

0 commit comments

Comments
 (0)