• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

miragejs/graphql: A library for handling GraphQL requests with Mirage JS

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

miragejs/graphql

开源软件地址(OpenSource Url):

https://github.com/miragejs/graphql

开源编程语言(OpenSource Language):

JavaScript 100.0%

开源软件介绍(OpenSource Introduction):

Mirage JS GraphQL

npm package build

Use Mirage JS with GraphQL.

Overview

Mirage lets you simulate API responses by writing route handlers. A route handler is a function that returns data to fulfill a request. Mirage GraphQL provides the ability to create a GraphQL route handler based on your GraphQL and Mirage schemas.

import { createServer } from "miragejs"
import { createGraphQLHandler } from "@miragejs/graphql"
import graphQLSchema from "app/gql/schema.gql"

export function makeServer() {
  return createServer({
    routes() {
      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema)

      this.post("/graphql", graphQLHandler)
    }
  })
}

Highlights

Mirage GraphQL tries to do a lot for you. Here are the highlights:

  • It fulfills GraphQL requests by fetching data from Mirage's database.
  • It filters records from Mirage's database by using arguments from your GraphQL queries.
  • It handles create, update and delete type mutations automatically based on some conventions.
  • It allows you to supply your own resolvers (for cases where the automatic query and mutation resolution isn't sufficient).

Installation

You should install both miragejs and @miragejs/graphql.

# Using npm
npm install --save-dev miragejs @miragejs/graphql

# Using Yarn
yarn add --dev miragejs @miragejs/graphql

Guide

This guide assumes most of its readers are already using GraphQL in their apps and want to start using Mirage to mock out their backend. This guide will try to provide enough information to be useful but it's worth reading the Mirage guides to get a full understanding of everything Mirage can do.

Table of Contents

Mirage GraphQL Assumptions

There are a couple of assumptions Mirage GraphQL makes concerning how it resolves GraphQL queries. It's important to understand these assumptions to avoid confusion based on its behavior.

You Don't Need to Define Mirage Models

In many cases, you need to tell Mirage about the models that exist in your app but Mirage GraphQL assumes relationships between types from your GraphQL schema and creates models accordingly. You can still define Mirage models, if you'd like, and Mirage GraphQL won't try to create them on its own.

Arguments from GraphQL Queries Map to Field Names of the Return Type

Mirage GraphQL uses arguments to filter records from Mirage's database. This isn't very useful for testing, as you only need to seed Mirage's database with the exact records you need for a given test. It's more useful when using Mirage for development where filtering and pagination may be desired for a more realistic user experience.

Miscellaneous Assumptions

  • Fields that should resolve to a single object of a union type are resolved by taking the first appropriate record from Mirage's database. This is how Mirage GraphQL automatically resolves in this scenario. As with all automatic resolution, if you need to include some additional logic, you'll need to supply your own resolver.

Example Use Cases

Notes:

  • For further reference, there are many more use cases covered by the integration tests.
  • The graphql-request library is used in the examples but is not a dependency installed by Mirage GraphQL.

Example Schema

For these examples, imagine we have a GraphQL schema that looks like this:

# app/gql/schema.gql

input PersonInput {
  firstName: String
  lastName: String
}

type Mutation {
  createPerson(input: PersonInput!): Person
  updatePerson(id: ID!, input: PersonInput!): Person

  # Note: `deletePerson` can't automatically be resolved due to the Boolean
  # return type. We will need to implement a resolver for this.
  deletePerson(id: ID!): Boolean
}

type Person {
  id: ID!
  firstName: String!
  lastName: String!
}

type Query {
  allPeople: [Person]
  person(id: ID!): Person

  # Note: `people` can't automatically be resolved if the `sortBy` argument is
  # supplied to the query. We will need to implement a resolver for this.
  people(firstName: String, lastName: String, sortBy: String): [Person]
}

and we create a Mirage server like this:

// app/mirage/server.js

import { createServer } from "miragejs"
import { createGraphQLHandler } from "@miragejs/graphql"
import graphQLSchema from "app/gql/schema.gql"

export function makeServer() {
  return createServer({
    routes() {
      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema);

      this.post("/graphql", graphQLHandler)
    }
  })
}

Example: Find Person by ID

In this example, we can get a Person record by ID.

// app/components/person.js

import { createServer } from "app/mirage/server";
import { request } from "graphql-request"

const server = createServer();

server.create("person", { firstName: "Mikael", lastName: "Åkerfeldt" })

export default {
  // ...other component stuff

  personQuery: `
    query Person($id: id) {
      person(id: $id) {
        id
        firstName
        lastName
      }
    }
  `,
  getPerson(id) {
    return request("/graphql", this.personQuery, { id })
  }
}

A call to getPerson("1") will cause Mirage GraphQL to respond with:

{
  "data": {
    "person": {
      "id": "1",
      "firstName": "Mikael",
      "lastName": "Åkerfeldt"
    }
  }
}

Example: Get All People

In this example, we can get all the Person records from Mirage's database.

// app/components/people.js

import { createServer } from "app/mirage/server";
import { request } from "graphql-request"

const server = createServer();

server.create("person", { firstName: "Mikael", lastName: "Åkerfeldt" })
server.create("person", { firstName: "Per", lastName: "Nilsson" })
server.create("person", { firstName: "Tomas", lastName: "Haake" })

export default {
  // ...other component stuff

  peopleQuery: `
    query People {
      people {
        id
        firstName
        lastName
      }
    }
  `,
  getPeople() {
    return request("/graphql", this.peopleQuery)
  }
}

A call to getPeople() will cause Mirage GraphQL to respond with:

{
  "data": {
    "people": [
      {
        "id": "1",
        "firstName": "Mikael",
        "lastName": "Åkerfeldt"
      },
      {
        "id": "2",
        "firstName": "Per",
        "lastName": "Nilsson"
      },
      {
        "id": "3",
        "firstName": "Tomas",
        "lastName": "Haake"
      }
    ]
  }
}

Example: Creating and Updating a Person

In this example, we can create or update a Person record in Mirage's database.

// app/components/people.js

import { createServer } from "app/mirage/server";
import { request } from "graphql-request"

const server = createServer();

export default {
  // ...other component stuff

  createPersonMutation: `
    mutation CreatePerson($input: PersonInput!) {
      createPerson(input: $input) {
        id
        firstName
        lastName
      }
    }
  `,
  updatePersonMutation: `
    mutation UpdatePerson($id: ID!, $input: PersonInput!) {
      updatePerson(id: $id, input: $input) {
        id
        firstName
        lastName
      }
    }
  `,
  createPerson(input) {
    return request("/graphql", this.createPersonMutation, { input })
  },
  updatePerson(id, input) {
    return request("/graphql", this.updatePersonMutation, { id, input })
  }
}

A call to createPerson({ firstName: "Ola", lastName: "Englund" }) will cause Mirage GraphQL to respond with:

{
  "data": {
    "createPerson": {
      "id": "1",
      "firstName": "Ola",
      "lastName": "Englund"
    }
  }
}

If you then wanted to update that person, you could call updatePerson("1", { lastName: "Strandberg" }) which would result in:

{
  "data": {
    "updatePerson": {
      "id": "1",
      "firstName": "Ola",
      "lastName": "Strandberg"
    }
  }
}

Automatic Mutation Conventions

Mirage GraphQL will automatically resolve these mutations per these conventions:

  • A mutation that returns an object type and has one argument, an input type, will create a record with the given input type attributes.
  • A mutation that returns an object type and has two arguments, an ID type and an input type, will update a record having that ID with the given input type attributes.
  • A mutation that returns an object type and has one argument, an ID type, will delete a record having that ID.

Any other combination of arguments for a mutation requires a resolver. This can be seen in a later example.

Example: Filtering People

In this example, we can get filter Person records from Mirage's database. There will be two parts. In part 1, we'll filter by lastName which is an argument for the query and an attribute of Person records. In part 2, we'll add a sortBy argument which will require us to implement a resolver.

Part 1: Filtering by Last Name

In the following case, Mirage GraphQL can automatically filter the records from Mirage's database because the lastName argument for the query matches an attribute of the records.

// app/components/people.js

import { createServer } from "app/mirage/server";
import { request } from "graphql-request"

const server = createServer();

server.create("person", { firstName: "Mikael", lastName: "Åkerfeldt" })
server.create("person", { firstName: "Per", lastName: "Nilsson" })
server.create("person", { firstName: "Tomas", lastName: "Haake" })

export default {
  // ...other component stuff

  peopleQuery: `
    query People($firstName: String, $lastName: String, $sortBy: String) {
      people(firstName: $firstName, lastName: $lastName, sortBy: $sortBy) {
        id
        firstName
        lastName
      }
    }
  `,
  getPeopleByLastName(lastName) {
    return request("/graphql", this.peopleQuery, { lastName })
  }
}

A call to getPeopleByLastName("Haake") will cause Mirage GraphQL to respond with:

{
  "data": {
    "people": [
      {
        "id": "3",
        "firstName": "Tomas",
        "lastName": "Haake"
      }
    ]
  }
}

Part 2: Sorting

In the following case, Mirage GraphQL can't automatically resolve the query because the sortBy argument for the query doesn't match any attribute of the records. To do this, we need to add pass a resolver in when creating our GraphQL handler.

In the Mirage server setup:

// app/mirage/server.js

import { createServer } from "miragejs"
import graphQLSchema from "app/gql/schema.gql"
import {
  createGraphQLHandler,
  mirageGraphQLFieldResolver
} from "@miragejs/graphql"

export function makeServer() {
  return createServer({
    routes() {
      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema, {
        resolvers: {
          Query: {
            people(obj, args, context, info) {
              const { sortBy } = args
              
              delete args.sortBy
              
              const records =
                mirageGraphQLFieldResolver(obj, args, context, info)

              return records.sort((a, b) => a[sortBy].localeCompare(b[sortBy]))
            }
          }
        }
      })

      this.post("/graphql", graphQLHandler)
    }
  })
}

Note: We can pass as many resolvers into createGraphQLHandler as we want. Additionally, we can compose resolvers by leaning on the default field resolver from Mirage GraphQL, as shown above. In this case, the default field resolver does most of the work to get the records and our custom resolver only has to sort them.

Having added a resolver to handle the sortBy argument, the following component example will now work:

// app/components/people.js

import { createServer } from "app/mirage/server";
import { request } from "graphql-request"

const server = createServer();

server.create("person", { firstName: "Mikael", lastName: "Åkerfeldt" })
server.create("person", { firstName: "Per", lastName: "Nilsson" })
server.create("person", { firstName: "Tomas", lastName: "Haake" })

export default {
  // ...other component stuff

  peopleQuery: `
    query People($firstName: String, $lastName: String, $sortBy: String) {
      people(firstName: $firstName, lastName: $lastName, sortBy: $sortBy) {
        id
        firstName
        lastName
      }
    }
  `,
  getSortedPeopleBy(sortBy) {
    return request("/graphql", this.peopleQuery, { sortBy })
  }
}

A call to getSortedPeopleBy("lastName") will cause Mirage GraphQL to respond with:

{
  "data": {
    "people": [
      {
        "id": "1",
        "firstName": "Mikael",
        "lastName": "Åkerfeldt"
      },
      {
        "id": "3",
        "firstName": "Tomas",
        "lastName": "Haake"
      },
      {
        "id": "2",
        "firstName": "Per",
        "lastName": "Nilsson"
      }
    ]
  }
}

Example: Deleting a Person

If you read the section on automatically resolving mutations, you'll know that Mirage GraphQL can automatically handle conventional mutations that delete records. However, in our example schema, the deletePerson mutation is unconventional. It returns Boolean instead of a Person.

In this case, we need to implement a resolver but just like in the example of sorting people, we can leverage Mirage GraphQL's default behavior.

In the Mirage server setup:


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
eclipse/microprofile-graphql: microprofile-graphql发布时间:2022-06-13
下一篇:
graphql/codemirror-graphql: GraphQL mode and helpers for CodeMirror.发布时间:2022-06-13
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap