Daraja 3.4.0 is almost here. This release is small in surface area but meaningful in practice: two opt-in features that make servers easier to operate and debug, one routing fix that removes a long-standing surprise, and a large batch of new test coverage.
Fail fast with StrictStart
Until now, Daraja has been forgiving at startup. If a context failed to start, or a Web Component’s Init raised an exception, the problem was logged and swallowed. The result: Server.Start returned normally, the server looked healthy, and you found out about the broken component when the first request hit a 404 or a 500.
3.4.0 adds TdjServer.StrictStart, an opt-in switch that changes this behavior:
pascal
Server := TdjServer.Create(8080);
Server.StrictStart := True; // must be set before Start
Context := TdjWebAppContext.Create('custom');
Context.Add(TFailingResource, '/fail');
Server.Add(Context);
Server.Start; // raises if anything in the handler tree fails to start
With StrictStart enabled, a startup failure anywhere in the handler tree now raises out of Server.Start. That is exactly what you want in deployment scripts, containers, and CI smoke tests, where a half-started server should be a hard failure rather than a silent one.
A few details worth knowing:
- The default is
False, so existing applications behave exactly as before. StrictStartmust be set beforeStart. Setting it on an already-started server raises an exception.
ErrorHandler now actually works
This one is a fix as much as a feature. TdjContextHandler.ErrorHandler has existed for a while, but the value you assigned was stored and never invoked. In 3.4.0 it finally does what its name promises.
When a Web Component or Web Filter raises an unhandled exception, and an ErrorHandler is configured on the context, Daraja calls it instead of sending the framework’s generic 500 response. The handler can see what went wrong through new properties on TdjServerContext:
LastErrorStatusCodeLastErrorExceptionClassLastErrorExceptionMessage
That makes it straightforward to render a branded error page, return a JSON error body for an API context, or log structured failure details in one central place.
The change is conservative by design. If no ErrorHandler is set, or if the handler itself raises, Daraja falls back to exactly the same generic response as today. Contexts that don’t opt in see no behavior change.
A runnable example is included as demo/19_error_handler.
Fix: bare context paths now match
If you registered a context named "app", you might reasonably expect /app to reach it. Previously, only /app/... matched, and the bare /app returned a 404.
TdjContextHandler.ContextMatches now handles this case, following the Servlet specification’s rule for request path matching: a request matches if the path is an exact match for the context path, or the context path followed by /. This is the same rule TdjPathMap already applies when a /foo/* pattern matches a bare /foo, so context matching and path mapping are now consistent with each other.
If you worked around the old behavior (for example, with a redirect or an extra mapping for the bare path), it’s worth reviewing it after upgrading.
Under the hood: a big test coverage push
3.4.0 also wraps up a systematic coverage audit (tracked in #502). None of this changes runtime behavior, but it makes the framework safer to evolve. New tests now cover:
- Filter chains:
TdjWebFilterChain.DoFilterwith zero filters, with a filter that short-circuits by never callingNext.DoFilter, and with an exception thrown mid-chain; plusTdjWebFilterMapping.AppliesToURL-pattern matching (#503). - Connector and server lifecycle: bind/activate on
Start, deactivate onStop, socket release onDestroy, double-start and stop-without-start as no-ops, and changingPortwhile running leaving the live binding untouched; plus the guard inTdjServerBase.Handleon the wrapped handler’s started state (#504). - Sessions: all three branches of
TdjHandlerWrapper.GetSession: existing session returned as-is,nilwhen absent andCreateisFalse, and a new session created when absent andCreateisTrue(#505). - Shared base classes: the
TdjGenericHolder,TdjGenericWebComponent, andTdjGenericWebFiltercontracts reused by every holder subclass, including the previously untestedGetSession(#506). - Utilities:
djGlobal.HTMLEncodeescaping and the case-sensitive key contract ofTdjInitParameters. The audit also confirmed thatdjPlatformanddjHTTPConstantsare low-risk constant and wrapper units with nothing left to test (#507). - Configuration: the full
TdjAbstractConfigcontract (missing keys, case sensitivity, duplicate-key rejection,GetInitParameterNames,SetContextrules, andName) andTdjContextConfigconformance toIContextConfig(#508).
Upgrading
For most applications, 3.4.0 should be a drop-in upgrade. The only change that can alter behavior without you opting in is the context path fix, so if you have special handling for bare context paths, take a quick look at it. To get the new behaviors:
- Set
Server.StrictStart := TruebeforeStartif you want startup failures to surface immediately. - Assign an
ErrorHandleron the contexts where you want custom error responses, and read the failure details from the newTdjServerContextproperties.
As always, feedback and bug reports are welcome on GitHub. Thanks to everyone who reported issues and helped test this release.