尝试使用Nestjs搭建GraphQL服务
参考文档官网文档尝试遇到问题:
1、返回null的问题可以通过nullable: true解决
2、返回的数据跟schema 中定义的预期 types类型不一致,主要是由于之前在result.interceptor.ts中自定义返回数据格式导致,做下区分就可以了。
app.module.ts
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { SuppliesModule } from '../supplies/supplies.module';
const GQLModule = GraphQLModule.forRootAsync({
useFactory: () => ({
debug: true,
playground: true,
installSubscriptionHandlers: true,
autoSchemaFile: 'schema.gql',
tracing: true,
include: [SuppliesModule],
}),
});
@Module({
imports: [
GQLModule,
],
})
export class AppModule {}
supplies.resolver.ts
import { NotFoundException } from '@nestjs/common';
import { Args, Mutation, Query, Resolver, Subscription } from '@nestjs/graphql';
import { PubSub } from 'apollo-server-express';
import { NewSupplieInput } from '../dto/supplie.input';
import { SupplieArgs } from '../dto/supplie.args';
import { Supplie } from '../models/supplie.model';
import { SuppliesService } from '../service/supplies.service';
const pubSub = new PubSub();
@Resolver((of) => Supplie)
export class SuppliesResolver {
constructor(private readonly suppliesService: SuppliesService) {}
// @UseGuards(GqlAuthGuard)
@Query((returns) => String)
hello(): string {
return 'Hello World!';
}
// 查询单个
@Query((returns) => Supplie, { name: 'supplie', nullable: true })
async supplie(@Args('id') id: string): Promise {
const supplie = await this.suppliesService.findOneById(id);
if (!supplie) {
throw new NotFoundException(id);
}
return supplie;
}
// 查询所有
@Query((returns) => [Supplie])
async suppliesAll(@Args() supplieArgs: SupplieArgs): Promise {
return this.suppliesService.findAll(supplieArgs);
}
// 添加
@Mutation((returns) => Supplie)
async addSupplie(@Args('newSupplieData') newSupplieData: NewSupplieInput): Promise {
const supplie = await this.suppliesService.create(newSupplieData);
pubSub.publish('suplieAdded', { suplieAdded: supplie });
return supplie;
}
// 删除
@Mutation((returns) => Boolean)
async removeSupplie(@Args('id') id: string) {
return this.suppliesService.remove(id);
}
@Subscription((returns) => Supplie)
suplieAdded() {
return pubSub.asyncIterator('suplieAdded');
}
}
supplies.service.ts
import { Injectable } from '@nestjs/common';
import { NewSupplieInput } from '../dto/supplie.input';
import { SupplieArgs } from '../dto/supplie.args';
import { Supplie } from '../models/supplie.model';
@Injectable()
export class SuppliesService {
private readonly supplies: Supplie[] = [{ id: 1, firstName: 'Cat', lastName: '5' }];
async create(data: NewSupplieInput): Promise {
return {} as any;
}
async findOneById(id: string): Promise {
// return this.supplies.find((supplie) => supplie.id === id);
return this.supplies[0];
}
async findAll(supplieArgs: SupplieArgs): Promise {
const result = [
{ id: 100, firstName: 'ddd', lastName: 'ddf' },
{ id: 11, firstName: 'ddd', lastName: 'ddf' },
];
return result;
}
async remove(id: string): Promise<boolean> {
return true;
}
}
supplies.module.ts
import { Module } from '@nestjs/common';
import { SuppliesResolver } from './resolver/supplies.resolver';
import { SuppliesService } from './service/supplies.service';
@Module({
providers: [SuppliesResolver, SuppliesService],
})
export class SuppliesModule {}
supplie.model.ts
import { Field, Int, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class Supplie {
@Field((type) => Int)
id?: number;
@Field({ nullable: true })
firstName: string;
@Field({ nullable: true })
lastName: string;
}
supplie.args.ts
import { ArgsType, Field, Int } from '@nestjs/graphql';
import { Max, Min } from 'class-validator';
@ArgsType()
export class SupplieArgs {
@Field((type) => Int)
@Min(0)
skip: number = 0;
@Field((type) => Int)
@Min(1)
@Max(50)
take: number = 25;
}
supplie.input.ts
import { Field, InputType } from '@nestjs/graphql';
import { IsOptional, Length, MaxLength } from 'class-validator';
@InputType()
export class NewSupplieInput {
@Field()
@MaxLength(30)
name: string;
@Field({ nullable: true })
@IsOptional()
@Length(30, 255)
firstName?: string;
@Field((type) => String)
lastName: string;
}
result.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { GqlContextType } from '@nestjs/graphql';
export interface Response {
data: T;
}
@Injectable()
export class ResultInterceptor implements NestInterceptor> {
intercept(context: ExecutionContext, next: CallHandler): Observable> {
// HTTP (REST) Context
if (context.getType() === 'http') {
return next.handle().pipe(
map((rawData) => ({
code: (rawData && rawData.code) || 100000,
msg: (rawData && rawData.msg) || 'success',
currTime: new Date(),
data: rawData ? (!rawData.code && !rawData.msg ? rawData : rawData.data || undefined) : undefined,
}))
);
}
// GraphQL Context
else if (context.getType() === 'graphql') {
eturn next.handle();
}
return next.handle();
}
}
二、在 Vue 组件中的用法
{{ hello }}
query {
supplie(id: "1") {
firstName,
lastName,
id
}
hello
}
query SuppliesAll($pageIndex: Int!) {
suppliesAll(skip: $pageIndex) {
id,
lastName
}
}
Query Variables
{
"pageIndex": 1
}
参考:
vue Apollo https://vue-apollo.netlify.com/zh-cn/guide/apollo
NestJS GraphQL https://docs.nestjs.com/graphql/resolvers
GraphQL快速入门 https://segmentfault.com/a/1190000017851838
VUE与GQL