Skip to content

Commit fdfd53f

Browse files
committed
Updated documentation and removed unnecessary types and files.
1 parent 4e68e3b commit fdfd53f

3 files changed

Lines changed: 123 additions & 77 deletions

File tree

README.md

Lines changed: 123 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,31 +127,143 @@ const server = new ApolloServer({ schema, context });
127127

128128
### Data Sources
129129

130-
Data sources in `graphql-component` use a proxy-based approach for context injection:
130+
Data sources in `graphql-component` use a proxy-based approach for context injection. The library provides two key types to assist with correct implementation:
131131

132-
```javascript
133-
class PropertyDataSource {
134-
async getPropertyById(context, id) {
135-
// context is automatically injected
136-
return await this.fetchProperty(id);
132+
```typescript
133+
// When implementing a data source:
134+
class MyDataSource implements DataSourceDefinition<MyDataSource> {
135+
name = 'MyDataSource';
136+
137+
// Context must be the first parameter when implementing
138+
async getUserById(context: ComponentContext, id: string) {
139+
// Use context for auth, config, etc.
140+
return { id, name: 'User Name' };
137141
}
138142
}
139143

140-
// Usage in resolvers
144+
// In resolvers, context is automatically injected:
141145
const resolvers = {
142146
Query: {
143-
property(_, { id }, { dataSources }) {
144-
return dataSources.PropertyDataSource.getPropertyById(id);
147+
user(_, { id }, context) {
148+
// Don't need to pass context - it's injected automatically
149+
return context.dataSources.MyDataSource.getUserById(id);
145150
}
146151
}
147152
}
148153

149-
// Component configuration
154+
// Add to component:
150155
new GraphQLComponent({
151-
dataSources: [new PropertyDataSource()]
156+
types,
157+
resolvers,
158+
dataSources: [new MyDataSource()]
152159
});
153160
```
154161

162+
#### Data Source Types
163+
164+
- `DataSourceDefinition<T>`: Interface for implementing data sources - methods must accept context as first parameter
165+
- `DataSource<T>`: Type representing data sources after proxy wrapping - context is automatically injected
166+
167+
This type system ensures proper context handling while providing a clean API for resolver usage.
168+
169+
#### TypeScript Example
170+
171+
```typescript
172+
import {
173+
GraphQLComponent,
174+
DataSourceDefinition,
175+
ComponentContext
176+
} from 'graphql-component';
177+
178+
// Define your data source with proper types
179+
class UsersDataSource implements DataSourceDefinition<UsersDataSource> {
180+
name = 'users';
181+
182+
// Static property
183+
defaultRole = 'user';
184+
185+
// Context is required as first parameter when implementing
186+
async getUserById(context: ComponentContext, id: string): Promise<User> {
187+
// Access context properties (auth, etc.)
188+
const apiKey = context.config?.apiKey;
189+
190+
// Implementation details...
191+
return { id, name: 'User Name', role: this.defaultRole };
192+
}
193+
194+
async getUsersByRole(context: ComponentContext, role: string): Promise<User[]> {
195+
// Implementation details...
196+
return [
197+
{ id: '1', name: 'User 1', role },
198+
{ id: '2', name: 'User 2', role }
199+
];
200+
}
201+
}
202+
203+
// In resolvers, the context is automatically injected
204+
const resolvers = {
205+
Query: {
206+
user: (_, { id }, context) => {
207+
// No need to pass context - it's injected by the proxy
208+
return context.dataSources.users.getUserById(id);
209+
},
210+
usersByRole: (_, { role }, context) => {
211+
// No need to pass context - it's injected by the proxy
212+
return context.dataSources.users.getUsersByRole(role);
213+
}
214+
}
215+
};
216+
217+
// Component configuration
218+
const usersComponent = new GraphQLComponent({
219+
types: `
220+
type User {
221+
id: ID!
222+
name: String!
223+
role: String!
224+
}
225+
226+
type Query {
227+
user(id: ID!): User
228+
usersByRole(role: String!): [User]
229+
}
230+
`,
231+
resolvers,
232+
dataSources: [new UsersDataSource()]
233+
});
234+
```
235+
236+
#### Data Source Overrides
237+
238+
You can override data sources when needed (for testing or extending functionality). The override must follow the same interface:
239+
240+
```typescript
241+
// For testing - create a mock data source
242+
class MockUsersDataSource implements DataSourceDefinition<UsersDataSource> {
243+
name = 'users';
244+
defaultRole = 'admin';
245+
246+
async getUserById(context: ComponentContext, id: string) {
247+
return { id, name: 'Mock User', role: this.defaultRole };
248+
}
249+
250+
async getUsersByRole(context: ComponentContext, role: string) {
251+
return [{ id: 'mock', name: 'Mock User', role }];
252+
}
253+
}
254+
255+
// Use the component with overrides
256+
const testComponent = new GraphQLComponent({
257+
imports: [usersComponent],
258+
dataSourceOverrides: [new MockUsersDataSource()]
259+
});
260+
261+
// In tests
262+
const context = await testComponent.context({});
263+
const mockUser = await context.dataSources.users.getUserById('any-id');
264+
// mockUser will be { id: 'any-id', name: 'Mock User', role: 'admin' }
265+
```
266+
155267
## Examples
156268

157269
The repository includes example implementations:

src/README-context-utils.md

Lines changed: 0 additions & 50 deletions
This file was deleted.

src/index.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,6 @@ import { SubschemaConfig } from '@graphql-tools/delegate';
1818

1919
const debug = debugConfig('graphql-component');
2020

21-
// Re-export the context utility types
22-
/**
23-
* Utility type to extract and merge contexts from multiple components
24-
* @template TContexts - Array of component context types to merge
25-
*/
26-
export type MergeComponentContexts<TContexts extends ComponentContext[]> = ComponentContext & {
27-
dataSources: UnionToIntersection<TContexts[number]['dataSources']>
28-
};
29-
30-
/**
31-
* Utility type to convert a union type to an intersection type
32-
* This allows multiple component dataSources to be merged correctly
33-
*/
34-
export type UnionToIntersection<U> =
35-
(U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
36-
3721
export type ResolverFunction = (_: any, args: any, ctx: any, info: GraphQLResolveInfo) => any;
3822

3923
export interface IGraphQLComponentConfigObject {

0 commit comments

Comments
 (0)