利用GraphQL的Schema快速创建一个模拟服务器

总结

由于以下原因,我正在使用GraphQL开发客户端,并且希望有一个模拟服务器。

    • バックエンドの開発を待たずにGraphQLのSchemaベースで非同期でフロントエンドの開発を行いたい

 

    テスト用にAPIのモック

我想快速地建立一个漂亮的模拟服务器,所以我进行了一番调查。

想要制作的东西

我想制作一个能够自动生成类型安全的MSW处理程序和数据创建函数的方法,以实现对GraphQL Schema的正向操作。这样一来,即使Schema发生变化,Mock服务器也能够快速跟进,而且Mock服务器的维护也会更加容易。

大致介绍步骤

我將簡單地寫出下面所做的事情。

首先,假设有以下的GraphQL Schema和Query。

架构

type Query {
  getUser(id: ID!): User
}

type User {
  id: ID!
  name: String!
  email: String!
}

查询

query GetUser($id: String!) {
  getUser(id: $id) {
    id
    name
    email
  }
}

1. 安装必要的软件包。

首先,需要安装必要的软件包。

npm install @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-msw graphql-codegen-typescript-mock-data msw

每个用途如下所示。

GraphQL Code Generator: GraphQLのschema等からいろいろ自動生成してくれるライブラリ

Mock Service Worker(msw): ネットワーク層でリクエストをインターセプトし、モックのレスポンスを返すことができるライブラリ

@graphql-codegen/typescript-msw: クライアントで定義したquery/mutationから型セーフなmswのhandlerを自動生成する

graphql-codegen-typescript-mock-data: Schemaからデータ自動生成するライブラリ

2. GraphQL Code Generator的配置

接下来,按照以下方式编写codegen.yml文件。

const config: CodegenConfig = {
  overwrite: true
  schema: "path/to/your/schema.graphql" // 適当な値を入れる
  documents: '**/*.graphql', // 適当な値を入れる
  generates:
   /**
   * その他のgeneratorsは省略
   */
   '__generated__/mockHandlers.ts': {
     plugins: [
       'typescript',
       'typescript-operations',
       '@graphql-codegen/typescript-msw',
        {
         'graphql-codegen-typescript-mock-data': {
           prefix: 'mock',
        },
      },
    ],
  },
}

通过此配置,执行代码生成命令将会生成以下文件,其中包含了TS类型、MSW处理程序和模拟数据生成函数的相应内容。

自动生成的文件内容
import { graphql,ResponseResolver,GraphQLRequest,GraphQLContext } from’msw’
export type Maybe = T | null;
export type InputMaybe = Maybe ;
export type Exact = { [K in keyof T]:T[K]};
export type MakeOptional <T,K extends keyof T> = Omit <T,K> & { [SubKey in K]?Maybe <T[SubKey]>};
export type MakeMaybe <T,K extends keyof T> = Omit <T,K> & { [SubKey in K]:Maybe <T[SubKey]>};
export type MakeEmpty = { [_ in K]?never};
export type Incremental = T | { [P in keyof T]?P extends’ $fragmentName’ |’__ typename’?T[P]:never};
/ **所有内置和自定义标量,映射到其实际值* /
export type Scalars = {
ID:{ input:string; output:string;}
String:{ input:string; output:string;}
Boolean:{ input:boolean; output:boolean;}
Int:{ input:number; output:number;}
Float:{ input:number; output:number;}
};export type Query = {
__ typename?:’Query’;
getUser?:Maybe ;
};

export type QueryGetUserArgs = {
id:Scalars [‘ID’] [‘input’];
};

export type User = {
__ typename?:’User’;
电子邮件:Scalars [‘String’] [‘output’];
id:Scalars [‘ID’] [‘output’];
名称:Scalars [‘String’] [‘output’];
};

export type GetUserQueryVariables = Exact <{   id:Scalars [‘ID’] [‘input’]; }>;

export type GetUserQuery = { __ typename?:’Query’,getUser?:{ __ typename?:’User’,id:string,name:string,email:string} | null };

/ **
* @param resolver接受捕获请求并可能返回模拟响应的函数。
* @see https://mswjs.io/docs/basics/response-resolver
* @example
* mockGetUserQuery((req,res,ctx)=> {
* const {id} = req.variables;
* return res(
* ctx.data({getUser})
*)
*})
* /
export const mockGetUserQuery =(resolver:ResponseResolver ,GraphQLContext ,any>)=>
graphql.query <GetUserQuery,GetUserQueryVariables>(
‘GetUser’,
解析器

export const mockQuery =(覆盖?:Partial ):Query =》{
return {
getUser:覆盖&&覆盖.hasOwnProperty(’getUser’)?覆盖.getUser!:mockUser(),
};
};

export const mockUser =(覆盖?:Partial ):User =》{
return {
电子邮件:覆盖&&覆盖.hasOwnProperty(’email’)?覆盖.email!:’sunt’,
id:覆盖&&覆盖.hasOwnProperty(’id’)?覆盖.id!:’a5756f00-41a6-422a-8a7d-d13ee6a63750’,
名称:覆盖&&覆盖.hasOwnProperty(’name’)?覆盖.name!:’porro’,
};
};

3. 使用自动生成的代码。

接下来只需要将以下代码组合起来即可。

mockGetUserQuery: 自動生成されてたmswのハンドラー

mockUser: 自動生成されたダミーデータ作成関数

※ 虚拟数据创建函数可以自然地进行重写,并且还可以设置更加现实的值。

import { mockGetUserQuery, mockUser } from '__generated__/mockHandlers'

const handlers = [
  mockGetUserQuery((req, res, ctx) => {
    const { id } = req.variables;
    return res(
      // Schemaに応じて適当なデータが作成される
      ctx.data({ mockUser() })
    )
  })
]

const worker = setupWorker(...handlers)
广告
将在 10 秒后关闭
bannerAds