Handles class
Information for creating a rule or initializing exception handlers.
Instances of this class is designed to be used as an annotation on a
top-level function or static member that will be used to populate rules
and exception handlers when using serverFromAnnotations
and
serverPipelineFromAnnotations
.
Annotating request handlers
Annotate a request handler to automatically populate pipelines with ServerRule objects.
Use the convenience constructors Handles.get, Handles.post, Handles.put etc. that are named after a standard HTTP method, or the generic Handles.request constructor.
The httpMethod is the HTTP request method that the rule will handle.
The ServerPipeline it is for is identified by the pipeline. The order for the rule is determined by the priority and then the pattern. Normally, the priority does not need to be changed from the default of zero, since sorting by the pattern usually produces a correctly working pipeline.
For example, used as an annotation on a top-level function, for the default pipeline:
@Handles.get('~/foo/bar')
Future<Response> myBarHandler(Request req) {
...
}
Usage as an annotation on a static method, for a named pipeline:
class SomeClass {
@Handles.post('~/foo/bar/baz', pipeline='mySpecialPipeline')
static Future<Response> myPostHandler(Request req) {
...
}
}
When a named pipeline is created and populated using these annotations, rules are automatically added to the pipeline from the annotations where the pipeline name matches.
The rules are added in an order determined firstly by the priority and secondly by the pattern.
Normally, the priority can be left as the default, since sorting by the pattern should produce a properly functioning pipeline. See the Pattern.compareTo operator for how patterns are ordered. For special situations, the priority can be set to a non-zero value; but multiple pipelines can also be used to achieve the same behaviour.
Request handler
A server rule consists of a pattern and a request handler. For rules created by a Handles annotation, the request handler comes from the item the annotation is on.
Currently, the item must be a top-level function or a static method. While there is nothing preventing the annotation being placed on other items, they will be ignored.
By default, the handlerWrapper is not set (i.e. it is null). In this case, the item with the annotation must be a RequestHandler function.
If the handlerWrapper is set, the annotated function is passed to it, and the result it returns is used as the request handler.
For example, this example allows a function that is not a RequestHandler to be used in a rule.
RequestHandler myWrapper(Handles info, Object obj) {
if (obj is Function) {
return (Request req) {
final myParam = ... // convert the [Request] req into [MyParamType]
final myResponse = obj(myParam);
final response = ... // convert [MyResponseType] into a [Response]
return response;
};
} else {
throw ...
}
}
@Handles.get('~/foo/bar/')
Future<MyResponseType> baz(MyParamType t) {
...
}
Handles.handlerWrapper = myWrapper;
Annotating exception handlers
Annotate exception handlers to automatically set them. The three types of exception handlers are supported.
Use the Handles.exceptions constructor for the server exception handler. Servers should at least provide one of these exception handlers to customise the "not found" error page.
@Handles.exceptions()
Future<Response> foo(Request req, Object exception, StackTrace st) async {
...
}
Use the Handles.pipelineExceptions constructor for pipeline exception handlers. This allows exception handling to be customised per-pipeline, instead of having all exceptions handled the same way by the server exception handler.
An optional pipeline name can be passed to it, otherwise it will be the pipeline exception handler for the default pipeline.
@Handles.pipelineExceptions(pipeline='mySpecialPipeline')
Future<Response> foo(Request req, Object exception, StackTrace st) async {
...
}
Use the Handles.rawExceptions constructor for the raw server exception handler.
@Handles.rawException()
Future<void> Function(HttpRequest rawRequest, String requestId,
Object exception, StackTrace st) async {
...
}
In a program, there cannot be more than one pipeline exception handler for the same pipeline (i.e. the same pipeline name). There cannot be more than one server exception handler, and there cannot be more than one server raw exception handler.
Logging
The "woomera.handles" logger is used for Handles related log entries.
- CONFIG: shows only the number of annotations found
- FINE: lists what they handle
- FINER: lists what they handle and the request handler that was annotated
- FINEST: also logs the libraries that were scanned for annotations
Note: the above logs the Handles annotations that were found, but they will only be used if a pipeline was created with the same name (i.e. via the ServerPipeline constructor or Server constructor).
Migration from explicit registration to using Handles annotations
In previous versions of Woomera (version 4.3.1 and earlier), ServerRule must be created and added to pipelines. While this is still supported, the use of Handles annotation is now the preferred mechanism for populating a pipeline with rules. The code is easier to maintain, since no extra code is needed to create the server rules and to add them to the pipelines.
To migrate old programs to using Handles annotations, one approach is to:
- Add code to print out all the pipelines and their rules.
- Run the original program and save the output.
- Modify the code: removing the explicit creation of server rules and adding Handles annotations to the request handler functions. Use priority values to control the order the rules appear in the pipeline.
- Run the modified program and compare the output with the original output.
- Repeat steps 3 and 4 until the new output matches the original output.
- Consider removing most of the priority values: only keep those which are significant to how HTTP requests are processed or use multiple pipelines to achieve the same behaviour.
The following example can be used to print out all the pipelines and their rules:
final theServer = ...
... // old pipeline and server rule creation code
// Immediately after all the pipelines have been created...
print('---- BEGIN server rules ----');
var pCount = 0;
for (final pipeline in theServer.pipelines) {
pCount++;
final methodNames = List<String>.from(pipeline.methods());
methodNames.sort();
for (final method in methodNames) {
final rules = pipeline.rules(method);
var rCount = 0;
for (final rule in rules) {
rCount++;
print('Pipeline $pCount: $method $rCount: $rule');
}
}
}
print('---- END server rules ----');
throw UnsupportedError('code in migration to Handles annotations');
// Abort after printing rules. Remove above code after migration.
Constructors
- Handles.delete(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP DELETE method.
const
- Handles.exceptions()
-
Constructor for server exception handler annotation.
const
- Handles.get(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP GET method.
const
- Handles.head(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP HEAD method.
const
- Handles.patch(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP PATCH method.
const
- Handles.pipelineExceptions({String? pipeline})
-
Constructor for pipeline exception handler annotations.
const
- Handles.post(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP POST method.
const
- Handles.put(String? pattern, {String? pipeline, int? priority})
-
Constructor with the HTTP PUT method.
const
- Handles.rawExceptions()
-
Constructor for low-level server exception handler annotation.
const
- Handles.request(String? httpMethod, String? pattern, {String? pipeline, int? priority})
-
Constructor with a specific HTTP method.
const
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- httpMethod → String?
-
The HTTP method for the server rule.
final
- isPipelineExceptionHandler → bool
-
Indicates if this is describing a pipeline exception handler
no setter
- isRequestHandler → bool
-
Indications if this is describing an exception handler or not.
Indications if this is describing a request handler or not.
no setter
- isServerExceptionHandler → bool
-
Indicates if this is describing a server exception handler
no setter
- isServerRawExceptionHandler → bool
-
Indicates if this is describing a server raw exception handler
no setter
- pattern → String?
-
The string representation of the pattern for the server rule.
final
- pipeline → String?
-
Name of the pipeline.
final
- priority → int?
-
The priority for the rule within the pipeline.
final
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
override
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Properties
- handlerWrapper ↔ HandlerWrapper?
-
Wrapper for the annotated function.
getter/setter pair