Garph

Fullstack TypeScript experience for GraphQL-APIs

README

garph


Warning:

Garph is currently in Alpha. We would love to hear your Feedback on our Discord


Note:

tRPC-style client for Garph has arrived! See garph-gqty for more 🚀


Garph is a GraphQL schema-builder for TypeScript, that aims to deliver tRPC-like Developer-Experience. On top of that, Garph provides a GraphQL compability layer and type-safety primitives for any TypeScript project

Example of a GraphQL API built with Garph (served by Yoga):

  1. ```ts
  2. import { g, InferResolvers, buildSchema } from 'garph'
  3. import { createYoga } from 'graphql-yoga'
  4. import { createServer } from 'http'

  5. const queryType = g.type('Query', {
  6.   greet: g.string()
  7.     .args({
  8.       name: g.string().optional().default('Max')
  9.     })
  10.     .description('Greets a person')
  11. })

  12. const resolvers: InferResolvers<{ Query: typeof queryType }, {}> = {
  13.   Query: {
  14.     greet: (parent, args, context, info) => `Hello, ${args.name}`
  15.   }
  16. }

  17. const schema = buildSchema({ g, resolvers })
  18. const yoga = createYoga({ schema })
  19. const server = createServer(yoga)
  20. server.listen(4000, () => {
  21.   console.info('Server is running on http://localhost:4000/graphql')
  22. })
  23. ```

Produces the following GraphQL schema:

  1. ```gql
  2. type Query {
  3.   greet(name: String = "Max"): String!
  4. }
  5. ```

Get started


  1. ```
  2. npm i garph
  3. ```

  1. ```ts
  2. import { g } from 'garph'
  3. ```

Reference


Types


Object Type


  1. ```ts
  2. g.type('Name', {
  3.   greet: g.string()
  4. })
  5. ```

String


  1. ```ts
  2. g.string()
  3. ```

Int


  1. ```ts
  2. g.int()
  3. ```

Float


  1. ```ts
  2. g.float()
  3. ```

Boolean


  1. ```ts
  2. g.boolean()
  3. ```

ID


  1. ```ts
  2. g.id()
  3. ```

Enum


Plain:

  1. ```ts
  2. g.enumType('Name', ['A', 'B', 'C'] as const)
  3. ```

(We need as const for proper type inference)

From TypeScript Enum:

  1. ```ts
  2. enum Fruits {
  3.   Apples,
  4.   Oranges
  5. }

  6. g.enumType('Name', Fruits)
  7. ```

Union


  1. ```ts
  2. g.unionType('Name', { a, b })
  3. ```

Ref


Reference another type by name or pass-by-reference

  1. ```ts
  2. const name = g.type('Name', {
  3.   greet: g.string()
  4. })

  5. g.ref(name)
  6. ```

Alternative:

  1. ```ts
  2. const name = g.type('Name', {
  3.   greet: g.string()
  4. })

  5. g.ref(() => name)
  6. ```

See Circular References for handling circular references

Interface


  1. ```ts
  2. g.interface('Name', {
  3.   greet: g.string()
  4. })
  5. ```

Implementing an interface

  1. ```ts
  2. const test = g.type('Test', {}).implements(interface)
  3. ```

Or a set of interfaces:

  1. ```ts
  2. const test = g.type('Test', {}).implements([interface, interface])
  3. ```

Note: Inherited fields will be added to the schema automatically, you don't need to re-specify them


Input


  1. ```ts
  2. g.inputType('Name', {
  3.   greet: g.string()
  4. })
  5. ```

Scalar


  1. ```ts
  2. g.scalarType<Date, number>('Name', {
  3.   serialize: (value) => value.getTime(),
  4.   parseValue: (value) => new Date(value)
  5. })
  6. ```

Directive


Currently not supported

Fragment


Currently not supported

Modifiers


Modifiers can be chained together to produce desired type

Implements


  1. ```ts
  2. const test = g.type('Test', {}).implements(interface)
  3. ```

Or array of interfaces:

  1. ```ts
  2. const test = g.type('Test', {}).implements([interface, interface])
  3. ```

List


  1. ```ts
  2. g.string().list()
  3. ```

Optional (nullable)


  1. ```ts
  2. g.string().optional()
  3. ```

Description


  1. ```ts
  2. g.string().description("Description")
  3. ```

Args


  1. ```ts
  2. g.string().args({
  3.   name: g.string()
  4. })
  5. ```

Required


  1. ```ts
  2. g.string().required()
  3. ```

Default


  1. ```ts
  2. g.string().default("Default string")
  3. ```

Deprecated


  1. ```ts
  2. g.string().deprecated("Deprecation reason")
  3. ```

Extras


Inferring Types


Types can be inferred into TypeScript using the Infer utility

  1. ```ts
  2. import { g, Infer } from 'garph'

  3. const nameType = g.type('Name', {
  4.   greet: g.string()
  5. })

  6. type NameType = Infer<typeof nameType>
  7. ```

Inferred type:

  1. ```ts
  2. type NameType = {
  3.   greet: string
  4. }
  5. ```

Inferring Args


Argument Types can be inferred into TypeScript using the InferArgs utility

  1. ```ts
  2. import { g, InferArgs } from 'garph'

  3. const nameType = g.type('Name', {
  4.   greet: g.string().args({ name: g.string().optional() })
  5. })

  6. type NameType = InferArgs<typeof nameType>
  7. ```

Inferred type:

  1. ```ts
  2. type NameType = {
  3.   greet: {
  4.     name: string | null | undefined
  5.   }
  6. }
  7. ```

Inferring Resolvers


Resolvers can be inferred into TypeScript using the InferResolvers utility

  1. ```ts
  2. const queryType = g.type('Query', {
  3.   greet: g.string()
  4.   .args({
  5.     name: g.string().optional().default('Max'),
  6.   })
  7.   .description('Greets a person')
  8. })

  9. const resolvers: InferResolvers<{ Query: typeof queryType }, { context: any, info: any }> = {
  10.   Query: {
  11.     greet: (parent, args, context, info) => `Hello, ${args.name}`
  12.   }
  13. }
  14. ```

Inferred type:

  1. ```ts
  2. {
  3.   Query: {
  4.     greet?: (parent: any, args: {
  5.       name: string
  6.     }, context: any, info: any) => string | Promise<string>
  7.   }
  8. }
  9. ```

Circular References


With Garph, circular references work just as you expect them to

Example GraphQL Schema:

  1. ```gql
  2. type User {
  3.   name: String!
  4.   age: Int!
  5.   friends(includeLastName: Boolean): [User!]!
  6. }
  7. ```

Converted to Garph schema:

  1. ```ts
  2. const userType = g.type('User', {
  3.   name: g.string(),
  4.   age: g.int(),
  5.   friends: g.ref(() => userType).list()
  6.     .args({
  7.       includeLastName: g.boolean().optional()
  8.     })
  9. })
  10. ```

Inferred type:

  1. ```ts
  2. type UserType = {
  3.   name: string;
  4.   age: number;
  5.   friends: ...;
  6. }
  7. ```

Converting to GraphQL schema


  1. ```ts
  2. import { buildSchema } from 'garph'
  3. const schema = buildSchema({ g, resolvers }, { defaultNullability: false })
  4. ```

Examples


Example projects can be found under [examples/](examples/)

Feedback


We would love to hear your Feedback on our Discord community