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.
  • StrictStart must be set before Start. 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:

  • LastErrorStatusCode
  • LastErrorExceptionClass
  • LastErrorExceptionMessage

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.DoFilter with zero filters, with a filter that short-circuits by never calling Next.DoFilter, and with an exception thrown mid-chain; plus TdjWebFilterMapping.AppliesTo URL-pattern matching (#503).
  • Connector and server lifecycle: bind/activate on Start, deactivate on Stop, socket release on Destroy, double-start and stop-without-start as no-ops, and changing Port while running leaving the live binding untouched; plus the guard in TdjServerBase.Handle on the wrapped handler’s started state (#504).
  • Sessions: all three branches of TdjHandlerWrapper.GetSession: existing session returned as-is, nil when absent and Create is False, and a new session created when absent and Create is True (#505).
  • Shared base classes: the TdjGenericHolder, TdjGenericWebComponent, and TdjGenericWebFilter contracts reused by every holder subclass, including the previously untested GetSession (#506).
  • Utilities: djGlobal.HTMLEncode escaping and the case-sensitive key contract of TdjInitParameters. The audit also confirmed that djPlatform and djHTTPConstants are low-risk constant and wrapper units with nothing left to test (#507).
  • Configuration: the full TdjAbstractConfig contract (missing keys, case sensitivity, duplicate-key rejection, GetInitParameterNames, SetContext rules, and Name) and TdjContextConfig conformance to IContextConfig (#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:

  1. Set Server.StrictStart := True before Start if you want startup failures to surface immediately.
  2. Assign an ErrorHandler on the contexts where you want custom error responses, and read the failure details from the new TdjServerContext properties.

As always, feedback and bug reports are welcome on GitHub. Thanks to everyone who reported issues and helped test this release.