{"id":19240316,"url":"https://github.com/miragejs/graphql","last_synced_at":"2025-10-06T01:37:58.556Z","repository":{"id":40692449,"uuid":"269958105","full_name":"miragejs/graphql","owner":"miragejs","description":"A library for handling GraphQL requests with Mirage JS","archived":false,"fork":false,"pushed_at":"2025-09-02T20:14:28.000Z","size":440,"stargazers_count":74,"open_issues_count":23,"forks_count":13,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-11T20:44:21.234Z","etag":null,"topics":["graphql","miragejs","pretender","prototype","server","testing"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/miragejs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-06-06T11:18:42.000Z","updated_at":"2024-01-11T14:53:32.000Z","dependencies_parsed_at":"2023-11-29T09:27:16.423Z","dependency_job_id":"3e44a6ce-7d4d-4c93-a389-0a77cafb31da","html_url":"https://github.com/miragejs/graphql","commit_stats":{"total_commits":54,"total_committers":10,"mean_commits":5.4,"dds":0.4814814814814815,"last_synced_commit":"17ca8b366b7f3ad2ca9b613b424a4330da3fa6a8"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/miragejs/graphql","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miragejs%2Fgraphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miragejs%2Fgraphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miragejs%2Fgraphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miragejs%2Fgraphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/miragejs","download_url":"https://codeload.github.com/miragejs/graphql/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/miragejs%2Fgraphql/sbom","scorecard":{"id":649072,"data":{"date":"2025-08-11","repo":{"name":"github.com/miragejs/graphql","commit":"0c80be171685ced7b44ddb99a12b8ea7edfa6bbd"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":2,"reason":"Found 3/15 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/main.yml:1","Warn: no topLevel permission defined: .github/workflows/pr.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr.yml:11: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/pr.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/pr.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pr.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/miragejs/graphql/pr.yml/main?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 22 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"16 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-52f5-9888-hmc6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T12:57:32.387Z","repository_id":40692449,"created_at":"2025-08-21T12:57:32.387Z","updated_at":"2025-08-21T12:57:32.387Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278547772,"owners_count":26004772,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["graphql","miragejs","pretender","prototype","server","testing"],"created_at":"2024-11-09T17:06:55.263Z","updated_at":"2025-10-06T01:37:58.522Z","avatar_url":"https://github.com/miragejs.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Mirage JS GraphQL\n\n![npm package](https://img.shields.io/npm/v/@miragejs/graphql?color=success\u0026label=npm%20package)\n![build](https://img.shields.io/github/actions/workflow/status/miragejs/graphql/main.yml?branch=main)\n\nUse [Mirage JS](https://miragejs.com) with [GraphQL](https://graphql.org).\n\n## Overview\n\nMirage 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.\n\n```javascript\nimport { createServer } from \"miragejs\"\nimport { createGraphQLHandler } from \"@miragejs/graphql\"\nimport graphQLSchema from \"app/gql/schema.gql\"\n\nexport default function makeServer(config) {\n  return createServer({\n    routes() {\n      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema)\n\n      this.post(\"/graphql\", graphQLHandler)\n    }\n  })\n}\n\n```\n\n### Highlights\n\nMirage GraphQL tries to do a lot for you. Here are the highlights:\n\n* It fulfills GraphQL requests by fetching data from Mirage's database.\n* It filters records from Mirage's database by using arguments from your GraphQL queries.\n* It handles create, update and delete type mutations automatically based on [some conventions](#automatic-mutation-conventions).\n* It allows you to supply your own resolvers (for cases where the automatic query and mutation resolution isn't sufficient).\n\n## Installation\n\nYou should install both `miragejs` and `@miragejs/graphql`.\n\n```sh\n# Using npm\nnpm install --save-dev miragejs @miragejs/graphql\n\n# Using Yarn\nyarn add --dev miragejs @miragejs/graphql\n```\n\n## Guide\n\nThis 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](https://miragejs.com/docs/getting-started/introduction/) to get a full understanding of everything Mirage can do.\n\n### Table of Contents\n\n* [Mirage GraphQL Assumptions](#mirage-graphql-assumptions)\n  * [You Don't Need Mirage Models](#you-dont-need-mirage-models)\n  * [Arguments from GraphQL Queries Map to Field Names of the Return Type](#arguments-from-graphql-queries-map-to-field-names-of-the-return-type)\n  * [Miscellaneous Assumptions](#miscellaneous-assumptions)\n* [Example Use Cases](#example-use-cases)\n  * [Example Schema](#example-schema)\n  * [Example: Find Person by ID](#example-find-person-by-id)\n  * [Example: Get All People](#example-get-all-people)\n  * [Example: Creating and Updating a Person](#example-creating-and-updating-a-person)\n    * [Automatic Mutation Conventions](#automatic-mutation-conventions)\n  * [Example: Filtering People](#example-filtering-people)\n    * [Part 1: Filtering by Last Name](#part-1-filtering-by-last-name)\n    * [Part 2: Sorting](#part-2-sorting)\n  * [Example: Deleting a Person](#example-deleting-a-person)\n\n### Mirage GraphQL Assumptions\n\nThere 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.\n\n#### You Don't Need to Define Mirage Models\n\nIn many cases, you need to [tell Mirage about the models](https://miragejs.com/docs/main-concepts/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.\n\n#### Arguments from GraphQL Queries Map to Field Names of the Return Type\n\nMirage 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.\n\n#### Miscellaneous Assumptions\n\n* 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.\n\n### Example Use Cases\n\nNotes:\n\n* For further reference, there are many more use cases covered by the integration tests.\n* The `graphql-request` library is used in the examples but is not a dependency installed by Mirage GraphQL.\n\n#### Example Schema\n\nFor these examples, imagine we have a GraphQL schema that looks like this:\n\n```graphql\n# app/gql/schema.gql\n\ninput PersonInput {\n  firstName: String\n  lastName: String\n}\n\ntype Mutation {\n  createPerson(input: PersonInput!): Person\n  updatePerson(id: ID!, input: PersonInput!): Person\n\n  # Note: `deletePerson` can't automatically be resolved due to the Boolean\n  # return type. We will need to implement a resolver for this.\n  deletePerson(id: ID!): Boolean\n}\n\ntype Person {\n  id: ID!\n  firstName: String!\n  lastName: String!\n}\n\ntype Query {\n  allPeople: [Person]\n  person(id: ID!): Person\n\n  # Note: `people` can't automatically be resolved if the `sortBy` argument is\n  # supplied to the query. We will need to implement a resolver for this.\n  people(firstName: String, lastName: String, sortBy: String): [Person]\n}\n```\n\nand we create a Mirage server like this:\n\n```javascript\n// app/mirage/server.js\n\nimport { createServer } from \"miragejs\"\nimport { createGraphQLHandler } from \"@miragejs/graphql\"\nimport graphQLSchema from \"app/gql/schema.gql\"\n\nexport function makeServer() {\n  return createServer({\n    routes() {\n      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema)\n\n      this.post(\"/graphql\", graphQLHandler)\n    }\n  })\n}\n```\n\n#### Example: Find Person by ID\n\nIn this example, we can get a `Person` record by ID.\n\n```javascript\n// app/components/person.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nserver.create(\"person\", { firstName: \"Mikael\", lastName: \"Åkerfeldt\" })\n\nexport default {\n  // ...other component stuff\n\n  personQuery: `\n    query Person($id: id) {\n      person(id: $id) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  getPerson(id) {\n    return request(\"/graphql\", this.personQuery, { id })\n  }\n}\n```\n\nA call to `getPerson(\"1\")` will cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"person\": {\n      \"id\": \"1\",\n      \"firstName\": \"Mikael\",\n      \"lastName\": \"Åkerfeldt\"\n    }\n  }\n}\n```\n\n### Example: Get All People\n\nIn this example, we can get all the `Person` records from Mirage's database.\n\n```javascript\n// app/components/people.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nserver.create(\"person\", { firstName: \"Mikael\", lastName: \"Åkerfeldt\" })\nserver.create(\"person\", { firstName: \"Per\", lastName: \"Nilsson\" })\nserver.create(\"person\", { firstName: \"Tomas\", lastName: \"Haake\" })\n\nexport default {\n  // ...other component stuff\n\n  peopleQuery: `\n    query People {\n      people {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  getPeople() {\n    return request(\"/graphql\", this.peopleQuery)\n  }\n}\n```\n\nA call to `getPeople()` will cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"people\": [\n      {\n        \"id\": \"1\",\n        \"firstName\": \"Mikael\",\n        \"lastName\": \"Åkerfeldt\"\n      },\n      {\n        \"id\": \"2\",\n        \"firstName\": \"Per\",\n        \"lastName\": \"Nilsson\"\n      },\n      {\n        \"id\": \"3\",\n        \"firstName\": \"Tomas\",\n        \"lastName\": \"Haake\"\n      }\n    ]\n  }\n}\n```\n\n### Example: Creating and Updating a Person\n\nIn this example, we can create or update a `Person` record in Mirage's database.\n\n```javascript\n// app/components/people.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nexport default {\n  // ...other component stuff\n\n  createPersonMutation: `\n    mutation CreatePerson($input: PersonInput!) {\n      createPerson(input: $input) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  updatePersonMutation: `\n    mutation UpdatePerson($id: ID!, $input: PersonInput!) {\n      updatePerson(id: $id, input: $input) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  createPerson(input) {\n    return request(\"/graphql\", this.createPersonMutation, { input })\n  },\n  updatePerson(id, input) {\n    return request(\"/graphql\", this.updatePersonMutation, { id, input })\n  }\n}\n```\n\nA call to `createPerson({ firstName: \"Ola\", lastName: \"Englund\" })` will cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"createPerson\": {\n      \"id\": \"1\",\n      \"firstName\": \"Ola\",\n      \"lastName\": \"Englund\"\n    }\n  }\n}\n```\n\nIf you then wanted to update that person, you could call `updatePerson(\"1\", { lastName: \"Strandberg\" })` which would result in:\n\n```json\n{\n  \"data\": {\n    \"updatePerson\": {\n      \"id\": \"1\",\n      \"firstName\": \"Ola\",\n      \"lastName\": \"Strandberg\"\n    }\n  }\n}\n```\n\n#### Automatic Mutation Conventions\n\nMirage GraphQL will automatically resolve these mutations per these conventions:\n\n* A mutation that returns an object type and has one argument, an input type, will create a record with the given input type attributes.\n* 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.\n* A mutation that returns an object type and has one argument, an ID type, will delete a record having that ID.\n\nAny other combination of arguments for a mutation requires a resolver. This can be seen in a later example.\n\n### Example: Filtering People\n\nIn 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.\n\n#### Part 1: Filtering by Last Name\n\nIn 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.\n\n```javascript\n// app/components/people.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nserver.create(\"person\", { firstName: \"Mikael\", lastName: \"Åkerfeldt\" })\nserver.create(\"person\", { firstName: \"Per\", lastName: \"Nilsson\" })\nserver.create(\"person\", { firstName: \"Tomas\", lastName: \"Haake\" })\n\nexport default {\n  // ...other component stuff\n\n  peopleQuery: `\n    query People($firstName: String, $lastName: String, $sortBy: String) {\n      people(firstName: $firstName, lastName: $lastName, sortBy: $sortBy) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  getPeopleByLastName(lastName) {\n    return request(\"/graphql\", this.peopleQuery, { lastName })\n  }\n}\n```\n\nA call to `getPeopleByLastName(\"Haake\")` will cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"people\": [\n      {\n        \"id\": \"3\",\n        \"firstName\": \"Tomas\",\n        \"lastName\": \"Haake\"\n      }\n    ]\n  }\n}\n```\n\n#### Part 2: Sorting\n\nIn 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.\n\nIn the Mirage server setup:\n\n```javascript\n// app/mirage/server.js\n\nimport { createServer } from \"miragejs\"\nimport graphQLSchema from \"app/gql/schema.gql\"\nimport {\n  createGraphQLHandler,\n  mirageGraphQLFieldResolver\n} from \"@miragejs/graphql\"\n\nexport function makeServer() {\n  return createServer({\n    routes() {\n      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema, {\n        resolvers: {\n          Query: {\n            people(obj, args, context, info) {\n              const { sortBy } = args\n              \n              delete args.sortBy\n              \n              const records =\n                mirageGraphQLFieldResolver(obj, args, context, info)\n\n              return records.sort((a, b) =\u003e a[sortBy].localeCompare(b[sortBy]))\n            }\n          }\n        }\n      })\n\n      this.post(\"/graphql\", graphQLHandler)\n    }\n  })\n}\n```\n\nNote: 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.\n\nHaving added a resolver to handle the `sortBy` argument, the following component example will now work:\n\n```javascript\n// app/components/people.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nserver.create(\"person\", { firstName: \"Mikael\", lastName: \"Åkerfeldt\" })\nserver.create(\"person\", { firstName: \"Per\", lastName: \"Nilsson\" })\nserver.create(\"person\", { firstName: \"Tomas\", lastName: \"Haake\" })\n\nexport default {\n  // ...other component stuff\n\n  peopleQuery: `\n    query People($firstName: String, $lastName: String, $sortBy: String) {\n      people(firstName: $firstName, lastName: $lastName, sortBy: $sortBy) {\n        id\n        firstName\n        lastName\n      }\n    }\n  `,\n  getSortedPeopleBy(sortBy) {\n    return request(\"/graphql\", this.peopleQuery, { sortBy })\n  }\n}\n```\n\nA call to `getSortedPeopleBy(\"lastName\")` will cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"people\": [\n      {\n        \"id\": \"1\",\n        \"firstName\": \"Mikael\",\n        \"lastName\": \"Åkerfeldt\"\n      },\n      {\n        \"id\": \"3\",\n        \"firstName\": \"Tomas\",\n        \"lastName\": \"Haake\"\n      },\n      {\n        \"id\": \"2\",\n        \"firstName\": \"Per\",\n        \"lastName\": \"Nilsson\"\n      }\n    ]\n  }\n}\n```\n\n### Example: Deleting a Person\n\nIf 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.\n\nIn the Mirage server setup:\n\n```javascript\n// app/mirage/server.js\n\nimport { createServer } from \"miragejs\"\nimport graphQLSchema from \"app/gql/schema.gql\"\nimport {\n  createGraphQLHandler,\n  mirageGraphQLFieldResolver\n} from \"@miragejs/graphql\"\n\nexport function makeServer() {\n  return createServer({\n    routes() {\n      const graphQLHandler = createGraphQLHandler(graphQLSchema, this.schema, {\n        resolvers: {\n          Mutation: {\n            deletePerson(obj, args, context, info) {\n              const person = context.mirageSchema.db.people.find(args.id)\n\n              if (person) {\n                context.mirageSchema.db.people.remove(args.id)\n\n                return true\n              }\n\n              return false\n            }\n          }\n        }\n      })\n\n      this.post(\"/graphql\", graphQLHandler)\n    }\n  })\n}\n```\n\nHaving added a resolver to handle the mutation, the following component example will now work:\n\n```javascript\n// app/components/people.js\n\nimport { createServer } from \"app/mirage/server\"\nimport { request } from \"graphql-request\"\n\nconst server = createServer()\n\nexport default {\n  // ...other component stuff\n\n  deletePersonMutation: `\n    mutation DeletePerson($id: ID!) {\n      deletePerson(id: $id)\n    }\n  `,\n  deletePerson(id) {\n    return request(\"/graphql\", this.deletePersonMutation, { id })\n  }\n}\n```\n\nA call to `deletePerson(\"1\")` will remove the record from Mirage's database and cause Mirage GraphQL to respond with:\n\n```json\n{\n  \"data\": {\n    \"deletePerson\": true\n  }\n}\n```\n\n## Getting Help and Contributing\n\nDiscussions are welcome anywhere including the Mirage Discord server's `#graphql` channel. Please feel free to reach out for help or to collaborate.\n\nAny contributions are welcome. The most helpful contributions come from new use cases and most often arrive in the form of GitHub issues. One great way to contribute a new use case is by adding a failing test.\n\n## History\n\nAs Mirage itself evolved from an Ember add-on ([ember-cli-mirage](https://ember-cli-mirage.com)) so too did Mirage GraphQL ([ember-cli-mirage-graphql](https://github.com/kloeckner-i/ember-cli-mirage-graphql)).\n\n### Differences from `ember-cli-mirage-graphql`\n\nThe `ember-cli-mirage-graphql` add-on doesn't leverage very many features of [GraphQL JS](https://github.com/graphql/graphql-js) and does quite a lot of custom work to resolve queries.\n\nThere are several disadvantages to its approach, namely:\n\n* It doesn't use resolvers but rather uses the mocking feature from [GraphQL Tools](https://github.com/ardatan/graphql-tools). This can lead to some strange results, if every field isn't mocked properly.\n* It doesn't use much of GraphQL's API and re-implements a lot of existing functionality in a less robust way.\n* It doesn't use Mirage's ORM API which introduces many limitations on its ability to automatically resolve records.\n* The add-on's API includes custom field and variable mapping which can be avoided entirely by providing the ability to supply your own resolvers.\n\n### Upgrading\n\nIf you want to upgrade to Mirage GraphQL from `ember-cli-mirage-graphql`, you may need to make some significant changes in how you create the GraphQL handler. Firstly, you will need to pass in your Mirage schema as shown at the top of this README.\n\nIf you used any of the options, `fieldsMap`, `varsMap` and `mutations`, you will need to re-implement them with resolvers; though, hopefully some mutations can be automatically resolved for you now.\n\n## Special Thanks\n\nSpecial thanks for helping this library evolve go out to [Sam Selikoff](https://github.com/samselikoff), [Chad Carbert](https://github.com/chadian), [Jamie White](https://github.com/jgwhite), [Blake Gentry](https://github.com/bgentry), [Ruben Manrique](https://github.com/miwialex), [Louis-Michel Couture](https://github.com/louim), [David Mazza](https://github.com/dmzza), [Cameron Nicklaus](https://github.com/camnicklaus) and [Bert De Block](https://github.com/bertdeblock).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiragejs%2Fgraphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiragejs%2Fgraphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiragejs%2Fgraphql/lists"}