🔧 Nodeblocks Backend SDK
The Nodeblocks Backend SDK is a collection of composable utilities for building robust, type-safe REST APIs in minutes.
It is designed around functional composition & dependency injection so that every layer can be tested and reused in isolation.
🧠 Core Philosophy
The Nodeblocks Backend SDK embraces a functional, compositional approach to backend services. Instead of relying on large, opinionated frameworks, you construct your application by composing small, independent functions and modules.
At the heart of the SDK is the idea that complex systems can be built from simple, pure functions. Rather than creating large classes or objects that hold a lot of state and logic, you define small, focused functions and compose them into more complex ones.
This approach provides:
- Modularity: Each piece of your application is small and self-contained, making it easy to understand, test, and reuse.
- Declarative Style: You declare what your service is, rather than specifying how it should be built step-by-step.
- Predictability: With a foundation in functional principles, the behavior of your system is more predictable and easier to reason about.
🏗️ Layered Architecture
The Nodeblocks Backend SDK follows a clear layered architecture where each layer has a specific responsibility and can be composed independently. This separation of concerns makes your code more maintainable, testable, and reusable.
-
Schema – JSON-Schema definitions for request validation. Schemas define the shape of your data and validate incoming requests.
-
Handler – The async business logic (e.g.
createUser
). Handlers contain your core application logic and are pure functions that take validated input and return results or errors. -
Route – HTTP method + path + handler + validators. Routes define your API endpoints and specify which HTTP methods they accept, what path they respond to, and how validation should be applied.
-
Feature – Composition of a schema + route (or multiple routes). Features bundle related functionality together, combining validation rules with their corresponding endpoints.
-
Service – Groups related features and wires external deps (e.g. Mongo
Collection
). Services are the top-level containers that combine multiple features and inject dependencies like database connections.
Architecture diagram
Request Flow
Here's how a typical request flows through the layered architecture:
Request → Route → Handler → DB / External API → Terminator → Response
Because each unit is a pure function you can swap, decorate or extend any layer without touching the others.
🔧 Core Concepts
Now that you understand the layered architecture, let's dive into the key concepts you'll work with when building applications using the Nodeblocks Backend SDK. These concepts form the building blocks of your API and understanding them will help you create maintainable, scalable backend services.
Services
A service is a composable piece of your application that provides HTTP endpoints. It's implemented as Express middleware that you can mount on your Express application. You create a service using the defService
function, which takes a composed set of features and configurations and returns an Express router ready to be used as middleware.
Composition
Composition is the central pattern in the SDK. The compose
function allows you to chain together different parts of your application from left to right (unlike traditional function composition which goes right to left). You start with simple functions and progressively build them up into more complex ones, with each function being applied in the order they appear in the composition chain.
// Compose multiple features into a single service definition
const serviceDefinition = compose(feature1, feature2, feature3);
// Create the service from the composed definition
const service = defService(partial(serviceDefinition, [...]));
Primitives
Primitives are lower level helper functions that help you build blocks for your service. Two of the most commonly used primitives you are withSchema
and withRoute
.
withSchema
The withSchema
primitive defines a JSON Schema for data validation. What makes it powerful is how it interacts with withRoute
- when you compose withSchema
, it sets up validation for the next route automatically.
// Define a reusable schema
const userSchema: SchemaDefinition = {
$schema: 'http://json-schema.org/draft-07/schema#',
additionalProperties: false,
properties: {
email: { type: 'string' },
name: { type: 'string' },
status: { type: 'string' },
},
type: 'object',
};
export const createUserSchema = withSchema({
requestBody: {
content: {
'application/json': {
schema: {
...userSchema,
required: ['email', 'name', 'status'],
},
},
},
required: true,
},
});
// Apply the same schema to multiple routes
const createUserFeature = compose(createUserSchema, createUserRoute);
const updateUserFeature = compose(createUserSchema, updateUserRoute);
withRoute
The withRoute
primitive defines HTTP and WebSocket endpoints. It takes a configuration object that specifies the protocol, HTTP method (for HTTP routes), path, validators and a handler function.
const createUserRoute = withRoute({
handler: compose(
withLogging(createUser),
flatMapAsync(withLogging(getUserById)),
lift(withLogging(normalizeUserTerminator))
),
method: 'POST',
path: '/users',
validators: [verifyAuthentication(getBearerTokenInfo)],
});
Features
A feature is a logical grouping of related functionality, typically consisting of one or more routes and their associated schemas. You create a feature by composing its parts.
// Create a complete feature by composing schema and route
export const userFeature = compose(createUserSchema, createUserRoute);
⚡ Quickstart
Looking to spin up your first API quickly? Follow the step-by-step Quickstart tutorial which walks you through installation, server bootstrap and testing your first request.
Open the Quickstart tutorial →
📑 Available Documentation
How-To Guides
Step-by-step tutorials that walk you through common development tasks and advanced customization scenarios.
- Create a Custom Service → – Build your own service from scratch
- Create a WebSocket Service → – Build real-time WebSocket services with RxJS and MongoDB change streams
- Create a Custom Datastore → – Implement your own data persistence layer
- Create a Composite Service → – Combine multiple services into one
Components
In-depth explanations of each architectural component, including API references, usage patterns, and best practices.
- Service → – High-level service architecture
- Schema → – Data validation and TypeScript types
- Handler → – Business logic functions
- Route → – HTTP endpoint definitions
- Feature → – Composed schemas + routes
- Composition Utilities → – Handler composition tools
- Error Handling → – Result types and error patterns
Built-in Services
Ready-to-use services that provide common functionality out of the box, with full customization options.
- Authentication Service → – Complete authentication and authorization system
- User Service → – Complete user management
- Organization Service → – Multi-tenant organizations
- Product Service → – Product catalog management
- Order Service → – Order processing and management
- Category Service → – Product categorization
- Attribute Service → – Dynamic attribute management
- Chat Service → – Real-time messaging and communication with channels, subscriptions, and messages
🙌 Contributing
Found a bug or have an idea? Open an issue or PR on GitHub – contributions are welcome.