Extracts woomera annotations and generates Dart code to instantiate the Server.

This package is for creating a program that scans libraries for woomera annotations that define a Woomera Server and its pipelines. And then to generate a Dart file with code to instantiate that woomera Server and its pipelines.

Note: this package is only useful if you are using the woomera package.

The woomera package is a framework for writing Web server programs. The functionality is implemented in a set of functions. There are request handler functions for processing the HTTP requests into HTTP responses. They are organised into pipelines. And there are various exception handler functions for error handling. Setup code is then required to instantiate a Server object and its pipelines, and populate them with those functions.

This package can be used to automatically generate that setup code. This ensures the functions and the setup code is consistent - especially when functions are added, changed or removed.

Getting started

1. Create the Dart project for the Web server program

$ dart create foobar

Edit the pubspec.yaml file to have the woomera package as a dependency and this woomera_server_gen package as a development dependency.

dependencies:
  woomera: ^8.0.0

dev_dependencies:
  woomera_server_gen: ^0.0.1

Run dart pub get.

2. Write the Web server program

Write the Web server program with its functions in a Dart library.

Annotate the request handler and exception handler functions with the annotations defined in the woomera package. Implement as many or as few of the functions (even none), since functions can be added later on.

In this simple example, the library will be called "foobar" and this is its lib/foobar.dart file:

library foobar;

import 'dart:io';

import 'package:woomera/woomera.dart';

part 'src/server.dart';
part 'src/example_handlers.dart';

And this is its src/example_handlers.dart file:

part of foobar;

@Handles.get('~/')
Future<Response> myRequestHandler(Request) async {
  return ResponseBuffered(ContentType.text)..write('Hello world\n');
}

@ServerExceptionHandler()
Future<Response> myServerExceptionHandler(
    Request req, Object exception, StackTrace st) async {
  stderr.writeln('exception (${exception.runtimeType}): $exception\n$st');

return ResponseBuffered(ContentType.text)
    ..status = HttpStatus.internalServerError
    ..write('Exception: $exception\n');
}

Create a temporary placeholder lib/src/server.dart file so the library does not have any errors. Later, this will be replaced with the generated Dart file.

part of foobar;

Server serverBuilder() => Server();

The program that uses this library can be bin/foobar.dart containing:

import 'dart:io';

import 'package:foobar/foobar.dart' as foobar;

Future<void> main(List<String> arguments) async {
  final server = foobar.serverBuilder()
    ..bindAddress = InternetAddress.loopbackIPv4
    ..bindPort = 8080;

  await server.run();
}

3. Write the server code generation utility

The simplest program just needs to:

  • import the library with the annotations;
  • instantiate a ServerDefinition object;
  • invoke the generateDart function with that object and the name of the library.

For example, dev/gen_server.dart could contain:

import 'dart:io';
import 'package:woomera_server_gen/woomera_server_gen.dart';

// Library being scanned for annotations
import 'package:foobar/foobar.dart' ;

void main() {
  stdout.write(generateDart(ServerDefinition(), libraryName: 'foobar'));
}

Tip: instead of this simple program, copy the example.dart and modify it.

4. Run the utility to generate Dart

Run the utility program.

$ dart dev/server_gen.dart > lib/src/server-new.txt

Inspect the generated file to see if it is correct.

For example, the example above would have generated a file containing:

// WARNING: DO NOT EDIT

part of foobar;

Server serverBuilder() {
  final p1 = ServerPipeline(ServerPipeline.defaultName)
    ..get('~/', myRequestHandler)
    ;

  return Server(numberOfPipelines: 0)
    ..exceptionHandler = myServerExceptionHandler
    ..pipelines.addAll([p1]);
}

5. Updating the Dart code

If it is correct, replace the temporary placeholder file with it.

$ mv lib/src/server-new.txt lib/src/server.dart

Maintaining the Dart code

If the functions and/or their annotations have changed, repeat the above step to update the Dart file.

For example, if a new request handler function and Handles annotation was added to the program, the utility will generate new Dart code that includes it.

Feedback

Please report bugs by opening an issue in GitHub.

Libraries

woomera_server_gen
Uses the dart:mirror package to create a server definition using the annotations defined in the woomera package and generates Dart code to instantiate that server from it.