A Declarative, Discoverable, and AI-Native API Protocol for TypeScript
RQL (Resource Query Language) is a lightweight alternative to GraphQL designed for modern applications and AI agents. Define your API contracts once, get automatic schema discovery, type-safe resolvers, and efficient relation batching.
- π― Contract-Driven - Define what data can be fetched, not how
- π€ AI-Native - Self-documenting schemas for LLM tool use
- π Secure by Default - Only exposed fields can be queried
- β‘ Batched Relations - Automatic N+1 prevention
- π¦ Minimal Dependencies - Just Zod for validation
- π§ Framework Agnostic - Core engine works anywhere
# Using bun
bun add @rql-kit/core @rql-kit/express zod
# Using npm
npm install @rql-kit/core @rql-kit/express zod// contracts/products.ts
import { defineContract } from '@rql-kit/core';
import { z } from 'zod';
export const getProductContract = defineContract({
name: 'getProduct',
description: 'Fetches a product by ID',
type: 'GET',
params: z.object({
productId: z.string(),
}),
selectable: {
id: { type: 'string', description: 'Product ID' },
name: { type: 'string', description: 'Product name' },
price: { type: 'number', description: 'Price in cents' },
},
async resolve({ params }) {
// Your data fetching logic
return { id: params.productId, name: 'Laptop', price: 99900 };
},
});// server.ts
import express from 'express';
import { createRQLMiddleware } from '@rql-kit/express';
import { getProductContract } from './contracts/products';
const app = express();
app.use(express.json());
app.use('/api/rql', createRQLMiddleware({
contracts: [getProductContract],
}));
app.listen(3000);curl -X POST http://localhost:3000/api/rql \
-H "Content-Type: application/json" \
-d '{
"product": {
"contract": "getProduct",
"params": { "productId": "prod_123" },
"select": { "id": true, "name": true, "price": true }
}
}'Response:
{
"data": {
"product": { "id": "prod_123", "name": "Laptop", "price": 99900 }
},
"errors": []
}Define relations between contracts with automatic batching:
const getProductContract = defineContract({
// ...
selectable: {
id: { type: 'string', description: 'ID' },
manufacturerId: { type: 'string', description: 'Manufacturer ID' },
manufacturer: {
type: 'Manufacturer',
description: 'Product manufacturer',
relation: {
contractName: 'getManufacturerById',
params: { manufacturerId: '{{ parent.manufacturerId }}' },
// Enable batching - 50 products = 1 batch call, not 50 calls
batch: { param: 'manufacturerId', as: 'manufacturerIds' },
},
},
},
});Reference data from other queries in the same request:
{
"mainProduct": {
"contract": "getProduct",
"params": { "productId": "prod_123" },
"select": { "id": true, "categoryId": true }
},
"relatedProducts": {
"contract": "getProductsByCategory",
"params": {
"categoryId": "{{ data.mainProduct.categoryId }}",
"excludeId": "{{ data.mainProduct.id }}"
},
"select": { "id": true, "name": true }
}
}# Get all groups and ungrouped contracts
GET /api/rql/schema
# Get all contracts in a group
GET /api/rql/schema/Products
# Get flat list of all contracts
GET /api/rql/schema/all
# Pretty print and/or raw Zod schemas
GET /api/rql/schema?pretty=1&raw=1| Feature | RQL | GraphQL |
|---|---|---|
| Learning curve | Minutes | Hours/Days |
| Schema definition | TypeScript + Zod | SDL |
| Code generation | Not needed | Often required |
| Bundle size | ~20KB | 50KB+ |
| N+1 prevention | Built-in batching | DataLoader needed |
| AI compatibility | Native JSON | Needs parsing |
RQL is ideal when you want GraphQL-like flexibility without the complexity.
| Package | Description |
|---|---|
@rql-kit/core |
Core types, engine, and server factory |
@rql-kit/express |
Express middleware adapter |
- β Core engine with validation, relations, templating
- β Express middleware adapter
- β Schema discovery endpoints
- β
Cross-query
{{ data.x.y }}templating - β Budget limits (depth, fields, queries)
- Relation batching - automatic N+1 prevention via
batchmetadata - MCP adapter - expose RQL as Model Context Protocol tools
- Caching layer - configurable response caching
- OpenAPI export - generate OpenAPI spec from contracts
- Subscriptions - real-time data updates
- Rate limiting - per-contract rate limits
- Metrics/tracing - OpenTelemetry integration
- React Query integration - typed client hooks
- Wire Protocol Specification
- Security Considerations (coming soon)
MIT Β© 2024