Protocols
GraphQL Integration
Optional GraphQL support with Pothos for TypeScript-first schemas, GraphQL-JIT for performance, and WebSocket subscriptions for real-time data.
Overview
Add GraphQL to your API with one call. TypeScript-first schemas, WebSocket subscriptions, and 5-10x performance boost included.
1import { createApp } from '@morojs/moro';
2
3const app = await 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/playgroundWithout 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
Use Pothos for TypeScript-first schemas. Get full type inference automatically.
1import { createApp } from '@morojs/moro';
2import SchemaBuilder from '@pothos/core';
3
4const app = await 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 });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 runs alongside your existing REST API in the same app instance. 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
1import { createApp } from '@morojs/moro';
2
3const app = await 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});1import { createApp } from '@morojs/moro';
2import SchemaBuilder from '@pothos/core';
3
4const app = await 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
1import { createApp, createPothosBuilder } from '@morojs/moro';
2
3const app = await 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/subscriptions1app.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 functions1import { createApp, createPothosBuilder, createDataLoader } from '@morojs/moro';
2
3const app = await 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});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