dartvel_shelf 0.7.2 copy "dartvel_shelf: ^0.7.2" to clipboard
dartvel_shelf: ^0.7.2 copied to clipboard

A Fetch-style HTTP server for Dart backed by a Rust (Axum/Tokio) runtime over FFI, with routing, middleware, streaming, request limits and TLS.

example/main.dart

// A small JSON API: path parameters, query strings, request bodies, a route
// that accepts a larger body than the rest, and errors.
//
//   dart run example/main.dart
//
//   curl http://127.0.0.1:8080/todos
//   curl -X POST -H 'content-type: application/json' \
//        -d '{"title":"write docs"}' http://127.0.0.1:8080/todos
//   curl http://127.0.0.1:8080/todos/1
//   curl 'http://127.0.0.1:8080/search?tag=a&tag=b'
//   curl http://127.0.0.1:8080/health
import 'dart:io';

import 'package:dartvel_shelf/dartvel_shelf.dart';

final _todos = <int, Map<String, Object?>>{};
var _nextId = 1;

Future<void> main() async {
  final router = Router()
    ..get('/todos', (req) async => Response.json(_todos.values.toList()))
    ..get('/todos/:id', (req) async {
      final id = int.tryParse(req.params['id']!);
      final todo = id == null ? null : _todos[id];
      if (todo == null) {
        return Response.json({'error': 'no such todo'}, status: 404);
      }
      return Response.json(todo);
    })
    ..post('/todos', (req) async {
      if (req.headers.get('content-type')?.startsWith('application/json') !=
          true) {
        return Response.json({'error': 'send JSON'}, status: 415);
      }
      // jsonDecode() hands back the raw text when the body is not valid JSON
      // rather than throwing, so check the shape before trusting it.
      final body = await req.body.jsonDecode();
      if (body is! Map || body['title'] is! String) {
        return Response.json({
          'error': 'expected {"title": "..."}',
        }, status: 400);
      }
      final todo = {'id': _nextId++, 'title': body['title'], 'done': false};
      _todos[todo['id'] as int] = todo;
      return Response.json(
        todo,
        status: 201,
        headers: Headers()..set('location', '/todos/${todo['id']}'),
      );
    })
    ..delete('/todos/:id', (req) async {
      final removed = _todos.remove(int.tryParse(req.params['id']!));
      return removed == null
          ? Response.json({'error': 'no such todo'}, status: 404)
          : Response(204);
    })
    ..get('/search', (req) async {
      // queryParameters keeps the last value of a repeated key;
      // queryParametersAll keeps every one.
      final tags = req.url.queryParametersAll['tag'] ?? const <String>[];
      return Response.json({'tags': tags});
    })
    // Every other route reads at most maxBodyBytes (1 MiB by default); this
    // one reads up to 8 MiB.
    ..post('/uploads', (req) async {
      final bytes = await req.body.bytes();
      return Response.json({'received': bytes.length});
    }, maxBodyBytes: 8 * 1024 * 1024);

  final server = await serve(
    router.call,
    host: '127.0.0.1',
    port: 8080,
    // Tells the native side about /uploads' larger limit. Without this the
    // server's own limit applies to every route.
    routeBodyLimits: router.bodyLimits,
    requestTimeout: const Duration(seconds: 30),
  );
  stdout.writeln('Listening on http://${server.host}:${server.port}');

  await ProcessSignal.sigint.watch().first;
  await server.stop();
  exit(0);
}
1
likes
0
points
414
downloads

Publisher

unverified uploader

Weekly Downloads

A Fetch-style HTTP server for Dart backed by a Rust (Axum/Tokio) runtime over FFI, with routing, middleware, streaming, request limits and TLS.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

code_assets, crypto, dartvel_core, ffi, hooks, image, meta, path

More

Packages that depend on dartvel_shelf