Sirius β‘ β A Lightweight Dart Backend Framework
Sirius is a lightweight, expressive, and fast HTTP & WebSocket backend framework built entirely with Dart.
It features powerful routing, composable wrapper middlewares, validation, and lifecycle hooks.
π Features
- β‘ Simple, expressive routing (
GET,POST,PUT,PATCH,DELETE) - π§± Wrapper middleware via
.wrap()for lifecycle-level logic (e.g. logging, timing) - π Grouped routes for modular structure
- π Validation with nested object and list support
- π WebSocket routing support
- π‘ Built on top of
dart:iofor raw performance
π¦ Installation
dependencies:
sirius_backend: ^2.4.2
Then run:
dart pub get
π οΈ Basic Usage
import 'package:sirius_backend/sirius_backend.dart';
void main() async {
final sirius = Sirius();
sirius.get('/hello', (req) async {
return Response.send({'message': 'Hello from Sirius!'});
});
await sirius.start(port: 3000);
}
π Routing
sirius.get('/users', userController.getUsersHandler);
sirius.post('/users', userController.createUserHandler);
sirius.put('/users/:id', userController.updateUserHandler);
sirius.delete('/users/:id', userController.deleteUserHandler);
Grouped Routes
sirius.group('/api', (router) {
router.get('/status', (req) async => Response.send({'ok': true}));
});
π Wrapper Middleware (NEW in 2.0)
Wrappers allow full control over the request lifecycle for tasks like logging, auth, timing, etc.
class TimerWrapper extends Wrapper {
@override
FutureOr<Response?> handle(Request request, FutureOr<Response?> Function() nextHandler) async {
final start = DateTime.now();
final response = await nextHandler();
final end = DateTime.now();
print("Duration: ${end.difference(start)}");
return response;
}
}
Register wrapper globally:
sirius.wrap(TimerWrapper().handle);
Or for a single route:
sirius.get('/dashboard', controller.dashboardHandler, wrappers: [TimerWrapper().handle]);
π§Ύ Request Object
final id = request.pathVariable('id');
final name = request.jsonValue('name');
final headers = request.headers;
final method = request.method;
final userData = request.getContextData; // Passed via middleware
π§ Request Lifecycle Flow
Incoming Request
βββ Global Wrapper (Entry)
βββ Route Wrapper (Entry)
βββ Route Handler
βββ Route Wrapper (Exit)
βββ Global Wrapper (Exit)
βββ Response Sent
1οΈβ£ Incoming Request
β
2οΈβ£ Global Wrapper (Entry)
β
3οΈβ£ Route Wrapper (Entry)
β
4οΈβ£ Route Handler (your main logic)
β
5οΈβ£ Route Wrapper (Exit)
β
6οΈβ£ Global Wrapper (Exit)
β
7οΈβ£ π’ Response Sent
β Validation
Basic Validation
final validator = Validator(request, {
'name': ValidationRules(required: required(message: "Name is required")),
'age': ValidationRules(minNumber: minNumber(18)),
});
if (!validator.validate()) {
return Response.send(validator.getAllErrors, statusCode: 400);
}
Nested Object Validation
'address': ValidationRules(
dataType: dataType(DataTypes.MAP),
childMap: {
'street': ValidationRules(required: required()),
'zip': ValidationRules(minLength: minLength(5)),
},
)
List Validation
'items': ValidationRules(
dataType: dataType(DataTypes.LIST),
childList: [
ValidationRules(required: required(message: "Item is required")),
],
)
Validate Every List Element with Same Rules
'ids': ValidationRules(
dataType: dataType(DataTypes.LIST),
childList: ValidationRules(
required: required(),
dataType: dataType(DataTypes.NUMBER),
).forEachElement(),
)
π€ Response API
return Response.send({"message": "Success"});
return Response.send({"error": "Unauthorized"}, statusCode: 401);
return Response.sendJson({"error": "Unauthorized"}, statusCode: 401);
You can also override headers:
return Response.send({'ok': true}, overrideHeaders: (headers) {
headers.set('x-powered-by', 'Sirius');
});
π WebSocket Support
sirius.webSocket('/chat', (request) async {
final socketConn = await request.upgradeToWebSocket();
final connId = socketConn.getId;
print("Client connected: $connId");
// Respond to a custom event
socketConn.onEvent("ping", (data) {
print("Received ping: $data");
socketConn.sendEvent("pong", {
"message": "Pong received!",
"echo": data,
});
});
// Listen to raw messages (not event-based)
socketConn.onData((msg) {
print("Raw message: $msg");
socketConn.sendData("Echo: $msg");
});
// Handle disconnection
socketConn.onDisconnect(() {
print("Client disconnected: $connId");
});
});
π§± Advanced Usage: Route Composition
sirius.get(
'/secure-data',
secureDataHandler,
wrappers: [
TimerWrapper().handle,
AuthWrapper().handle,
],
);
π License
MIT License β free for commercial and personal use.
π€ Contributing
Pull requests, issues, and feature suggestions are welcome. Letβs make backend development in Dart delightful!
Libraries
- inbuilds/cors_handler
- inbuilds/logger_handler
- sirius_backend
- A powerfull and lightweigh dart backend framework