Loading...
Loading...
Serverpod web server (Relic) — REST APIs, webhooks, middleware, static files, server-rendered HTML, SPAs, Flutter web. Use when adding raw HTTP routes, serving web pages or web apps, or intercepting requests. Not for RPC endpoints called from the generated client — use serverpod-endpoints for those.
npx skill4agent add serverpod/serverpod serverpod-webserverSessionwebServerRoutehandleCall(Session, Request)pod.start()class HelloRoute extends Route {
Future<Result> handleCall(Session session, Request request) async {
return Response.ok(
body: Body.fromString(
jsonEncode({'message': 'Hello'}),
mimeType: MimeType.json,
),
);
}
}
pod.webServer.addRoute(HelloRoute(), '/api/hello');Sessionrequest.methodclass UserRoute extends Route {
UserRoute() : super(methods: {Method.get, Method.post, Method.delete});
Future<Result> handleCall(Session session, Request request) async {
if (request.method == Method.post) {
final data = jsonDecode(await request.readAsString());
// ...
return Response(201);
}
// ...
}
}pod.webServer.addRoute(UserRoute(), '/api/users/:id');
pod.webServer.addRoute(route, '/:userId/posts/:postId');class UserRoute extends Route {
static const _idParam = IntPathParam(#id);
Future<Result> handleCall(Session session, Request request) async {
int userId = request.pathParameters.get(_idParam);
// ...
}
}request.pathParameters.raw[#id]IntQueryParam('page')request.queryParameters.get(...)request.queryParameters.raw['query']pod.webServer.addRoute(route, '/item/*'); // One segment: /item/foo
pod.webServer.addRoute(route, '/item/**'); // Tail-match: /item/foo/bar/baz**request.remainingPathfinal userAgent = request.headers.userAgent;
final contentLength = request.headers.contentLength;
final auth = request.headers.authorization;
final apiKey = request.headers['X-API-Key']?.first;
final body = await request.readAsString(); // JSON, form data
final stream = request.read(); // Stream for large uploadsResponseoknoContentnotModifiedmovedPermanentlyfoundseeOtherbadRequestunauthorizedforbiddennotFoundnotImplementedinternalServerErrorResponse(201)Body.fromString(content, mimeType: MimeType.json)Body.fromData(...)Body.fromDataStream(...)pod.webServer.fallbackRoute = NotFoundRoute();injectIn()class UserCrudModule extends Route {
void injectIn(RelicRouter router) {
router
..get('/', _list)
..get('/:id', _get);
}
static const _idParam = IntPathParam(#id);
Future<Result> _list(Request request) async {
final session = await request.session;
final users = await User.db.find(session);
return Response.ok(
body: Body.fromString(jsonEncode(users.map((u) => u.toJson()).toList()),
mimeType: MimeType.json),
);
}
Future<Result> _get(Request request) async {
final session = await request.session;
final user = await User.db.findById(session, request.pathParameters.get(_idParam));
if (user == null) return Response.notFound();
return Response.ok(
body: Body.fromString(jsonEncode(user.toJson()), mimeType: MimeType.json),
);
}
}
pod.webServer.addRoute(UserCrudModule(), '/api/users');
// Creates GET /api/users and GET /api/users/:idinjectInRequestSessionawait request.sessionHandler apiKeyMiddleware(Handler next) {
return (Request request) async {
final apiKey = request.headers['X-API-Key']?.firstOrNull;
if (apiKey == null || !await isValidApiKey(apiKey)) {
return Response.unauthorized(body: Body.fromString('API key required'));
}
return await next(request);
};
}
pod.webServer.addMiddleware(apiKeyMiddleware, '/api');pod.webServer.addMiddleware(rateLimitMiddleware, '/api/users'); // Inner (last before handler)
pod.webServer.addMiddleware(apiKeyMiddleware, '/api'); // Outer (first)/api/users/listfinal _tenantProperty = ContextProperty<String>('tenant');
extension TenantEx on Request {
String get tenant => _tenantProperty.get(this);
}
Handler tenantMiddleware(Handler next) {
return (Request request) async {
final session = await request.session;
final tenant = await extractTenant(session, request.headers.host);
if (tenant == null) return Response.notFound();
_tenantProperty[request] = tenant;
return await next(request);
};
}
// In route:
final tenant = request.tenant;pod.webServer.addMiddleware(mw, '/api', host: 'api.example.com')Hostpod.webServer.addRoute(ApiRoute(), '/v1'); // ApiRoute has host: 'api.example.com'
pod.webServer.addRoute(SpaRoute(webDir, fallback: index, host: 'www.example.com'), '/');
pod.webServer.addRoute(HealthRoute(), '/health'); // All hosts (default)hostRouteStaticRouteSpaRouteFlutterRoutereferences/static-files.mdStaticRoutereferences/spa-and-flutter-web.mdSpaRouteFlutterRoutereferences/server-rendered-html.mdWidgetRoute