What must service method bodies contain and what is prohibited?
← Web Services · Ref: Q685
EK9 service methods must have concrete implementations, and one access modifier is restricted.
CONCRETE BODIES REQUIRED (E07740)
Every service method and operator must have a body. A method declared with no implementation is E07740 ('implementation not provided, but services cannot be abstract'): the runtime must be able to invoke every endpoint.
HELPER METHODS
A service may also have methods that are not web endpoints (no HTTP verb and path), plain or 'private', for logic shared by its endpoints. Marking such a helper 'protected' is E07240: nothing can extend a service, so 'protected' has no meaning there.
RETURN TYPE
Service methods return HTTPResponse. The response is typically created as a dynamic class implementing the HTTPResponse trait.
HTTPRESPONSE PATTERN
The standard pattern uses a dynamic class with trait implementation:
<- response as HTTPResponse: () with trait HTTPResponse override content() ... override status() ... override contentType() ...
OPERATOR ENDPOINTS
Services can use operators (+=, -=, :~:, :^:) for CRUD:
operator += for POST (create) operator -= for DELETE operator :~: for PATCH (merge) operator :^: for PUT (replace)
See Q657 for URI mapping. See Q660 for CRUD operator pattern. See Q684 for URI path rules.
Example
defines module qa.webdeep.methodbodies defines service <?- Service with fully implemented method bodies. Every method returns a concrete HTTPResponse. -?> StatusService :/status open //GET /status/health — health check endpoint health() as GET for :/health <- response as HTTPResponse: () with trait HTTPResponse override content() <- rtn as Bytes: Bytes().withUtf8(`{"status": "healthy"}`) override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: "application/json" override cacheControl() as pure <- rtn as String: "no-cache" override contentLanguage() as pure <- rtn as String: "en" default operator ? //GET /status/version — version info endpoint version() as GET for :/version <- response as HTTPResponse: () with trait HTTPResponse override content() <- rtn as Bytes: Bytes().withUtf8(`{"version": "1.0.0"}`) override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: "application/json" override cacheControl() as pure <- rtn as String: "max-age=300" override contentLanguage() as pure <- rtn as String: "en" default operator ? defines application StatusApp register StatusService() defines program ServiceMethodBodiesDemo() stdout <- Stdout() stdout.println("Service method bodies:") stdout.println(" GET /status/health -> concrete body with HTTPResponse") stdout.println(" GET /status/version -> concrete body with HTTPResponse")
Common mistakes
E50001 — The function getMethodInfo is not defined in this module. See ek9 -h E50001 for details.
Incorrect:
stdout.println(getMethodInfo())
Correct:
stdout.println("Service method bodies:")
E50001 — The function getHealthInfo is not defined in this module. See ek9 -h E50001 for details.
Incorrect:
stdout.println(getHealthInfo())
Correct:
stdout.println(" GET /status/health -> concrete body with HTTPResponse")
Other ways to ask this
- What is E07740 service method with no body?
- What is E07240 protected method in a service?
- Can a service have private helper methods?
- What restrictions apply to service method implementations?
Coming from another language?
Java: Spring @RestController methods must have bodies. Python: Flask route handlers need implementations. Go: handler functions must be concrete. Rust: handler functions must be concrete. EK9: service methods must have concrete bodies (E07740) and return HTTPResponse; non-web helper methods may be plain or private, never protected (E07240).
Keywords: service, E07740, E07240, abstract, body, HTTPResponse, concrete, method, http