xserver 0.1.1 copy "xserver: ^0.1.1" to clipboard
xserver: ^0.1.1 copied to clipboard

A Dart-based web server framework.

xserver #

xserver is a Dart-based web server framework that leverages source generation for automatic handler registration, making it easier to manage and expand your web server's endpoints.

Features #

  • Automatic Handler Registration: Utilize file structure conventions to auto-register handlers.
  • Flexible Response Types: Return various response types including Response, String, Stream, Map, and more.
  • Nested Routes: Support for nested routes and dynamic parameters.
  • Async Context Management: Access the current request context asynchronously with XServer.currentRequest.

Getting Started #

Installation #

Add xserver as a dependency in your pubspec.yaml:

dependencies:
  xserver: ^0.1.0

Run pub get to install the package.

Usage #

  1. Define the Server:

    Create a class for your server and annotate it with @XServer, specifying the root directory for your handlers.

    import 'package:xserver/xserver.dart';
    
    @XServer('./server')
    final class AppServer extends _$AppServer {
    }
    
  2. Organize Handlers:

    Organize your handlers according to the file structure. Handlers should be placed in the directory specified in @XServer.

    For example:

    ./server/hello.dart
    ./server/get.get.dart
    ./server/get.post.dart
    ./server/nested/hello.dart
    ./server/[id].dart
    ./server/nested/index.dart
    
  3. Define Handlers:

    Define your handlers in the respective files.

    ./server/hello.dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      return 'Hello, world!';
    });
    

    ./server/get.get.dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      return 'GET Hello!';
    });
    

    ./server/get.post.dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      return 'POST Hello!';
    });
    

    ./server/nested/hello.dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      return 'Nested Hello!';
    });
    

    ./server/[id].dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      final id = request.params['id'];
      return 'Hello, $id!';
    });
    

    ./server/nested/index.dart:

    import 'package:xserver/xserver.dart';
    
    final export = defineHandler((request) {
      return 'Nested Index!';
    });
    
  4. Generate Handlers:

    Run the build command to generate the handler registration code:

    dart run build_runner build
    
  5. Start the Server:

    You can start the server directly using the start method:

    import 'package:xserver/xserver.dart';
    
    void main() async {
      await AppServer.start('localhost', 8080);
      print('Server listening on port 8080');
    }
    

    Or use it as a router:

    import 'package:xserver/xserver.dart';
    import 'package:shelf/shelf.dart';
    import 'package:shelf/shelf_io.dart' as io;
    
    void main() async {
      final handler = const Pipeline()
          .addMiddleware(logRequests())
          .addHandler(AppServer.handle);
    
      final server = await io.serve(handler, 'localhost', 8080);
      print('Server listening on port ${server.port}');
    }
    

Response Types #

The defineHandler function can return various types, and xserver will handle them appropriately:

  • Response: Directly return a shelf response.
  • String: Return a string as a plain text response.
  • Stream<Map<String, dynamic>>: Handle server-sent events with JSON streams.
  • Stream<String>: Handle server-sent events with string streams.
  • Stream<List<int>>: Handle binary streams.
  • Map<String, dynamic>: Return a JSON map.
  • List<int>: Return a binary list.
  • List<String>: Return a list of strings joined by newline.
  • null: Return an empty response.
  • Any other type: Return as JSON encodable.

Async Context Management #

xserver uses zoned contexts to manage asynchronous requests. You can access the current request at any time without passing it explicitly:

import 'package:xserver/xserver.dart';

final export = defineHandler((request) async {
  final currentRequest = XServer.currentRequest;
  // Use the currentRequest as needed
  return 'Handled asynchronously!';
});

Documentation #

Detailed documentation and examples can be found in the documentation directory.

Contributing #

Contributions are welcome! Please read our contributing guide to get started.

License #

This project is licensed under the MIT License. See the LICENSE file for details.