LogoRevali

Response Headers

Headers Revali sets automatically, and setting your own with @SetHeader or the Headers object

Revali sets content headers (Content-Type, Content-Length, ...) from the response body. Add your own with @SetHeader(name, value) when the value is fixed, or through the response Headers object when it is computed per request.

Minimal example#

routes/controllers/data_controller.dart
import 'package:revali_router/revali_router.dart';

@Controller('data')
class DataController {
  const DataController();

  @SetHeader('Cache-Control', 'max-age=3600')
  @Get()
  String cached() => 'cached';

  @Get('traced')
  String traced(Headers headers) {
    headers.set('X-Trace-Id', 'abc123');
    return 'traced';
  }
}
curl -i http://localhost:8080/api/data
# cache-control: max-age=3600
# content-type: application/json
# {"data":"cached"}

curl -i http://localhost:8080/api/data/traced
# x-trace-id: abc123
# {"data":"traced"}

Automatic headers#

HeaderSet when
Content-Type Always, from the body: application/json , text/plain ( StringContent ), application/octet-stream (bytes, streams), the file's type for File , the given type for MemoryFile . See Response .
Content-Length Body length when known. Otherwise the response is sent with Transfer-Encoding: chunked.
Content-Disposition attachment; filename="..." for File and MemoryFile bodies.
Last-Modified, Accept-RangesFile bodies.
DateAlways, unless you set it.
Content-Encoding, Vary When compression applies.
Access-Control-*, Allow CORS headers (Access control).

Setting headers#

MethodScopeUse when
@SetHeader(name, value) App class, controller class, or endpoint method The value is constant.
Headers / ResponseHeaders endpoint parameter One endpoint The value is computed in the handler.
response.headers in a lifecycle component Wherever the component is applied The value is computed and shared by many endpoints.
class SecurityHeaders implements LifecycleComponent {
  const SecurityHeaders();

  MiddlewareResult apply(Response response) {
    response.headers
      ..set('X-Content-Type-Options', 'nosniff')
      ..set('X-Frame-Options', 'DENY');

    return const MiddlewareResult.next();
  }
}

Headers methods for writing:

MethodEffect
set(name, value, {expose}) / headers[name] = value Replace the header.
add(name, value, {expose})Add another value.
remove(name)Remove the header.
addAll(map)Set several headers.
mimeType , contentType , contentLength , filename , lastModified setters Typed shortcuts for common headers.

Header names are case-insensitive.

Exposing headers to browser JavaScript#

Cross-origin fetch/XHR code can only read a few response headers unless the others are listed in Access-Control-Expose-Headers. Pass expose: true to add the header there too:

@Get('item')
String item(Headers headers) {
  headers.set('X-Request-Id', 'req-1', expose: true);
  return 'ok';
}

The response then carries X-Request-Id: req-1 and Access-Control-Expose-Headers: X-Request-Id.

CallEffect on Access-Control-Expose-Headers
set(name, value, expose: true)Adds name.
set(name, value, expose: false) Removes name (the header value is still set).
set(name, value)Unchanged.
expose(name) / unexpose(name) Add / remove without touching the value.

@SetHeader has no expose option; use the Headers object.

Related: Cookies · Status code · Request headers