Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/Davide-Gheri/nestjs-mercurius
NestJs module to use Mercurius as GraphQL server
https://github.com/Davide-Gheri/nestjs-mercurius
fastify graphql mercurius nestjs
Last synced: about 1 month ago
JSON representation
NestJs module to use Mercurius as GraphQL server
- Host: GitHub
- URL: https://github.com/Davide-Gheri/nestjs-mercurius
- Owner: Davide-Gheri
- License: mit
- Created: 2021-02-12T21:16:38.000Z (almost 4 years ago)
- Default Branch: master
- Last Pushed: 2023-03-05T20:58:48.000Z (almost 2 years ago)
- Last Synced: 2024-11-15T04:10:09.457Z (about 1 month ago)
- Topics: fastify, graphql, mercurius, nestjs
- Language: TypeScript
- Homepage:
- Size: 3.1 MB
- Stars: 40
- Watchers: 1
- Forks: 7
- Open Issues: 31
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
README
If you want to use Mercurius with @nestjs/graphql > v10, please use the @nestjs/mercurius package
# Nestjs Mercurius
Use [Mercurius GraphQL](https://github.com/mercurius-js/mercurius) with Nestjs framework
Visit the [Wiki](https://github.com/Davide-Gheri/nestjs-mercurius/wiki)
## Install
```bash
npm i @nestjs/platform-fastify fastify mercurius nestjs-mercurius
```## Use
### Register the module
```typescript
import { Module } from '@nestjs/common';
import { MercuriusModule } from 'nestjs-mercurius';@Module({
imports: [
// Work also with async configuration (MercuriusModule.forRootAsync)
MercuriusModule.forRoot({
autoSchemaFile: true,
context: (request, reply) => ({
user: request.user,
}),
subscription: {
context: (connection, request) => ({
user: request.user,
}),
},
}),
],
providers: [
CatResolver,
],
})
export class AppModule {}
```### The Object type
```typescript
import { Field, ID, ObjectType } from '@nestjs/graphql';@ObjectType()
export class Cat {
@Field(() => ID)
id: number;
@Field()
name: string;
@Field(() => Int)
ownerId: number;
}
```### The Resolver
```typescript
import { Resolver, Query, ResolveField, Parent, Mutation, Subscription, Context, Args } from '@nestjs/graphql';
import { ParseIntPipe } from '@nestjs/common';
import { ResolveLoader, toAsyncIterator, LoaderQuery } from 'nestjs-mercurius';
import { PubSub } from 'mercurius';
import { Cat } from './cat';@Resolver(() => Cat)
export class CatResolver {
constructor(
private readonly catService: CatService,
private readonly userService: UserService,
) {}@Query(() => [Cat])
cats(@Args({name: 'filter', type: () => String, nullable: true}) filter?: string) {
return this.catService.find(filter);
}@Query(() => Cat, { nullable: true })
cat(@Args('id', ParseIntPipe) id: number) {
return this.catService.findOne(id);
}@Mutation(() => Cat)
createCat(
@Args('name') name: string,
@Context('pubsub') pubSub: PubSub,
@Context('user') user: User,
) {
const cat = new Cat();
cat.name = name;
cat.ownerId = user.id;
//...
pubSub.publish({
topic: 'CatCreated',
payload: { cat },
});
return cat;
}
@Subscription(() => Cat, {
resolve: (payload) => payload.cat,
filter: (payload, vars, context) =>
payload.cat.ownerId !== context.user.id,
})
onCatCreated(
@Context('pubsub') pubSub: PubSub,
) {
return toAsyncIterator(pubSub.subscribe('CatCreated'));
}
@ResolveField(() => Int)
age(@Parent() cat: Cat) {
return 5;
}
@ResolveLoader(() => User, { opts: { cache: false } })
owner(
@Parent() queries: LoaderQuery[],
) {
return this.userService.findById(
// queries is an array of objects defined as { obj, params } where obj is the current object and params are the GraphQL params
queries.map(({ obj }) => obj.ownerId)
);
}
}
```## Federation
Install necessary dependencies
```typescript
npm i @apollo/federation
```### The Gateway
```typescript
import { Module } from '@nestjs/common';
import { MercuriusGatewayModule } from 'nestjs-mercurius';@Module({
imports: [
MercuriusGatewayModule.forRoot({
graphiql: 'playground',
subscription: true,
gateway: {
pollingInterval: 10000,
services: [
{
name: 'users',
url: 'https://....',
wsUrl: 'wss://...',
},
{
name: 'pets',
url: 'https://...',
rewriteHeaders: headers => headers,
},
],
},
}),
],
})
export class GatewayModule {}
```### The Service
```typescript
import { Module } from '@nestjs/common';
import { MercuriusModule } from './mercurius.module';
import { User } from './user';
import { PetResolver, UserResolver } from './resolvers';@Module({
imports: [
MercuriusModule.forRoot({
autoSchemaFile: true,
federationMetadata: true,
buildSchemaOptions: {
orphanedTypes: [User],
},
//...
}),
],
providers: [
PetResolver,
UserResolver,
],
})
export class PetModule {}
```### The Resolver
```typescript
import { Resolver, ResolveReference } from '@nestjs/graphql';
import { Pet } from './pet';
import { Reference } from './reference.interface';@Resolver(() => Pet)
export class PetResolver {
constructor(
private readonly petService: PetService,
) {}@ResolveReference()
resolveReference(ref: Reference<'Pet', 'id'>) {
return this.petService.findOne(ref.id);
}
}
```Resolve reference could also be defined as Loader, potentially improving performance:
```typescript
import { ResolveReferenceLoader } from './resolve-reference-loader.decorator';
import { LoaderQuery } from './loader.interface';@Resolver(() => Pet)
export class PetResolver {
constructor(
private readonly petService: PetService,
) {}@ResolveReferenceLoader()
resolveReference(refs: LoaderQuery>) {
return this.petService.findById(
refs.map(({ obj }) => obj.id)
);
}
}
```## Hooks
Register mercurius hooks as service methods, using the `@GraphQLHook()` decorator
```typescript
import { GraphQLHook } from 'nestjs-mercurius';@Injectable()
export class HookService {
@GraphQLHook('preValidation')
async onPreValidation(schema: GraphQLSchema, source: DocumentNode, context: any) {
//...
}
}
```