Conduit HTTP Snippets

Hello, World

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router.route("/hello_world").linkFunction((request) async {
7
return Response.ok("Hello, world!")
8
..contentType = ContentType.TEXT;
9
});
10
11
return router;
12
}
13
}
Copied!

Route Variables

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router.route("/variable/[:variable]").linkFunction((request) async {
7
return Response.ok({
8
"method": request.raw.method,
9
"path": request.path.variables["variable"] ?? "not specified"
10
});
11
});
12
13
return router;
14
}
15
}
Copied!

Grouping Routes and Binding Path Variables

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router
7
.route("/users/[:id]")
8
.link(() => MyController());
9
10
return router;
11
}
12
}
13
14
class MyController extends ResourceController {
15
final List<String> things = ['thing1', 'thing2'];
16
17
@Operation.get()
18
Future<Response> getThings() async {
19
return Response.ok(things);
20
}
21
22
@Operation.get('id')
23
Future<Response> getThing(@Bind.path('id') int id) async {
24
if (id < 0 || id >= things.length) {
25
return Response.notFound();
26
}
27
return Response.ok(things[id]);
28
}
29
}
Copied!

Custom Middleware

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router
7
.route("/rate_limit")
8
.link(() => RateLimiter())
9
.linkFunction((req) async => Response.ok({
10
"requests_remaining": req.attachments["remaining"]
11
}));
12
13
return router;
14
}
15
}
16
17
class RateLimiter extends RequestController {
18
@override
19
Future<RequestOrResponse> handle(Request request) async {
20
final apiKey = request.raw.headers.value("x-apikey");
21
final requestsRemaining = await remainingRequestsForAPIKey(apiKey);
22
if (requestsRemaining <= 0) {
23
return Response(429, null, null);
24
}
25
26
request.addResponseModifier((r) {
27
r.headers["x-remaining-requests"] = requestsRemaining;
28
});
29
30
return request;
31
}
32
}
Copied!

Application-Wide CORS Allowed Origins

1
class AppChannel extends ApplicationChannel {
2
@override
3
Future prepare() async {
4
// All controllers will use this policy by default
5
CORSPolicy.defaultPolicy.allowedOrigins = ["https://mywebsite.com"];
6
}
7
8
@override
9
Controller get entryPoint {
10
final router = Router();
11
12
router.route("/things").linkFunction((request) async {
13
return Response.ok(["Widget", "Doodad", "Transformer"]);
14
});
15
16
return router;
17
}
18
}
Copied!

Serve Files and Set Cache-Control Headers

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router.route("/files/*").link(() =>
7
FileController("web")
8
..addCachePolicy(new CachePolicy(expirationFromNow: new Duration(days: 365)),
9
(path) => path.endsWith(".js") || path.endsWith(".css"))
10
);
11
12
return router;
13
}
14
}
Copied!

Streaming Responses (Server Side Events with text/event-stream)

1
class AppChannel extends ApplicationChannel {
2
final StreamController<String> controller = new StreamController<String>();
3
4
@override
5
Future prepare() async {
6
var count = 0;
7
Timer.periodic(new Duration(seconds: 1), (_) {
8
count ++;
9
controller.add("This server has been up for $count seconds\n");
10
});
11
}
12
13
@override
14
Controller get entryPoint {
15
final router = new Router();
16
17
router.route("/stream").linkFunction((req) async {
18
return Response.ok(controller.stream)
19
..bufferOutput = false
20
..contentType = new ContentType(
21
"text", "event-stream", charset: "utf-8");
22
});
23
24
return router;
25
}
26
}
Copied!

A websocket server

1
class AppChannel extends ApplicationChannel {
2
List<WebSocket> websockets = [];
3
4
@override
5
Future prepare() async {
6
// When another isolate gets a websocket message, echo it to
7
// websockets connected on this isolate.
8
messageHub.listen(sendBytesToConnectedClients);
9
}
10
11
@override
12
Controller get entryPoint {
13
final router = Router();
14
15
// Allow websocket clients to connect to ws://host/connect
16
router.route("/connect").linkFunction((request) async {
17
var websocket = await WebSocketTransformer.upgrade(request.raw);
18
websocket.listen(echo, onDone: () {
19
websockets.remove(websocket);
20
}, cancelOnError: true);
21
websockets.add(websocket);
22
23
// Take request out of channel
24
return null;
25
});
26
27
return router;
28
}
29
30
void sendBytesToConnectedClients(List<int> bytes) {
31
websockets.forEach((ws) {
32
ws.add(bytes);
33
});
34
}
35
36
void echo(List<int> bytes) {
37
sendBytesToConnectedClients(bytes);
38
39
// Send to other isolates
40
messageHub.add(bytes);
41
}
42
}
Copied!

Setting Content-Type and Encoding a Response Body

1
class AppChannel extends ApplicationChannel {
2
final ContentType CSV = ContentType("text", "csv", charset: "utf-8");
3
4
@override
5
Future prepare() async {
6
// CsvCodec extends dart:convert.Codec
7
CodecRegistry.defaultInstance.add(CSV, new CsvCodec());
8
}
9
10
@override
11
Controller get entryPoint {
12
final router = Router();
13
14
router.route("/csv").linkFunction((req) async {
15
// These values will get converted by CsvCodec into a comma-separated string
16
return Response.ok([[1, 2, 3], ["a", "b", "c"]])
17
..contentType = CSV;
18
});
19
20
return router;
21
}
22
}
Copied!

Proxy a File From Another Server

1
class AppChannel extends ApplicationChannel {
2
@override
3
Controller get entryPoint {
4
final router = Router();
5
6
router.route("/proxy/*").linkFunction((req) async {
7
var fileURL = "https://otherserver/${req.path.remainingPath}";
8
var fileRequest = await client.getUrl(url);
9
var fileResponse = await req.close();
10
if (fileResponse.statusCode != 200) {
11
return new Response.notFound();
12
}
13
14
// A dart:io.HttpResponse is a Stream<List<int>> of its body bytes.
15
return new Response.ok(fileResponse)
16
..contentType = fileResponse.headers.contentType
17
// let the data just pass through because it has already been encoded
18
// according to content-type; applying encoding again would cause
19
// an issue
20
..encodeBody = false;
21
});
22
23
return router;
24
}
25
}
Copied!
Last modified 6mo ago