Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite in TypeScript #110

Open
wants to merge 29 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
eea6332
working on adding some typedefs
tlivings Mar 2, 2022
e20e1bf
more to do
tlivings Mar 23, 2022
fd6f150
merged
tlivings Mar 23, 2022
1f14cb4
initial tests passing
tlivings Nov 4, 2022
da12c62
Fixed context injection, datasources, and converted examples/composit…
tlivings Nov 15, 2024
1518635
Fixed examples, fixed dataSources in contrext.
tlivings Nov 15, 2024
8b450f2
added some documentation
tlivings Nov 18, 2024
4405656
Added more tests
tlivings Nov 19, 2024
3d8db33
fallback name for data sources is the class name
tlivings Nov 19, 2024
7dab075
latest build
tlivings Nov 19, 2024
3602b8f
added a resolve binding test
tlivings Nov 19, 2024
21c993e
added a memoize test
tlivings Nov 19, 2024
50ff5cd
added more test coverage
tlivings Nov 19, 2024
ca80be8
correct context being objected to data source
tlivings Nov 20, 2024
e646fbd
updates, readme
tlivings Nov 20, 2024
e4aabb2
updated dependencies
tlivings Nov 20, 2024
28f83f2
changelog
tlivings Nov 20, 2024
cca6297
added type to context
tlivings Nov 20, 2024
d413010
fixed examples again
tlivings Nov 21, 2024
5bd591b
corrected dataSourceOverrides name
tlivings Nov 21, 2024
1d9217c
latest build
tlivings Nov 21, 2024
5426b3d
added mocks tests
tlivings Nov 21, 2024
2829731
Updated versioning to reflect the proper version planned
tlivings Jan 28, 2025
d017b5a
export GlobalContext, clean up typing for IResolvers
tlivings Jan 28, 2025
2cbb86a
Updated context to not only be extendable with a given type, but to b…
tlivings Jan 28, 2025
b9f3c7e
Merge branch 'master' into ts-conversion
tlivings Jan 28, 2025
c4611f5
Merge pull request #109 from tlivings/ts-conversion
tlivings Jan 28, 2025
415083e
Recent build
tlivings Jan 28, 2025
9827246
updated eslint
tlivings Jan 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .eslintrc

This file was deleted.

11 changes: 0 additions & 11 deletions .nycrc

This file was deleted.

11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
### v6.0.0

- Converted to TS
- BREAKING removed `delegateToComponent`
- BREAKING excludes removed as an option in import configuration. Transforms used instead as part of a `SubschemaConfig`.
- BREAKING upgraded to graphql 16.9+ peer

===

### v5.0.1

- Update @graphql-tools/utils dependency and fix samples for Apollo server v3.
Expand Down Expand Up @@ -179,4 +188,4 @@

- Fixed .npmignore to not include misc files that added to the package size

### v1.0.0 — promoted from alpha.23
### v1.0.0 — promoted from alpha.23
57 changes: 36 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Read more about the idea [here](https://medium.com/expedia-group-tech/graphql-co

Generally speaking, each instance of `GraphQLComponent` has reference to an instance of [`GraphQLSchema`](https://graphql.org/graphql-js/type/#graphqlschema). This instance of `GraphQLSchema` is built in a several ways, depending on the options passed to a given `GraphQLComponent`'s constructor.

* when a `GraphQLComponent` instance has `imports` (ie. other `GraphQLComponent` instances or component configuration objects) [graphql-tools stitchSchemas()](https://www.graphql-tools.com/docs/schema-stitching/) is used to create a "gateway" or aggregate schema that is the combination of the underlying imported schemas, and the typeDefs/resolvers passed to the root or importing `GraphQLComponent`
* when a `GraphQLComponent` instance has `imports` (ie. other `GraphQLComponent` instances or component [SubschemaConfig](https://the-guild.dev/graphql/stitching/docs/getting-started/remote-subschemas#configuring-subschemas) configuration objects) is used to create a "gateway" or aggregate schema that is the combination of the underlying imported schemas, and the typeDefs/resolvers passed to the root or importing `GraphQLComponent`
* when a `GraphQLComponent` has no imports, graphql-tools' `makeExecuteableSchema({typeDefs, resolvers})` is used to generate an executable GraphQL schema using the passed/required inputs.

It's worth noting that `GraphQLComponent` can also be used to construct componentized Apollo Federated schemas. That is, if you pass the `federation: true` flag to a GraphQLComponent constructor, `@apollo/federation`'s [buildSubgraphSchema()](https://www.apollographql.com/docs/federation/api/apollo-subgraph/) is used in lieu of graphql-tools `makeExecutableSchema({...})` and the above still schema construction rule applies. The general use case here might be to help modularize an individual federated subschema service implementation.
Expand All @@ -25,7 +25,7 @@ federation (2 subschema services implemented via `GraphQLComponent` and a vanill

### Repository structure

- `lib` - the graphql-component code.
- `src` - the graphql-component code.
- `examples/composition` - a simple example of composition using `graphql-component`
- `examples/federation` - a simple example of building a federated schema using `graphql-component`

Expand All @@ -41,18 +41,18 @@ federation (2 subschema services implemented via `GraphQLComponent` and a vanill
`GraphQLComponent` uses [debug]() for local stdout based debug logging. Enable all debug logging with the node environment variable `DEBUG=graphql-component:*`. Generally speaking, most debug output occurs during `GraphQLComponent` construction.

# API
- `GraphQLComponent(options)` - the component class, which may also be extended. Its options include:
- `GraphQLComponent(options: IGraphQLComponentOptions)` - the component class, which may also be extended. Its options include:
- `types` - a string or array of strings of GraphQL SDL defining the type definitions for this component
- `resolvers` - a resolver map (ie. a two level map whose first level keys are types from the SDL, mapped to objects, whose keys are fields on those types and values are resolver functions)
- `imports` - an optional array of imported components for the schema to be merged with.
- `context` - an optional object { namespace, factory } for contributing to context.
- `directives` - an optional object containing custom schema directives.
- `mocks` - a boolean (to enable default mocks) or an object to pass in custom mocks
- `dataSources` - an array of data sources instances to make available on `context.dataSources` .
- `dataSourceOverrides` - overrides for data sources in the component tree.
- `federation` - make this component's schema an Apollo Federated schema (default: `false`).
- `pruneSchema` - (optional) prune the schema according to [pruneSchema in graphql-tools](https://www.graphql-tools.com/docs/api/modules/utils_src#pruneschema) (default: false)
- `pruneSchemaOptions` - (optional) schema options as per [PruneSchemaOptions in graphql-tools](https://www.graphql-tools.com/docs/api/interfaces/utils_src.PruneSchemaOptions)
- `transforms` - An array of schema transforms to apply to the component's schema.

- `static GraphQLComponent.delegateToComponent(component, options)` - a wrapper function that utilizes `graphql-tools` `delegateToSchema()` to delegate the calling resolver's selection set to a root type field (`Query`, `Mutuation`) of another `GraphQLComponent`'s schema
- `component` (instance of `GraphQLComponent`) - the component's whose schema will be the target of the delegated operation
Expand All @@ -68,14 +68,29 @@ federation (2 subschema services implemented via `GraphQLComponent` and a vanill

A GraphQLComponent instance (ie, `new GraphQLComponent({...})`) has the following API:

```typescript
interface IGraphQLComponent {
readonly name: string;
readonly schema: GraphQLSchema;
readonly context: IContextWrapper;
readonly types: TypeSource;
readonly resolvers: IResolvers<any, any>;
readonly imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[];
readonly dataSources?: IDataSource[];
readonly dataSourcesOverrides?: IDataSource[];
federation?: boolean;
}
```

- `name` - the component name
- `schema` - getter that this component's `GraphQLSchema` object (ie. the "executable" schema that is constructed as described above)
- `context` - context function that builds context for all components in the tree.
- `types` - this component's types.
- `resolvers` - this component's resolvers.
- `imports` - this component's imported components in the form of import configuration objects
- `mocks` - custom mocks for this component.
- `directives` - this component's directives.
- `dataSources` - this component's data source(s), if any.
- `dataSourceOverrides` - this component's data source overrides, if any.
- `federation` - if this schema should be a federated schema.

# General usage

Expand Down Expand Up @@ -129,7 +144,7 @@ const server = new ApolloServer({
Imports can be a configuration object supplying the following properties:

- `component` - the component instance to import.
- `exclude` - fields on types to exclude from the component being imported, if any.
- `configuration` - a `SubschemaConfig` : see [SubschemaConfig](https://the-guild.dev/graphql/stitching/docs/getting-started/remote-subschemas#configuring-subschemas)

### Exclude

Expand Down Expand Up @@ -195,28 +210,28 @@ new GraphQLComponent({

### Override data sources

Since data sources are added to the context based on the constructor name, it is possible to simply override data sources by passing the same class name or overriding the constructor name:
Since data sources are added to the context based on the constructor name, it is possible to simply override data sources by passing the same class name or overriding the constructor name.

`datSourceOverrides` is provided as a way to facilitate mixing in specific overrides while preserving defaults.

Example:

```javascript
const { schema, context } = new GraphQLComponent({
imports: [
{
component: new Property(),
exclude: ['Mutation.*']
},
{
component: new Reviews(),
exclude: ['Mutation.*']
}
],

class PropertyComponent extends new GraphQLComponent {
constructor(options) {
super({ dataSources: [new PropertyDataSource()], ...options });
}
}

const { schema, context } = new PropertyComponent({
dataSourceOverrides: [
new class PropertyMock {
new class MockDataSource {
static get name() {
return 'PropertyDataSource';
}
//...etc
}
]
});
```

Expand Down
16 changes: 16 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Remaining to-dos for version 4:

- [x] More test coverage
- [x] Alternative for schema directive visitor (add custom directives after creating federated schema)
- [x] Document transforms, including directives
- [x] Fix context injection
- [x] IGraphQLComponentConfigObject documentation
- [x] Fix composition examples
- [x] Fix federations examples
- [ ] Revert composition examples to JS again
- [x] Update readme
- [x] Repository structure
- [x] API
- [x] Component options
- [x] Imports / excludes docs reference to SubschemaConfig
- [ ] Move to latest stitch functionality in @graphql-tools/stitch (big change)
80 changes: 80 additions & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { GraphQLResolveInfo, GraphQLSchema } from 'graphql';
import { IResolvers, PruneSchemaOptions, TypeSource, SchemaMapper } from '@graphql-tools/utils';
import { IMocks } from '@graphql-tools/mock';
import { SubschemaConfig } from '@graphql-tools/delegate';
export type ResolverFunction = (_: any, args: any, ctx: any, info: GraphQLResolveInfo) => any;
export interface IGraphQLComponentConfigObject {
component: IGraphQLComponent;
configuration?: SubschemaConfig;
}
export interface ComponentContext extends Record<string, unknown> {
dataSources: DataSourceMap;
}
export type ContextFunction = ((context: Record<string, unknown>) => any);
export interface IDataSource {
name: string;
}
export type DataSource<T> = {
[P in keyof T]: T[P] extends (context: ComponentContext, ...p: infer P) => infer R ? (...p: P) => R : never;
};
export type DataSourceMap = {
[key: string]: IDataSource;
};
export type DataSourceInjectionFunction = ((context: Record<string, unknown>) => DataSourceMap);
export interface IContextConfig {
namespace: string;
factory: ContextFunction;
}
export interface IContextWrapper extends ContextFunction {
use: (name: string | ContextFunction | null, fn?: ContextFunction | string) => void;
}
export interface IGraphQLComponentOptions<TContextType extends ComponentContext = ComponentContext> {
types?: TypeSource;
resolvers?: IResolvers<any, TContextType>;
mocks?: boolean | IMocks;
imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[];
context?: IContextConfig;
dataSources?: IDataSource[];
dataSourceOverrides?: IDataSource[];
pruneSchema?: boolean;
pruneSchemaOptions?: PruneSchemaOptions;
federation?: boolean;
transforms?: SchemaMapper[];
}
export interface IGraphQLComponent<TContextType extends ComponentContext = ComponentContext> {
readonly name: string;
readonly schema: GraphQLSchema;
readonly context: IContextWrapper;
readonly types: TypeSource;
readonly resolvers: IResolvers<any, TContextType>;
readonly imports?: (IGraphQLComponent | IGraphQLComponentConfigObject)[];
readonly dataSources?: IDataSource[];
readonly dataSourceOverrides?: IDataSource[];
federation?: boolean;
}
export default class GraphQLComponent<TContextType extends ComponentContext = ComponentContext> implements IGraphQLComponent {
_schema: GraphQLSchema;
_types: TypeSource;
_resolvers: IResolvers<any, TContextType>;
_mocks: boolean | IMocks;
_imports: IGraphQLComponentConfigObject[];
_context: ContextFunction;
_dataSources: IDataSource[];
_dataSourceOverrides: IDataSource[];
_pruneSchema: boolean;
_pruneSchemaOptions: PruneSchemaOptions;
_federation: boolean;
_dataSourceContextInject: DataSourceInjectionFunction;
_transforms: SchemaMapper[];
constructor({ types, resolvers, mocks, imports, context, dataSources, dataSourceOverrides, pruneSchema, pruneSchemaOptions, federation, transforms }: IGraphQLComponentOptions);
get context(): IContextWrapper;
get name(): string;
get schema(): GraphQLSchema;
get types(): TypeSource;
get resolvers(): IResolvers<any, TContextType>;
get imports(): IGraphQLComponentConfigObject[];
get dataSources(): IDataSource[];
get dataSourceOverrides(): IDataSource[];
set federation(flag: boolean);
get federation(): boolean;
}
Loading