Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/SaltyAom/mobius
End-to-end type safe TypeScript GraphQL Client
https://github.com/SaltyAom/mobius
graphql graphql-mobius mobius typescript
Last synced: 24 days ago
JSON representation
End-to-end type safe TypeScript GraphQL Client
- Host: GitHub
- URL: https://github.com/SaltyAom/mobius
- Owner: SaltyAom
- License: mit
- Created: 2023-08-02T13:29:52.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2024-11-18T04:36:47.000Z (about 1 month ago)
- Last Synced: 2024-11-24T07:51:21.149Z (29 days ago)
- Topics: graphql, graphql-mobius, mobius, typescript
- Language: TypeScript
- Homepage:
- Size: 383 KB
- Stars: 386
- Watchers: 5
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# GraphQL Mobius
GraphQL to TypeScript type, **no code gen** with ith Prisma-like query syntax, fully type-safe.**Written purely in TypeScript type.**
![Mobius Plushie](https://github.com/user-attachments/assets/fffb4a7d-3da0-4acf-a479-440b80d26be3)
---
Mobius can parse GraphQL schema to TypeScript to create End-to-end type safe GraphQL client in TypeScript.
Made possible by Template Literal and various dark magic.
### Known Caveat:
- Comment must not have "{}" (bracket) otherwise type will not be resolved
- Nested fragment is not supported
- TypeScript has limited total stack, pass around ~8-9 locs / 14k generated around ~900 types (compacted, only types)## Why
This is a proof that you can run GraphQL with end-to-end type safety.This is a bare minimum utility library, not intent to replace GraphQL client like URQL and GraphQL Apollo.
Mobius acts as a companion library or internal engine to add Type Safety layer over a new or an existing one.
Mobius does 2 things:
1. Infers GraphQL to TypeScript types
2. A bare minimum client that use Prisma-like syntax to query GraphQLYou 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)
## Prerequisted
1. TypeScript > 5.0
2. Set `strict` to true in **tsconfig.json**## Getting Start
1. Define a GraphQL Schema in string **(must be const)**
2. Cast schema to type using `typeof` (or pass it as literal params in constructor)```ts
import { Mobius } from 'graphql-mobius'const typeDefs = `
type A {
A: String!
B: String!
}type Query {
Hello(word: String!): A!
}
`const mobius = new Mobius({
// Using Mobius default fetch client
url: 'https://api.saltyaom.com/graphql'
})// This is also fine, if you don't care about TypeDefs being available on client-side
const mobius2 = new Mobius({
url: 'https://api.saltyaom.com/graphql'
typeDefs
})// Call query to execute query
const result = await mobius.query({
Hello: {
where: {
word: 'Hi'
},
select: {
A: true
}
}
})result
.then(x => x?.Hello.A)
.then(console.log)
```## Mobius Client
Mobius client provided the following method:
- $: Query all types of query at once
- query: Query GraphQL
- mutate: Mutate GraphQL
- subscription: Subscribe GraphQLMobius client provided the following properties:
- mobius: For type declaration only
- fragments: Type-safe GraphQL fragments (type is always provided, literal code is available if `typeDefs` is passed)## Mobius Types
Mobius type extends `Record` with the base of following:
- Query: `Record`
- Mutation: `Record`
- Subscription: `Record`
- Fragment: `Record`
- Rest of the types declarations infers from GraphQL Schema[@see Utility Types for an example usage and more detailed explaination](#utility-type)
## Scalar
You can add custom scalars type by passing types as second generic.```ts
import { Mobius } from 'graphql-mobius'const typeDefs = `
type A {
A: String!
B: Date!
}
`type Scalars = {
Data: Date
}const client = new Mobius()
client.klein
/**
* A: {
* A: string
* B: Date
* }
*/
```If scalars isn't provided but is defined in GraphQL anyway, it should resolved as **unknown**
## Resolvers
You can use Mobius to strictly type `Resolvers` function for GraphQL Apollo and GraphQL Yoga.### Using Mobius Instance
```ts
import { Mobius } from 'graphql-mobius'const typeDefs = `
type A {
A: String!
B: String!
}type Query {
Hello(word: String!): A!
}
`const mobius = new Mobius({
typeDefs
})const resolvers = {
Query: {
Hello(_, { word }) {
return {
A: "Hello",
B: "Hello"
}
}
}
} satisfies typeof mobius.resolvers
```### Using Type Definitions
```ts
import type { CreateMobius, Resolvers } from 'graphql-mobius'const typeDefs = `
type A {
A: String!
B: String!
}type Query {
Hello(word: String!): A!
}
`type Resolver = Resolvers>
const resolvers = {
Query: {
Hello(_, { word }) {
return {
A: "Hello",
B: "Hello"
}
}
}
} satisfies Resolver
```## Fragment
You use use `mobius.fragment` **if you provided typeDefs as literal code**Fragment syntax works like rest parameters which looks like GraphQL fragment syntax.
```ts
const typeDefs = `
interface A {
A: String!
B: String!
C: String!
D: String!
}fragment APart on A {
A
B
}type Query {
GetA: A!
}
`const mobius = new Mobius({
typeDefs
})const { APart } = mobius.fragments!
mobius.query({
GetA: {
...APart,
C: true
}
})
```## Utility type
For framework, and library author.You 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.
```ts
import type { CreateMobius } from 'graphql-mobius'const typeDefs = `
# Hello World
type A {
A: String!
B: String!
}# Hello World
type Query {
Hello(word: String!): A!
}
`// This is an equivalent to calling new Mobius().klein
type Engine = CreateMobius
```### Structured
`CreateMobius` will returned type structured as extends `Record` the base of following:
- Query: `Record`
- Mutation: `Record`
- Subscription: `Record`
- Fragment: `Record`
- Rest of the types declarations infers from GraphQL Schema### Others utilities
- `CreateMobius (Type)` - Infers GraphQL types to TypeScript
- `Resolver (Type)` - Infers GraphQL types to TypeScript
- `RemoveComment (Type)` - Remove GraphQL comment in type-level
- `CreateQuery (Type)` - Create Prisma-like argument syntax for Client
- `MakeExecutable (Type)` - Create Prisma-like function for GraphQL
- `mobiusToGraphQL` - Map Prisma-like JSON to GraphQL query (string)
- `createFragment` - Create fragments for usage in Prisma-like client## About fetch
As mentioned that Mobius is not intent to replace existing GraphQL client, but designed to create an abstraction over.Allowing you to integrate with existing library by providing a custom fetcher with the following type:
```ts
type Fetcher = (query: string) => Promise
```Fetch 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.
It's intent to be use like the following:
```ts
// Using URQL
new Mobius({
fetch: urql.query
})// Using native fetch (default)
new Mobius({
fetch: (query) => fetch(this.config.url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
variables: {}
}),
})
.then((res) => res.json())
})
```The library that you want to query GraphQL to use with Mobius is your choice, it's designed to be that way.
---
GraphQL Mobius is a library to convert GraphQL to TypeScript type **without code generation**, by using **purely TypeScript type.**
It's not intent to replace existing GraphQL client, but to create an abstraction over.
You can freely use Mobius in your source code / library / framework, just please keep the original **LICENSE** (MIT License)
Brought to you by [ElysiaJS](https://elysiajs.com)