Migrate from 1.x to 2.x
This guide outlines the steps required to migrate your application to the latest version of Serinus. The framework has undergone significant refactoring to improve type safety, consistency, and modularity.
Provider & Module Refactoring
Rename DeferredProvider to ComposedProvider
The way we handle providers that depend on other providers has changed to a "composition" model.
- Update
Provider.deferredtoProvider.composed. - Update
DeferredProvidertoComposedProvider. - Update the factory function to use
CompositionContextand thecontext.use<T>()syntax.
class AppModule extends Module {
AppModule(): super(
providers: [
Provider.deferred(
(AppProvider appProvider) => SecondProvider(appProvider),
inject: [AppProvider],
type: SecondProvider
),
Provider.composed<SecondProvider>(
(CompositionContext context) async => SecondProvider(context.use<AppProvider>()),
inject: [AppProvider],
)
]
)
}Global Scoping
Global registration has moved from the Provider level to the Module level.
- Remove
isGlobalfrom yourProviderclasses. - Add
isGlobal => trueto theModulethat should export its providers globally.
class TestProvider extends Provider {
@override
bool get isGlobal => true;
}
class TestModule extends Module {
@override
bool get isGlobal => true;
}Asyncrhonous Modules
The registerAsync method must now explicitly return a DynamicModule.
class AppModule extends Module {
Future<DynamicModule> registerAsync() async {
return DynamicModule(
imports: [
// other modules
],
providers: [
// providers
]
);
}
}Controllers & Routing
Required Path Parameters
Controllers now require an explicit path in the constructor.
- Old:
super(path: '/') - New:
super('/')
class AppController extends Controller {
AppController() : super(path: '/');
AppController() : super('/');
}Strict handler definitions
Route handlers must now follow a strict signature: Future<T> Function(RequestContext context). This ensures better type safety and consistency.
- Ensure all handlers are
asyncand return aFuture. - Custom parameters (like path params) can no longer be passed directly into the handler function; they must be accessed via
context.
Route hooks
Routes no longer have lifecycle hooks. If you need route-specific logic, add hooks directly to the route's hooks list.
Request & Response handling
Unified Execution Context
Middlewares, Pipes and Hooks now use ExecutionContext instead of raw request/response objects. This allows the same logic to work across HTTP, WebSockets, and other protocols.
- Use
context.argumentsHostto access the specific protocol host (e.g.,HttpArgumentsHost).
Body Parsing Rework
The ParseSchema pipe and schema parameters in routes have been removed.
on(
Route.post(
'/data',
pipes: {}
),
schema: AcanthisParseSchema(),
(context) async {
return data;
}
);- Use the new
context.bodyAs<T>()method to parse bodies into a specific typeT. - Standardize on using Pipes for any custom validation logic.
on(Route.post('/json'), (context) async {
final body = context.bodyAs<Map<String, dynamic>>(); // to parse the body as JSON
return body;
});
on(Route.post('/text'), (context) async {
final body = context.bodyAs<String>(); // to parse the body as plain text
return body;
});
on(Route.post('/form'), (context) async {
final body = context.bodyAs<FormData>(); // to parse the body as form data
return body;
});Header
- Headers: now handled via a dedicated
Headersclass for better structure. - Status Codes: POST requests now return
201 Createdby default instead of200 OK.
Middleware & Hooks
Fluent Middleware API
Middlewares are no longer registered in the Module constructor.
- Implement the
configure(MiddlewareConsumer consumer)method in your module. - Use the fluent
.apply().forRoutes()syntax.
class AppModule extends Module {
AppModule() : super(
middlewares: [
LogMiddleware(
routes: ['*']
)
]
);
void configure(MiddlewareConsumer consumer) {
consumer.apply(LogMiddleware()).forRoutes([
RouteInfo(
'*'
)
]);
}
}Hook Separation
The OnRequestResponse mixin has been split.
- Use
OnRequestandOnResponseseparately. - Update method signatures to use
ExecutionContextandWrappedResponsewhere applicable.
Future<void> onRequest(Request request, InternalResponse response);
Future<void> onRequest(ExecutionContext context);
Future<void> onResponse(Request request, dynamic data, ResponseProperties properties);
Future<void> onResponse(ExecutionContext context, WrappedResponse data);
Future<void> afterHandle(RequestContext context, dynamic response);
Future<void> afterHandle(ExecutionContext context, WrappedResponse response);
Future<void> beforeHandle(RequestContext context);
Future<void> beforeHandle(ExecutionContext context);Utilities & Services
Logger Refactor
The logging API has been updated for better flexibility.
- Rename
loggerServicetologger. - Change
loggingLevel(single value) tologLevels(aSet<LogLevel>).
void main(List<String> arguments) async {
final application = await serinus.createApplication(
entrypoint: AppModule(),
host: InternetAddress.anyIPv4.address,
loggerService: null,
loggingLevel: LogLevel.info
logger: ConsoleLogger(prefix: 'Serinus New Logger'),
logLevels: {LogLevel.info}
);
await application.serve();
}Exceptions
The message parameter in SerinusException is now a required positional argument rather than a named one.
- New:
throw BadGatewayException('Message').
throw BadGatewayException(message: 'Failed to retrieve template');
throw BadGatewayException('Failed to retrieve template');View Engine Simplification
ViewandViewStringare merged into oneViewclass.- Use
View.template()orView.string()constructors. - View Engines now only need to implement a single
rendermethod.
class MustacheViewEngine extends ViewEngine {
Future<String> render(View view) async {}
Future<String> renderString(ViewString view) async {}
}
// Usage in controller
class AppController extends Controller {
AppController() : super('/') {
on(Route.get('/template'), (context) async {
return View('template', {});
return View.template('templateName', {});
});
on(Route.get('/string'), (context) async {
return View('string', {});
return View.string('string', {});
});
}
}Deprecations & Removals
- Tracer API: Removed (to be reintroduced later).
- ModelProvider: Now uses
Stringkeys instead ofTypefor registration. - ResponseProperties: Renamed to
ResponseContext.
