🎉 RamAPI v1.0 is now available! Read the Getting Started Guide
Documentation
Protocols
GraphQL

GraphQL

Expose your API via GraphQL for flexible, efficient data fetching. RamAPI automatically generates GraphQL schemas from your operations.

Table of Contents

  1. Overview
  2. Setup
  3. Schema Builder
  4. Queries
  5. Mutations
  6. Playground

Overview

GraphQL allows clients to request exactly the data they need:

query {
  user(id: "123") {
    name
    email
    posts {
      title
      createdAt
    }
  }
}

Setup

Enable GraphQL

import { createApp } from 'ramapi';
 
const app = createApp({
  protocols: {
    graphql: {
      path: '/graphql',      // GraphQL endpoint
      playground: true,       // Enable playground
      introspection: true,    // Enable schema introspection
    },
  },
});

Register Operations

import { z } from 'zod';
 
const getUserOperation = {
  name: 'getUser',
  description: 'Get user by ID',
 
  input: z.object({
    id: z.string().uuid(),
  }),
 
  output: z.object({
    id: z.string(),
    name: z.string(),
    email: z.string().email(),
  }),
 
  handler: async (input, ctx) => {
    return await db.users.findById(input.id);
  },
 
  // GraphQL metadata
  graphql: {
    type: 'query',
  },
};
 
// Register with protocol manager
const protocolManager = app.getProtocolManager();
protocolManager?.registerOperation(getUserOperation);

Schema Builder

Automatic Schema Generation

RamAPI automatically generates GraphQL schema from Zod schemas:

// Zod schema
const userSchema = z.object({
  id: z.string(),
  name: z.string(),
  email: z.string().email(),
  age: z.number().int().optional(),
});
 
// Automatically becomes GraphQL type:
// type User {
//   id: String!
//   name: String!
//   email: String!
//   age: Int
// }

Type Mapping

Zod TypeGraphQL Type
z.string()String!
z.number()Float!
z.number().int()Int!
z.boolean()Boolean!
z.array(T)[T!]!
z.optional()Nullable
z.object()Type

Queries

Simple Query

const getPostOperation = {
  name: 'getPost',
 
  input: z.object({
    id: z.string(),
  }),
 
  output: z.object({
    id: z.string(),
    title: z.string(),
    content: z.string(),
  }),
 
  handler: async (input) => {
    return await db.posts.findById(input.id);
  },
 
  graphql: { type: 'query' },
};

Query:

query {
  getPost(id: "123") {
    id
    title
    content
  }
}

List Query

const listPostsOperation = {
  name: 'listPosts',
 
  input: z.object({
    limit: z.number().int().optional(),
    offset: z.number().int().optional(),
  }),
 
  output: z.array(z.object({
    id: z.string(),
    title: z.string(),
  })),
 
  handler: async (input) => {
    return await db.posts.find(input);
  },
 
  graphql: { type: 'query' },
};

Query:

query {
  listPosts(limit: 10, offset: 0) {
    id
    title
  }
}

Nested Queries

const getUserWithPostsOperation = {
  name: 'getUser',
 
  input: z.object({
    id: z.string(),
  }),
 
  output: z.object({
    id: z.string(),
    name: z.string(),
    posts: z.array(z.object({
      id: z.string(),
      title: z.string(),
    })),
  }),
 
  handler: async (input) => {
    const user = await db.users.findById(input.id);
    const posts = await db.posts.findByUserId(input.id);
    return { ...user, posts };
  },
 
  graphql: { type: 'query' },
};

Query:

query {
  getUser(id: "123") {
    name
    posts {
      title
    }
  }
}

Mutations

Create Mutation

const createUserOperation = {
  name: 'createUser',
 
  input: z.object({
    name: z.string().min(1),
    email: z.string().email(),
  }),
 
  output: z.object({
    id: z.string(),
    name: z.string(),
    email: z.string(),
  }),
 
  handler: async (input) => {
    return await db.users.create(input);
  },
 
  graphql: { type: 'mutation' },
};

Mutation:

mutation {
  createUser(name: "John", email: "john@example.com") {
    id
    name
    email
  }
}

Update Mutation

const updateUserOperation = {
  name: 'updateUser',
 
  input: z.object({
    id: z.string(),
    name: z.string().optional(),
    email: z.string().email().optional(),
  }),
 
  output: z.object({
    id: z.string(),
    name: z.string(),
    email: z.string(),
  }),
 
  handler: async (input) => {
    const { id, ...updates } = input;
    return await db.users.update(id, updates);
  },
 
  graphql: { type: 'mutation' },
};

Mutation:

mutation {
  updateUser(id: "123", name: "Jane") {
    id
    name
    email
  }
}

Delete Mutation

const deleteUserOperation = {
  name: 'deleteUser',
 
  input: z.object({
    id: z.string(),
  }),
 
  output: z.boolean(),
 
  handler: async (input) => {
    await db.users.delete(input.id);
    return true;
  },
 
  graphql: { type: 'mutation' },
};

Mutation:

mutation {
  deleteUser(id: "123")
}

Playground

Accessing Playground

Navigate to: http://localhost:3000/graphql

The playground provides:

  • Interactive query editor
  • Schema documentation
  • Query history
  • Variable editor

Example Session

# Query users
query GetUsers {
  listUsers {
    id
    name
    email
  }
}
 
# Create user
mutation CreateUser {
  createUser(name: "John", email: "john@example.com") {
    id
    name
  }
}
 
# With variables
query GetUser($id: String!) {
  getUser(id: $id) {
    name
    email
  }
}
 
# Variables pane:
{
  "id": "123"
}

Complete Example

import { createApp } from 'ramapi';
import { z } from 'zod';
 
const app = createApp({
  protocols: {
    graphql: {
      path: '/graphql',
      playground: true,
    },
  },
});
 
// Define operations
const operations = [
  // Query: List users
  {
    name: 'listUsers',
    output: z.array(z.object({
      id: z.string(),
      name: z.string(),
      email: z.string(),
    })),
    handler: async () => await db.users.findAll(),
    graphql: { type: 'query' },
  },
 
  // Query: Get user
  {
    name: 'getUser',
    input: z.object({ id: z.string() }),
    output: z.object({
      id: z.string(),
      name: z.string(),
      email: z.string(),
    }),
    handler: async (input) => await db.users.findById(input.id),
    graphql: { type: 'query' },
  },
 
  // Mutation: Create user
  {
    name: 'createUser',
    input: z.object({
      name: z.string(),
      email: z.string().email(),
    }),
    output: z.object({
      id: z.string(),
      name: z.string(),
      email: z.string(),
    }),
    handler: async (input) => await db.users.create(input),
    graphql: { type: 'mutation' },
  },
 
  // Mutation: Update user
  {
    name: 'updateUser',
    input: z.object({
      id: z.string(),
      name: z.string().optional(),
      email: z.string().optional(),
    }),
    output: z.object({
      id: z.string(),
      name: z.string(),
      email: z.string(),
    }),
    handler: async (input) => {
      const { id, ...updates } = input;
      return await db.users.update(id, updates);
    },
    graphql: { type: 'mutation' },
  },
];
 
// Register operations
const protocolManager = app.getProtocolManager();
operations.forEach(op => protocolManager?.registerOperation(op));
 
await app.listen(3000);
console.log('GraphQL Playground: http://localhost:3000/graphql');

Next Steps


Need help? Check the Troubleshooting Guide or GitHub Issues (opens in a new tab).