npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

graphql-mobius

v0.1.13

Published

End-to-end type safe TypeScript GraphQL Client

Downloads

2,148

Readme

GraphQL Mobius

GraphQL to TypeScript type, no code gen with ith Prisma-like query syntax, fully type-safe.

Written purely in TypeScript type.

Brought to you by ElysiaJS

mobius


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 GraphQL

You 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)
import { Mobius } from 'graphql-mobius'

const typeDefs = `
    type A {
        A: String!
        B: String!
    }

    type Query {
        Hello(word: String!): A!
    }
`

const mobius = new Mobius<typeof typeDefs>({
    // 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 GraphQL

Mobius 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<string, unknown> with the base of following:

  • Query: Record<string, unknown>
  • Mutation: Record<string, unknown>
  • Subscription: Record<string, unknown>
  • Fragment: Record<string, unknown>
  • Rest of the types declarations infers from GraphQL Schema

@see Utility Types for an example usage and more detailed explaination

Scalar

You can add custom scalars type by passing types as second generic.

import { Mobius } from 'graphql-mobius'

const typeDefs = `
    type A {
        A: String!
        B: Date!
    }
`

type Scalars = {
    Data: Date
}

const client = new Mobius<typeof typeDefs>()

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

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

import type { CreateMobius, Resolvers } from 'graphql-mobius'

const typeDefs = `
    type A {
        A: String!
        B: String!
    }

    type Query {
        Hello(word: String!): A!
    }
`

type Resolver = Resolvers<CreateMobius<typeof typeDefs>>

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.

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.

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<typeof typeDefs>

Structured

CreateMobius will returned type structured as extends Record<string, unknown> the base of following:

  • Query: Record<string, unknown>
  • Mutation: Record<string, unknown>
  • Subscription: Record<string, unknown>
  • Fragment: Record<string, unknown>
  • 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:

type Fetcher = (query: string) => Promise<unknown>

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:

// 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