Skip to main content
Version: Next

Introduction

Relic is a web server framework for Dart, built by the Serverpod team. It grew out of Shelf, and it keeps Shelf's model of handlers that turn requests into responses and middleware that wraps handlers.

A Relic server is an ordinary Dart program. This one answers a GET request for / with a greeting:

A complete Relic server
import 'package:relic/relic.dart';

Future<void> main() async {
final app = RelicApp()
..get('/', (req) => Response.ok(body: Body.fromString('Hello, world!\n')));

await app.serve();
}

Run it, ask it for http://localhost:8080/, and it answers Hello, world!. The Hello world page builds on this program one step at a time.

The pieces​

The program above already shows most of what Relic is made of, and the reference pages take the pieces in turn.

A handler is a function that receives a Request and returns a result. Usually the result is a Response, but it can also upgrade the connection to a WebSocket, or take the connection over entirely. The router picks a handler by the method and the path of the request, and a path can hold parameters, wildcards and tails. Middleware wraps the handlers below a path, to log, check credentials or change responses, and context properties carry what it learns to the handler. The request gives a handler typed access to the URL, the query, the headers, the body and forms, and the response and its body decide what goes back on the wire. Headers are read and written through typed accessors, and a program can declare its own. Static files are served by a ready-made handler, hot reload applies most changes without a restart, and serving is where the address, the isolates and the adapter are chosen.

Features​

🔒 Typed

Headers and path and query parameters are read as typed values, and a header that does not parse gets a 400.

⚡ Fast

A trie-based router, with headers and URLs parsed only when they are read.

🔌 WebSockets

A handler upgrades a connection by returning a WebSocketUpgrade.

🔧 Middleware

Middleware attaches to a path in the router and wraps every route below it.

👨‍💻 Hot reload

The router is rebuilt on every hot reload, so changed handlers apply without a restart.

🚀 Tested

More than 3,000 tests, run on Linux, macOS and Windows.

How Relic differs from Shelf​

If you know Shelf, most of Relic will look familiar. These are the places where it works differently:

AreaShelfRelic
HeadersStrings in a mapTyped accessors that validate values
Routingshelf_router, which tries routes in orderA built-in router on a trie, matched segment by segment
WebSocketsThe shelf_web_socket packageBuilt in
Path parametersStrings, passed as extra handler argumentsRead from the request by symbol, with typed accessors
Static filesThe shelf_static packageStaticHandler, with cache busting and ETags
HijackingA thrown HijackExceptionA returned Hijack or WebSocketUpgrade result
Request stateA Map<String, Object> contextTyped context properties
BodyContent and encoding set separatelyOne Body that carries content, type and encoding

The Migration from Shelf page goes through each of these with code.