{"id":15407650,"url":"https://github.com/saltyaom/mobius","last_synced_at":"2025-05-16T11:03:50.962Z","repository":{"id":185927880,"uuid":"673811694","full_name":"SaltyAom/mobius","owner":"SaltyAom","description":"End-to-end type safe TypeScript GraphQL Client","archived":false,"fork":false,"pushed_at":"2024-11-18T04:36:47.000Z","size":392,"stargazers_count":405,"open_issues_count":3,"forks_count":4,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-04-09T07:01:36.612Z","etag":null,"topics":["graphql","graphql-mobius","mobius","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/SaltyAom.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2023-08-02T13:29:52.000Z","updated_at":"2025-04-04T14:27:42.000Z","dependencies_parsed_at":"2025-02-18T00:01:07.547Z","dependency_job_id":null,"html_url":"https://github.com/SaltyAom/mobius","commit_stats":null,"previous_names":["saltyaom/mobius"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaltyAom%2Fmobius","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaltyAom%2Fmobius/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaltyAom%2Fmobius/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SaltyAom%2Fmobius/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SaltyAom","download_url":"https://codeload.github.com/SaltyAom/mobius/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254518384,"owners_count":22084374,"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","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","graphql-mobius","mobius","typescript"],"created_at":"2024-10-01T16:29:21.087Z","updated_at":"2025-05-16T11:03:50.913Z","avatar_url":"https://github.com/SaltyAom.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GraphQL Mobius\nGraphQL to TypeScript type, **no code gen** with ith Prisma-like query syntax, fully type-safe.\n\n**Written purely in TypeScript type.**\n\n![Mobius Plushie](https://github.com/user-attachments/assets/fffb4a7d-3da0-4acf-a479-440b80d26be3)\n\n\u003c!-- Brought to you by [ElysiaJS](https://elysiajs.com) --\u003e\n\n\u003c!-- ![mobius](https://github.com/SaltyAom/mobius/assets/35027979/0bb3291e-49f2-45da-9bcf-3e283ec3cc4d) --\u003e\n\n---\n\nMobius can parse GraphQL schema to TypeScript to create End-to-end type safe GraphQL client in TypeScript.\n\nMade possible by Template Literal and various dark magic.\n\n### Known Caveat:\n- Comment must not have \"{}\" (bracket) otherwise type will not be resolved\n- Nested fragment is not supported\n- TypeScript has limited total stack, pass around ~8-9 locs / 14k generated around ~900 types (compacted, only types)\n\n## Why\nThis is a proof that you can run GraphQL with end-to-end type safety.\n\nThis is a bare minimum utility library, not intent to replace GraphQL client like URQL and GraphQL Apollo.\n\nMobius acts as a companion library or internal engine to add Type Safety layer over a new or an existing one.\n\nMobius does 2 things:\n1. Infers GraphQL to TypeScript types\n2. A bare minimum client that use Prisma-like syntax to query GraphQL\n\nYou can use Mobius in your library / framework, just please keep the **LICENSE** mentioned that you are using **GraphQL Mobius** (It's MIT License, feels free to fork or improve on it)\n\n## Prerequisted\n1. TypeScript \u003e 5.0\n2. Set `strict` to true in **tsconfig.json**\n\n## Getting Start\n1. Define a GraphQL Schema in string **(must be const)**\n2. Cast schema to type using `typeof` (or pass it as literal params in constructor)\n\n```ts\nimport { Mobius } from 'graphql-mobius'\n\nconst typeDefs = `\n    type A {\n        A: String!\n        B: String!\n    }\n\n    type Query {\n        Hello(word: String!): A!\n    }\n`\n\nconst mobius = new Mobius\u003ctypeof typeDefs\u003e({\n    // Using Mobius default fetch client\n    url: 'https://api.saltyaom.com/graphql'\n})\n\n// This is also fine, if you don't care about TypeDefs being available on client-side\nconst mobius2 = new Mobius({\n    url: 'https://api.saltyaom.com/graphql'\n    typeDefs\n})\n\n// Call query to execute query\nconst result = await mobius.query({\n    Hello: {\n        where: {\n            word: 'Hi'\n        },\n        select: {\n            A: true\n        }\n    }\n})\n\nresult\n    .then(x =\u003e x?.Hello.A)\n    .then(console.log)\n```\n\n## Mobius Client\nMobius client provided the following method:\n- $: Query all types of query at once\n- query: Query GraphQL\n- mutate: Mutate GraphQL\n- subscription: Subscribe GraphQL\n\nMobius client provided the following properties:\n- mobius: For type declaration only\n- fragments: Type-safe GraphQL fragments (type is always provided, literal code is available if `typeDefs` is passed)\n\n## Mobius Types\nMobius type extends `Record\u003cstring, unknown\u003e` with the base of following:\n- Query: `Record\u003cstring, unknown\u003e`\n- Mutation: `Record\u003cstring, unknown\u003e`\n- Subscription: `Record\u003cstring, unknown\u003e`\n- Fragment: `Record\u003cstring, unknown\u003e`\n- Rest of the types declarations infers from GraphQL Schema\n\n[@see Utility Types for an example usage and more detailed explaination](#utility-type)\n\n## Scalar\nYou can add custom scalars type by passing types as second generic.\n\n```ts\nimport { Mobius } from 'graphql-mobius'\n\nconst typeDefs = `\n    type A {\n        A: String!\n        B: Date!\n    }\n`\n\ntype Scalars = {\n    Data: Date\n}\n\nconst client = new Mobius\u003ctypeof typeDefs\u003e()\n\nclient.klein\n/**\n * A: {\n *   A: string\n *   B: Date\n * }\n */\n```\n\nIf scalars isn't provided but is defined in GraphQL anyway, it should resolved as **unknown**\n\n## Resolvers\nYou can use Mobius to strictly type `Resolvers` function for GraphQL Apollo and GraphQL Yoga.\n\n### Using Mobius Instance\n```ts\nimport { Mobius } from 'graphql-mobius'\n\nconst typeDefs = `\n    type A {\n        A: String!\n        B: String!\n    }\n\n    type Query {\n        Hello(word: String!): A!\n    }\n`\n\nconst mobius = new Mobius({\n    typeDefs\n})\n\nconst resolvers = {\n    Query: {\n        Hello(_, { word }) {\n            return {\n                A: \"Hello\",\n                B: \"Hello\"\n            }\n        }\n    }\n} satisfies typeof mobius.resolvers\n```\n\n### Using Type Definitions\n```ts\nimport type { CreateMobius, Resolvers } from 'graphql-mobius'\n\nconst typeDefs = `\n    type A {\n        A: String!\n        B: String!\n    }\n\n    type Query {\n        Hello(word: String!): A!\n    }\n`\n\ntype Resolver = Resolvers\u003cCreateMobius\u003ctypeof typeDefs\u003e\u003e\n\nconst resolvers = {\n    Query: {\n        Hello(_, { word }) {\n            return {\n                A: \"Hello\",\n                B: \"Hello\"\n            }\n        }\n    }\n} satisfies Resolver\n```\n\n## Fragment\nYou use use `mobius.fragment` **if you provided typeDefs as literal code**\n\nFragment syntax works like rest parameters which looks like GraphQL fragment syntax.\n\n```ts\nconst typeDefs = `\n    interface A {\n        A: String!\n        B: String!\n        C: String!\n        D: String!\n    }\n\n    fragment APart on A {\n        A\n        B\n    }\n\n    type Query {\n        GetA: A!\n    }\n`\n\nconst mobius = new Mobius({\n    typeDefs\n})\n\nconst { APart } = mobius.fragments!\n\nmobius.query({\n    GetA: {\n        ...APart,\n        C: true\n    }\n})\n```\n\n## Utility type\nFor framework, and library author.\n\nYou can use exported utilities types from **graphql-mobius** to achieve End-to-end type safety while **not increasing any byte att all** for your project's bundle.\n\n```ts\nimport type { CreateMobius } from 'graphql-mobius'\n\nconst typeDefs = `\n    # Hello World\n    type A {\n        A: String!\n        B: String!\n    }\n\n    # Hello World\n    type Query {\n        Hello(word: String!): A!\n    }\n`\n\n// This is an equivalent to calling new Mobius().klein\ntype Engine = CreateMobius\u003ctypeof typeDefs\u003e\n```\n\n### Structured\n`CreateMobius` will returned type structured as extends `Record\u003cstring, unknown\u003e` the base of following:\n- Query: `Record\u003cstring, unknown\u003e`\n- Mutation: `Record\u003cstring, unknown\u003e`\n- Subscription: `Record\u003cstring, unknown\u003e`\n- Fragment: `Record\u003cstring, unknown\u003e`\n- Rest of the types declarations infers from GraphQL Schema\n\n### Others utilities\n- `CreateMobius (Type)` - Infers GraphQL types to TypeScript\n- `Resolver (Type)` - Infers GraphQL types to TypeScript\n- `RemoveComment (Type)` - Remove GraphQL comment in type-level\n- `CreateQuery (Type)` - Create Prisma-like argument syntax for Client\n- `MakeExecutable (Type)` - Create Prisma-like function for GraphQL\n- `mobiusToGraphQL` - Map Prisma-like JSON to GraphQL query (string)\n- `createFragment` - Create fragments for usage in Prisma-like client\n\n## About fetch\nAs mentioned that Mobius is not intent to replace existing GraphQL client, but designed to create an abstraction over.\n\nAllowing you to integrate with existing library by providing a custom fetcher with the following type:\n```ts\ntype Fetcher = (query: string) =\u003e Promise\u003cunknown\u003e\n```\n\nFetch function is a callback function that executed when new request is calls, and will accept a stringified GraphQL query and expected to return a GraphQL response.\n\nIt's intent to be use like the following:\n```ts\n// Using URQL\nnew Mobius({\n    fetch: urql.query\n})\n\n// Using native fetch (default)\nnew Mobius({\n    fetch: (query) =\u003e fetch(this.config.url, {\n        method: 'POST',\n        headers: {\n            'Content-Type': 'application/json',\n        },\n        body: JSON.stringify({\n            query,\n            variables: {}\n        }),\n    })\n    .then((res) =\u003e res.json())\n})\n```\n\nThe library that you want to query GraphQL to use with Mobius is your choice, it's designed to be that way.\n\n---\n\nGraphQL Mobius is a library to convert GraphQL to TypeScript type **without code generation**, by using **purely TypeScript type.**\n\nIt's not intent to replace existing GraphQL client, but to create an abstraction over.\n\nYou can freely use Mobius in your source code / library / framework, just please keep the original **LICENSE** (MIT License)\n\nBrought to you by [ElysiaJS](https://elysiajs.com)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaltyaom%2Fmobius","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaltyaom%2Fmobius","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaltyaom%2Fmobius/lists"}