Baeta
Schema first without the hassle
Schema First
Define your API contract upfront with a clear, schema-first approach that ensures consistency and maintainability.
Modular By Design
Build your API piece by piece. Baeta's modular architecture lets you organize code into small, maintainable modules.
Type Safe
Focus on your logic while Baeta handles type safety with automatic code generation and TypeScript integration.
Flexible & Extensible
Use only what you need. Add powerful features through official extensions when your API grows.
Define Your API Contract
Start with a clear, readable schema that serves as your API contract. Baeta's schema-first approach lets you focus on designing the perfect API before diving into implementation details.
type User {
id: ID!
name: String!
email: String!
age: Int
}
input UserWhereUnique {
id: ID
email: String
}
type Query {
user(where: UserWhereUnique!): User!
users: [User!]!
}
Write Clean, Type-Safe Resolvers
Focus purely on your business logic while Baeta handles all type definitions and safety. No more type gymnastics or complex and nested resolver patterns - just clean, straightforward code.
import { getUserModule } from "./typedef";
const { Query } = getUserModule();
Query.user(({ args }) => {
return dataSource.user.find(args.where);
});
Query.users(() => {
return dataSource.user.findMany();
});
Compose and Extend
Build your API like building blocks. Baeta's modular architecture lets you split your schema into small, focused pieces that are easy to maintain. Extend existing types seamlessly as your API grows.
type Photo {
id: ID!
url: String!
description: String!
postedBy: User!
}
input PhotoCreateData {
url: String! @trim
description: String!
userId: ID!
}
extend type User {
photos: [Photo!]!
}
Scope-Based Authorization
Secure your API with granular, scope-based authorization. Define permissions directly in your schema and let Baeta handle the rest.
const { Query, Mutation } = getUserModule();
Query.users.$auth({
$or: {
isPublic: true,
isLoggedIn: true,
},
});
Simple, Effective Caching
Add automatic caching to your queries with minimal setup. Update cached data easily and predictably when mutations occur.
import { getUserModule } from './typedef.ts';
const { User, Query } = getUserModule();
export const userCache = User.$createCache();
Query.user.$useCache(userCache);
Query.users.$useCache(userCache);
Mutation.updateUser.$use(async (params, next) => {
const user = await next();
await userCache.save(user);
return user;
});
Powerful Custom Directives
Add custom behavior exactly where you need it. Create your own directives for validation, transformation, or any custom logic. Baeta makes it simple to apply complex behaviors declaratively in your schema.
const trimDirective = createInputDirective({
name: "trim",
target: "scalar",
resolve: ({ getValue, setValue }) => {
const value = getValue();
if (typeof value === "string") {
setValue(value.trim());
}
},
});