Features
Docs
CLI
Benchmarks
Examples

© 2024 MoroJs

GraphQL Integration

Optional GraphQL support with Pothos for TypeScript-first schemas, GraphQL-JIT for performance, and WebSocket subscriptions for real-time data.

GraphQL That Just Works

Add GraphQL to your API with one call.
TypeScript-first schemas, WebSocket subscriptions, and 5-10x performance boost included.

It's This Simple

Enable GraphQL with one call

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp();
4
5app.graphqlInit({
6  typeDefs: `
7    type Query {
8      hello(name: String): String!
9      users: [User!]!
10    }
11    type User {
12      id: ID!
13      name: String!
14      email: String!
15    }
16  `,
17  resolvers: {
18    Query: {
19      hello: (_parent, args) => `Hello ${args.name || 'World'}!`,
20      users: async () => {
21        return [
22          { id: '1', name: 'Alice', email: 'alice@example.com' },
23          { id: '2', name: 'Bob', email: 'bob@example.com' },
24        ];
25      },
26    },
27  },
28});
29
30app.listen(3000);
31// GraphQL API: http://localhost:3000/graphql
32// Playground: http://localhost:3000/graphql/playground

Why GraphQL Integration Matters

Without proper GraphQL setup, you're manually configuring servers, handling subscriptions, and managing performance. With MoroJS, you get all of that automatically.

Traditional GraphQL setup requires multiple libraries and complex configuration. We handle that automatically.

Without Integration

  • Manual GraphQL server setup
  • No TypeScript-first schemas
  • Manual subscription handling
  • No built-in performance optimization

With MoroJS

  • One-call GraphQL setup
  • Pothos for TypeScript-first schemas
  • Built-in WebSocket subscriptions
  • GraphQL-JIT for 5-10x performance

It's This Easy

Use Pothos for TypeScript-first schemas. Get full type inference automatically.

TypeScript-first with Pothos

typescript

1import { createApp } from '@morojs/moro';
2import SchemaBuilder from '@pothos/core';
3
4const app = createApp();
5const builder = new SchemaBuilder({});
6
7// Define User type with full TypeScript inference
8const User = builder.objectRef<{ id: string; name: string; email: string }>('User');
9
10User.implement({
11  fields: (t) => ({
12    id: t.exposeID('id'),
13    name: t.exposeString('name'),
14    email: t.exposeString('email'),
15  }),
16});
17
18// Define Query type
19builder.queryType({
20  fields: (t) => ({
21    hello: t.string({
22      args: { name: t.arg.string() },
23      resolve: (_parent, args) => `Hello ${args.name || 'World'}!`,
24    }),
25    users: t.field({
26      type: [User],
27      resolve: async () => [
28        { id: '1', name: 'Alice', email: 'alice@example.com' },
29        { id: '2', name: 'Bob', email: 'bob@example.com' },
30      ],
31    }),
32  }),
33});
34
35app.graphqlInit({ pothosSchema: builder });

Why It Makes Sense

TypeScript-First

Pothos support for TypeScript-first schemas

Fast

GraphQL-JIT for 5-10x performance boost

Real-time

WebSocket subscriptions for real-time data

Optional

Completely optional - zero dependencies if unused

How It Works

MoroJS provides optional GraphQL support that integrates seamlessly with your existing REST API. You can use standard GraphQL schemas, Pothos for TypeScript-first development, or both. GraphQL-JIT compilation provides significant performance improvements, and WebSocket subscriptions enable real-time features.

Quick Start

Basic GraphQL with Type Definitions

typescript

1import { createApp } from '@morojs/moro';
2
3const app = createApp();
4
5app.graphqlInit({
6  typeDefs: `
7    type Query {
8      hello(name: String): String!
9      users: [User!]!
10    }
11
12    type User {
13      id: ID!
14      name: String!
15      email: String!
16    }
17
18    type Mutation {
19      createUser(name: String!, email: String!): User!
20    }
21  `,
22  resolvers: {
23    Query: {
24      hello: (_parent, args) => `Hello ${args.name || 'World'}!`,
25      users: async () => {
26        // Fetch from database
27        return [
28          { id: '1', name: 'Alice', email: 'alice@example.com' },
29          { id: '2', name: 'Bob', email: 'bob@example.com' },
30        ];
31      },
32    },
33    Mutation: {
34      createUser: async (_parent, args) => {
35        // Create user in database
36        return {
37          id: '3',
38          name: args.name,
39          email: args.email,
40        };
41      },
42    },
43  },
44  // Optional: Custom context
45  context: async (req, res) => ({
46    request: req,
47    response: res,
48    user: req.auth?.user,
49  }),
50});
51
52app.listen(3000, () => {
53  console.log('GraphQL API: http://localhost:3000/graphql');
54  console.log('GraphQL Playground: http://localhost:3000/graphql/playground');
55});

TypeScript-First with Pothos

typescript

1import { createApp } from '@morojs/moro';
2import SchemaBuilder from '@pothos/core';
3
4const app = createApp();
5
6// Create Pothos schema builder
7const builder = new SchemaBuilder<{
8  Context: {
9    user?: { id: string; name: string };
10  };
11}>({});
12
13// Define User type with full TypeScript inference
14const User = builder.objectRef<{ id: string; name: string; email: string }>('User');
15
16User.implement({
17  fields: (t) => ({
18    id: t.exposeID('id'),
19    name: t.exposeString('name'),
20    email: t.exposeString('email'),
21  }),
22});
23
24// Define Query type
25builder.queryType({
26  fields: (t) => ({
27    hello: t.string({
28      args: {
29        name: t.arg.string(),
30      },
31      resolve: (_parent, args) => `Hello ${args.name || 'World'}!`,
32    }),
33    users: t.field({
34      type: [User],
35      resolve: async () => [
36        { id: '1', name: 'Alice', email: 'alice@example.com' },
37        { id: '2', name: 'Bob', email: 'bob@example.com' },
38      ],
39    }),
40  }),
41});
42
43// Configure GraphQL with Pothos schema
44app.graphqlInit({
45  pothosSchema: builder,
46  context: async (req, res) => ({
47    request: req,
48    response: res,
49    user: req.auth?.user,
50  }),
51});
52
53app.listen(3000);

Advanced Features

WebSocket Subscriptions

typescript

1import { createApp, createPothosBuilder } from '@morojs/moro';
2
3const app = createApp({
4  websocket: true, // Enable WebSocket support
5});
6
7const builder = createPothosBuilder();
8
9// Define subscription type
10builder.subscriptionType({
11  fields: (t) => ({
12    messageAdded: t.field({
13      type: 'String',
14      subscribe: async function* () {
15        // Simulate real-time events
16        let count = 0;
17        while (true) {
18          await new Promise((resolve) => setTimeout(resolve, 1000));
19          yield `Message ${++count}`;
20        }
21      },
22    }),
23  }),
24});
25
26app.graphqlInit({
27  pothosSchema: builder,
28  enableSubscriptions: true, // Enable subscriptions
29});
30
31app.listen(3000);
32
33// Client usage:
34// ws://localhost:3000/graphql/subscriptions

Performance with GraphQL-JIT

typescript

1app.graphqlInit({
2  typeDefs: '...',
3  resolvers: {},
4  enableJIT: true, // Enabled by default if graphql-jit is installed
5  jitCacheTTL: 3600000, // Cache compiled queries for 1 hour
6});
7
8// GraphQL-JIT provides 5-10x performance boost by compiling 
9// queries to JavaScript functions

DataLoader for Batching (N+1 Prevention)

typescript

1import { createApp, createPothosBuilder, createDataLoader } from '@morojs/moro';
2
3const app = createApp();
4const builder = createPothosBuilder();
5
6// Create DataLoader for batching user queries
7const createUserLoader = () =>
8  createDataLoader(async (userIds: readonly string[]) => {
9    // Batch fetch users from database
10    const users = await db.users.findMany({
11      where: { id: { in: [...userIds] } },
12    });
13
14    // Return in same order as requested
15    return userIds.map((id) => users.find((u) => u.id === id) || new Error('Not found'));
16  });
17
18builder.queryType({
19  fields: (t) => ({
20    posts: t.field({
21      type: [Post],
22      resolve: async () => db.posts.findMany(),
23    }),
24  }),
25});
26
27const Post = builder.objectRef<{ id: string; authorId: string; title: string }>('Post');
28
29Post.implement({
30  fields: (t) => ({
31    id: t.exposeID('id'),
32    title: t.exposeString('title'),
33    author: t.field({
34      type: User,
35      resolve: (post, _args, ctx) => {
36        // Uses DataLoader to batch user queries
37        return ctx.loaders.user.load(post.authorId);
38      },
39    }),
40  }),
41});
42
43app.graphqlInit({
44  pothosSchema: builder,
45  context: async (req, res) => ({
46    request: req,
47    response: res,
48    loaders: {
49      user: createUserLoader(),
50    },
51  }),
52});

Full Configuration

typescript

1app.graphqlInit({
2  // Schema definition (choose one)
3  schema: myGraphQLSchema, // Pre-built GraphQL schema
4  typeDefs: '...', // GraphQL SDL
5  pothosSchema: builder, // Pothos schema builder
6
7  // Context
8  context: async (req, res) => ({
9    request: req,
10    response: res,
11    user: req.auth?.user,
12  }),
13
14  // Endpoints
15  path: '/graphql', // Default endpoint
16  playgroundPath: '/graphql/playground',
17  enablePlayground: true, // Disabled in production
18
19  // Performance
20  enableJIT: true, // GraphQL-JIT compilation
21  jitCacheTTL: 3600000, // 1 hour
22
23  // Features
24  enableIntrospection: true, // Disabled in production
25  enableSubscriptions: true, // Requires WebSocket
26  enableBatching: true, // Query batching
27
28  // Error handling
29  formatError: (error) => ({
30    message: error.message,
31    // Hide internal errors in production
32  }),
33  debug: false, // Include stack traces
34
35  // Security
36  maxDepth: 10, // Query depth limit
37  maxComplexity: 1000, // Query complexity limit
38
39  // Rate limiting (per operation type)
40  rateLimit: {
41    queries: { requests: 100, window: 60000 },
42    mutations: { requests: 20, window: 60000 },
43  },
44});

Installation

Core Features

  • Pothos support for TypeScript-first schemas
  • GraphQL-JIT for 5-10x performance boost
  • WebSocket subscriptions for real-time data
  • GraphQL Playground for interactive exploration
  • Completely optional - zero dependencies if unused
  • DataLoader integration for N+1 prevention

Installation

Core Package
npm install graphql
Pothos (Optional)
npm install @pothos/core
GraphQL-JIT (Optional)
npm install graphql-jit
DataLoader (Optional)
npm install dataloader

Next Steps