Skip to content

lithium-apps/adonis-graphql

Repository files navigation

Contributors Forks Stargazers Issues License GitHub Build


Logo

@lithium-apps/adonis-graphql

Create powerful GraphQL APIs with your AdonisJS Application

Request Feature · Report Bug · Request Modification

Table of Contents
  1. About The Project
  2. Installation
  3. Configuration
  4. Usage
  5. Features
  6. Advanced Configuration
  7. Contact

About the project

This package provides a seamless integration of GraphQL into your AdonisJS application using Apollo Server and TypeGraphQL. It supports multiple GraphQL schemas with separate endpoints, making it perfect for scenarios like separating public and admin APIs, or versioning your GraphQL endpoints.

Key Features:

  • 🚀 Easy integration with AdonisJS 6+
  • 🔄 Support for multiple GraphQL schemas with different endpoints
  • 🎯 Type-safe with TypeScript and TypeGraphQL
  • 🔐 Built-in authentication and authorization with AdonisJS Auth and Bouncer
  • 🎮 GraphQL Playground support for development
  • 📡 WebSocket support for real-time subscriptions
  • 🔧 Auto-loading resolvers with glob patterns
  • 📝 Built-in validation with VineJS integration
  • 🕒 Custom scalars (LuxonDateTime included)
  • 🎨 Flexible Apollo Server configuration per schema

We welcome contributions and improvements to this module. Don't hesitate to submit features and improvements ;)

(back to top)

Built With

  • TypeScript
  • Apollo
  • GraphQL

(back to top)

Installation

For now the package isn't published to npm, but you can install it from the GitHub registry and can be installed in any project.

  1. You need to create a .npmrc file at the root of your project with the following content:

    @lithium-apps:registry=https://npm.pkg.github.com
  2. For the login process you need to set a personal access token with the read:packages scope. Then you can login to the GitHub registry with the following command:

    pnpm login --registry=https://npm.pkg.github.com --scope=@lithium-apps
  3. Install the package using the following command:

    pnpm install @lithium-apps/adonis-graphql
  4. Configure the package:

    node ace configure @lithium-apps/adonis-graphql

This will:

  • Add the GraphQL provider to your adonisrc.ts
  • Create a config/graphql.ts configuration file
  • Create a start/graphql.ts file for registering resolvers
  • Create a demo resolver in app/graphql/resolvers/demo_resolver.ts
  • Install required dependencies (graphql, type-graphql, graphql-scalars)
  • Add the #graphql/* import alias to your package.json

(back to top)

Configuration

After installation, the package creates a configuration file at config/graphql.ts:

import app from '@adonisjs/core/services/app'
import { defineConfig } from '@lithium-apps/adonis-graphql'

export default defineConfig({
  main: {
    path: '/graphql',
    apollo: {
      introspection: !app.inProduction,
      playground: !app.inProduction,
    },
    emitSchemaFile: true,
  }
})

(back to top)

Usage

Single Schema

For a single GraphQL API, use the default configuration:

  1. Create a resolver:
// app/graphql/resolvers/user_resolver.ts
import { Resolver, Query, Arg } from '@lithium-apps/adonis-graphql'

@Resolver()
export default class UserResolver {
  @Query(() => String)
  hello(@Arg('name') name: string): string {
    return `Hello ${name}!`
  }
}
  1. Register the resolver in start/graphql.ts:
import graphql from '@lithium-apps/adonis-graphql/services/main'

graphql.use('main').resolvers([
  () => import('#graphql/resolvers/demo_resolver'),
  () => import('#graphql/resolvers/user_resolver'),
])

Multiple Schemas

For multiple GraphQL APIs (e.g., public and admin), update your configuration:

  1. Update config/graphql.ts:
import app from '@adonisjs/core/services/app'
import { defineConfig } from '@lithium-apps/adonis-graphql'

export default defineConfig({
  public: {
    path: '/graphql',
    apollo: {
      introspection: !app.inProduction,
      playground: !app.inProduction,
    },
    emitSchemaFile: true,
    // Auto-load resolvers matching this pattern
    resolverPatterns: [
      './app/graphql/public/*_resolver.js'
    ]
  },
  admin: {
    path: '/admin/graphql',
    apollo: {
      introspection: !app.inProduction,
      playground: !app.inProduction,
    },
    emitSchemaFile: true,
    resolverPatterns: [
      './app/graphql/admin/*_resolver.js'
    ]
  }
})
  1. Register resolvers for each schema:
// start/graphql.ts
import graphql from '@lithium-apps/adonis-graphql/services/main'

// Public API resolvers
await graphql.use('public').resolvers([
  () => import('#graphql/public/user_resolver'),
  () => import('#graphql/public/post_resolver'),
])

// Admin API resolvers  
await graphql.use('admin').resolvers([
  () => import('#graphql/admin/admin_resolver'),
  () => import('#graphql/admin/analytics_resolver'),
])

Creating Resolvers

Basic resolver:

import { Resolver, Query, Mutation, Arg } from 'type-graphql'

@Resolver()
export default class UserResolver {
  @Query(() => String)
  hello(@Arg('name') name: string): string {
    return `Hello ${name}!`
  }

  @Mutation(() => Boolean)
  createUser(@Arg('email') email: string): boolean {
    // Your logic here
    return true
  }
}

With HttpContext:

import { Resolver, Query, Ctx } from 'type-graphql'
import type { HttpContext } from '@adonisjs/core/http'

@Resolver()
export default class UserResolver {
  @Query(() => String)
  async currentUser(@Ctx() ctx: HttpContext): Promise<string> {
    await ctx.auth.check()
    return ctx.auth.user?.email || 'Guest'
  }
}

Authentication & Authorization

Using the CurrentUser decorator:

import { Resolver, Query } from 'type-graphql'
import { CurrentUser } from '@lithium-apps/adonis-graphql'

@Resolver()
export default class UserResolver {
  @Query(() => String)
  profile(@CurrentUser() user: any): string {
    return `Welcome ${user.email}!`
  }
}

Using authorization with Bouncer:

import { Resolver, Query, Authorized } from 'type-graphql'

@Resolver()
export default class AdminResolver {
  @Authorized(['viewAdminPanel']) // Bouncer ability name
  @Query(() => String)
  adminData(): string {
    return 'Secret admin data'
  }

  @Authorized() // Just requires authentication
  @Query(() => String)
  protectedData(): string {
    return 'Protected data'
  }
}

Validation

Using VineJS validation:

import { Resolver, Mutation, Arg } from 'type-graphql'
import { validateArgs } from '@lithium-apps/adonis-graphql/decorators/vine/main'
import vine from '@vinejs/vine'

const createUserSchema = vine.compile(
  vine.object({
    email: vine.string().email(),
    name: vine.string().minLength(2),
  })
)

@Resolver()
export default class UserResolver {
  @validateArgs(createUserSchema)
  @Mutation(() => Boolean)
  createUser(
    @Arg('email') email: string,
    @Arg('name') name: string
  ): boolean {
    // Arguments are automatically validated
    return true
  }
}

Scalars

Using built-in LuxonDateTime scalar:

import { Resolver, Query, Field, ObjectType } from 'type-graphql'
import { DateTime } from 'luxon'

@ObjectType()
class Post {
  @Field()
  title: string

  @Field(() => DateTime)
  createdAt: DateTime
}

@Resolver()
export default class PostResolver {
  @Query(() => Post)
  latestPost(): Post {
    return {
      title: 'Latest Post',
      createdAt: DateTime.now()
    }
  }
}

(back to top)

Features

  • Multiple GraphQL Schemas: Create separate APIs for different purposes (public, admin, etc.)
  • Automatic Endpoint Creation: All configured schemas are automatically instantiated and started
  • Type-Safe: Full TypeScript support with TypeGraphQL decorators
  • Authentication & Authorization: Built-in support for AdonisJS Auth and Bouncer
  • GraphQL Playground: Interactive API explorer for development
  • Auto-Loading: Load resolvers automatically using glob patterns
  • WebSocket Support: Real-time subscriptions with GraphQL subscriptions
  • Single HTTP Server: All schemas share the same HTTP server
  • Flexible Configuration: Independent Apollo Server configuration per schema
  • VineJS Integration: Built-in validation decorators for arguments
  • Custom Scalars: Includes LuxonDateTime scalar, easily extensible
  • Container Integration: Full dependency injection support
  • Error Handling: Comprehensive error handling with custom error types

(back to top)

Advanced Configuration

Custom scalars configuration:

import { defineConfig } from '@lithium-apps/adonis-graphql'
import { DateTimeScalar } from 'graphql-scalars'

export default defineConfig({
  main: {
    path: '/graphql',
    apollo: {
      introspection: true,
      playground: true,
    },
    scalarsMap: [
      { type: Date, scalar: DateTimeScalar },
    ],
    emitSchemaFile: true,
  }
})

WebSocket subscriptions:

import { defineConfig } from '@lithium-apps/adonis-graphql'
import { RedisPubSub } from 'graphql-redis-subscriptions'

export default defineConfig({
  main: {
    path: '/graphql',
    apollo: {
      introspection: true,
      playground: true,
    },
    // Enable subscriptions by providing a PubSub instance
    pubSub: new RedisPubSub({
      connection: {
        host: '127.0.0.1',
        port: 6379,
      }
    }),
    emitSchemaFile: true,
  }
})

Resolver patterns for auto-loading:

import { defineConfig } from '@lithium-apps/adonis-graphql'

export default defineConfig({
  api: {
    path: '/api/graphql',
    resolverPatterns: [
      './app/graphql/api/**/*_resolver.js',
      './app/graphql/shared/*_resolver.js'
    ],
    apollo: {
      introspection: true,
      playground: true,
    },
    emitSchemaFile: true,
  }
})

(back to top)

Contact

(back to top)

About

Create GraphQL APIs powered by Apollo GraphQL and TypeGraphQL on AdonisJS.

Resources

License

Stars

Watchers

Forks

Packages

No packages published