Skip to content

Commit 881d50c

Browse files
authored
Merge pull request #2 from nnoce14:fix-readme
Updated README
2 parents 7c90f2d + b00de1b commit 881d50c

File tree

1 file changed

+69
-33
lines changed

1 file changed

+69
-33
lines changed

README.md

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
[![npm version](https://badge.fury.io/js/apollo-datasource-mongodb.svg)](https://www.npmjs.com/package/apollo-datasource-mongodb)
1+
<!-- [![npm version](https://badge.fury.io/js/apollo-datasource-mongodb.svg)](https://www.npmjs.com/package/apollo-datasource-mongodb) -->
22

33
MongoDB [data source](https://www.apollographql.com/docs/apollo-server/data/fetching-data) for Apollo Server 4
44

5+
This is a forked repository from [apollo-datasource-mongodb](https://github.com/GraphQLGuide/apollo-datasource-mongodb) that implemented
6+
some changes made to data sources in Apollo Server 4. The package this is forking uses Apollo Server 3 conventions. I updated the `MongoDataSource` class
7+
in this package to be compliant with Apollo Server 4 data sources. See [dataSources](https://www.apollographql.com/docs/apollo-server/migration/#datasources) for more information.
8+
9+
**Installation**
510
```
611
npm i apollo-mongo-datasource
712
```
@@ -77,17 +82,19 @@ const { url } = await startStandaloneServer(server, {
7782
})
7883
```
7984

80-
Inside the data source, the collection is available at `this.collection` (e.g. `this.collection.update({_id: 'foo, { $set: { name: 'me' }}})`). The model (if you're using Mongoose) is available at `this.model` (`new this.model({ name: 'Alice' })`). In Apollo Server 3, the context was automatically handled by the abstract DataSource class from apollo-datasource. This package has been deprecated, so the DataSource class has been removed from this package, as well as the initialize method. By default, the API classes you create will not have access to the context. You can either choose to add the data that your API class needs as private members of the class, or you can add the entire context as a member of the class if you wish. All you need to do is add the field to the options argument of the constructor and call super. Then, the request's context is available at `this.context`. For example, if you put the logged-in user's ID on context as `context.currentUserId`:
85+
Inside the data source, the collection is available at `this.collection` (e.g. `this.collection.update({_id: 'foo, { $set: { name: 'me' }}})`). The model (if you're using Mongoose) is available at `this.model` (`new this.model({ name: 'Alice' })`). In Apollo Server 3, the context was automatically handled by the abstract `DataSource` class from apollo-datasource. This package has been deprecated, so the `DataSource` class has been removed from this package, as well as the initialize method.
86+
87+
By default, the API classes you create will not have access to the context. You can either choose to add the data that your API class needs on a case-by-case basis as members of the class, or you can add the entire context as a member of the class if you wish. All you need to do is add the field(s) to the options argument of the constructor and call super passing in options. For example, if you put the logged-in user's ID on context as `context.currentUserId` and you want your Users class to have access to `currentUserId`:
8188

8289
```js
8390
class Users extends MongoDataSource {
8491
constructor(options) {
8592
super(options)
86-
this.context = options.context
93+
this.currentUserId = options.currentUserId
8794
}
8895

8996
async getPrivateUserData(userId) {
90-
const isAuthorized = this.context.currentUserId === userId
97+
const isAuthorized = this.currentUserId === userId
9198
if (isAuthorized) {
9299
const user = await this.findOneById(userId)
93100
return user && user.privateData
@@ -96,7 +103,7 @@ class Users extends MongoDataSource {
96103
}
97104
```
98105

99-
and you would instantiate the Users class like this
106+
and you would instantiate the Users data source in the context like this
100107

101108
```js
102109
...
@@ -106,27 +113,55 @@ const server = new ApolloServer({
106113
})
107114

108115
const { url } = await startStandaloneServer(server, {
109-
context: async ({ req }) => ({
110-
dataSources: {
111-
users: new Users({ modelOrCollection: UserModel, context: { currentUserId: '123' } })
116+
context: async ({ req }) => {
117+
const currentUserId = getCurrentUserId(req) // not a real function, for demo purposes only
118+
return {
119+
currentUserId,
120+
dataSources: {
121+
users: new Users({ modelOrCollection: UserModel, currentUserId })
122+
},
112123
}
113-
}),
124+
},
114125
});
115126
```
116127

117-
If you want your data source to have access to the entire context, you need to create a Context class so the context can refer to itself as this in the constructor for the data source.
128+
If you want your data source to have access to the entire context at `this.context`, you need to create a `Context` class so the context can refer to itself as `this` in the constructor for the data source.
118129
See [dataSources](https://www.apollographql.com/docs/apollo-server/migration/#datasources) for more information regarding how data sources changed from Apollo Server 3 to Apollo Server 4.
119130

120131
```js
132+
class Users extends MongoDataSource {
133+
constructor(options) {
134+
super(options)
135+
this.context = options.context
136+
}
137+
138+
async getPrivateUserData(userId) {
139+
const isAuthorized = this.context.currentUserId === userId
140+
if (isAuthorized) {
141+
const user = await this.findOneById(userId)
142+
return user && user.privateData
143+
}
144+
}
145+
}
146+
147+
...
148+
121149
class Context {
122-
constructor() {
150+
constructor(req) {
151+
this.currentUserId = getCurrentUserId(req), // not a real function, for demo purposes only
123152
this.dataSources = {
124153
users: new Users({ modelOrCollection: UserModel, context: this })
125154
},
126-
this.currentUserId = '123',
127-
...
128155
}
129156
}
157+
158+
...
159+
160+
const { url } = await startStandaloneServer(server, {
161+
context: async ({ req }) => {
162+
return new Context(req)
163+
},
164+
});
130165
```
131166

132167
If you're passing a Mongoose model rather than a collection, Mongoose will be used for data fetching. All transformations defined on that model (virtuals, plugins, etc.) will be applied to your data before caching, just like you would expect it. If you're using reference fields, you might be interested in checking out [mongoose-autopopulate](https://www.npmjs.com/package/mongoose-autopopulate).
@@ -229,17 +264,17 @@ interface UserDocument {
229264
interests: [string]
230265
}
231266

232-
// This is optional
233267
interface Context {
234268
loggedInUser: UserDocument
269+
dataSources: any
235270
}
236271

237272
export default class Users extends MongoDataSource<UserDocument, Context> {
238-
protected loggedInUser: UserDocument;
273+
protected loggedInUser: UserDocument
239274

240275
constructor(options: { loggedInUser: UserDocument } & MongoDataSourceConfig<TData>) {
241-
super(options);
242-
this.loggedInUser = options.loggedInUser;
276+
super(options)
277+
this.loggedInUser = options.loggedInUser
243278
}
244279

245280
getUser(userId) {
@@ -267,20 +302,20 @@ const server = new ApolloServer({
267302

268303
const { url } = await startStandaloneServer(server, {
269304
context: async ({ req }) => {
270-
const loggedInUser = getLoggedInUser(req); // this function does not exist, just for demo purposes
305+
const loggedInUser = getLoggedInUser(req) // this function does not exist, just for demo purposes
271306
return {
272307
loggedInUser,
273308
dataSources: {
274-
users: new Users({ modelOrCollection: client.db().collection('users'), loggedInUser})
309+
users: new Users({ modelOrCollection: client.db().collection('users'), loggedInUser }),
275310
},
276-
};
311+
}
277312
},
278313
});
279314
```
280315

281316
You can also opt to pass the entire context into your data source class. You can do so by adding a protected context member
282317
to your data source class and modifying to options argument of the constructor to add a field for the context. Then, call super and
283-
assign the context to the member field on your data source class.
318+
assign the context to the member field on your data source class. Note: context needs to be a class in order to do this.
284319

285320
```ts
286321
import { MongoDataSource } from 'apollo-mongo-datasource'
@@ -294,17 +329,24 @@ interface UserDocument {
294329
interests: [string]
295330
}
296331

297-
// This is optional
298-
interface Context {
332+
class Context {
299333
loggedInUser: UserDocument
334+
dataSources: any
335+
336+
constructor(req: any) {
337+
this.loggedInUser = getLoggedInUser(req)
338+
this.dataSources = {
339+
users: new Users({ modelOrCollection: client.db().collection('users'), context: this }),
340+
}
341+
}
300342
}
301343

302344
export default class Users extends MongoDataSource<UserDocument, Context> {
303-
protected context: Context;
345+
protected context: Context
304346

305347
constructor(options: { context: Context } & MongoDataSourceConfig<TData>) {
306-
super(options);
307-
this.context = options.context;
348+
super(options)
349+
this.context = options.context
308350
}
309351

310352
getUser(userId) {
@@ -332,13 +374,7 @@ const server = new ApolloServer({
332374

333375
const { url } = await startStandaloneServer(server, {
334376
context: async ({ req }) => {
335-
const loggedInUser = getLoggedInUser(req); // this function does not exist, just for demo purposes
336-
return {
337-
loggedInUser,
338-
dataSources: {
339-
users: new Users({ modelOrCollection: client.db().collection('users'), context: this })
340-
},
341-
};
377+
return new Context(req)
342378
},
343379
});
344380
```

0 commit comments

Comments
 (0)