E12020: application registers services but program has no HTTP server
What went wrong
The linked application registers one or more services, but the program never creates an HTTP instance. Nothing will serve those services: the program runs its body and exits, so every registered route is unreachable for the whole life of the process.
Worked examples
The [EXAMPLE] section below shows an application that registers a service, and a program linked to it that never creates an HTTP instance (so it runs its body and exits); then (a) the program serving them with 'HTTP(props).serve()', and (b) the wiring split, so a program that only needs the components links an application that registers only those.
Rationale
A registered service that is never served is dead wiring. It is constructed, it consumes its dependencies, and it can never receive a request — the program terminates as soon as its body completes. Nothing at runtime reports this: the process simply exits successfully, so the mistake is invisible until someone notices the endpoint was never live.
This is the mirror of E12021. Both directions of the same wiring mistake are caught here, because the application's registrations and the program's variable declarations are both known at compile time.
Splitting the application is usually the right answer when a program genuinely needs only the components. Conflating serving wiring with component wiring is what leaves a REST service registered and permanently unreachable.
How to fix it
Either:
- Create and serve an HTTP instance in the program (most likely fix): 'HTTP(props).serve()' with the NetworkProperties for its port (good.ek9 in the [EXAMPLE] section below)
- Split the application, so this program uses one that registers only the components it needs (good_split.ek9 below), or
- Remove the service registration if the service is not wanted.
See also
Examples
Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.
Fails with E12020: application registers services but program has no HTTP server
#!ek9 defines module error.e12020.bad defines constant plainText <- "text/plain" defines service StatusService for :/status open health() as GET for :/health <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: plainText default operator ? defines application StatusApp register StatusService() defines program ServicesWithoutHttpDemo() with application of StatusApp stdout <- Stdout() stdout.println("this program exits — StatusService can never be reached")
Fixed: Serve the registered services over HTTP
#!ek9 defines module error.e12020.good defines service StatusService for :/status open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? defines application StatusApp register StatusService() defines program ServicesWithHttpDemo() with application of StatusApp props <- NetworkProperties(9090) HTTP(props).serve()
Fixed: Or give a program that does not serve an application with no services
#!ek9 defines module error.e12020.good.split defines component Repository as abstract size() as abstract <- rtn as Integer? default operator ? InMemoryRepository is Repository override size() <- rtn as Integer: 0 default operator ? defines service StatusService for :/status open health() as GET for :/status <- response as HTTPResponse: () with trait of HTTPResponse override status() as pure <- rtn as Integer: 200 override content() <- rtn as Bytes: Bytes().withUtf8("ok") override contentType() as pure <- rtn as String: "text/plain" default operator ? defines application StatusApp register InMemoryRepository() as Repository register StatusService() RepositoryOnly register InMemoryRepository() as Repository defines program Report() with application of RepositoryOnly stdout <- Stdout() repository as Repository! stdout.println($repository.size())
Questions and answers
These Q&A entries show E12020 and its fix: