What are the basic rules for EK9 service definitions?
← Web Services · Ref: Q944
EK9 services enforce three fundamental rules:
1. CONCRETE BODIES REQUIRED (E07740)
Every service method must have a concrete implementation body. A method with no implementation is E07740 ('implementation not provided, but services cannot be abstract'): abstract methods cannot serve HTTP requests.
2. SUPPORTED OPERATORS ONLY (E07670)
A service may declare only these operators: +, +=, -, -=, :^:, :~: and ?. The CRUD ones are commonly mapped as:
- += for POST (create)
- -= for DELETE
- :~: for PATCH (merge)
- :^: for PUT (replace)
Any other operator, such as == or <, is E07670.
3. NO PROTECTED NON-WEB METHODS (E07240)
A service may have helper methods that are not HTTP-bound, either plain or 'private'. What it may not do is mark such a method 'protected' (E07240): nothing can extend a service, so 'protected' has no meaning.
See Q657 for URI mapping. See Q659 for HTTPResponse. See Q660 for CRUD operators. See Q685 for method bodies.
Example
defines module qa.services.basics.overview defines class <?- Models an HTTP response with status and content. Demonstrates the pattern services use for endpoint handlers. -?> HealthResponse statusCode as Integer: 200 responseBody as String: `{"status": "ok"}` responseType as String: "application/json" HealthResponse() -> givenStatus as Integer givenBody as String this.statusCode :=: givenStatus this.responseBody :=: givenBody statusCode() <- rtn as Integer: Integer(statusCode) responseBody() <- rtn as String: String(responseBody) responseType() <- rtn as String: String(responseType) operator $ as pure <- rtn as String: `HealthResponse[${statusCode}]` operator #^ as pure <- rtn as String: $this default operator ? <?- Simulates a service endpoint handler. In real EK9 services, methods must have concrete bodies (E07740). -?> HealthHandler endpoint as String: "/api/health" handleGet() <- rtn as HealthResponse: HealthResponse(200, `{"status": "ok"}`) endpoint() <- rtn as String: String(endpoint) operator $ as pure <- rtn as String: `Handler[${endpoint}]` operator #^ as pure <- rtn as String: $this default operator ? defines program ServiceBasicsDemo() stdout <- Stdout() handler <- HealthHandler() healthResult <- handler.handleGet() stdout.println("Service basics:") stdout.println(" Methods must have concrete bodies") stdout.println(" Service operators: +, +=, -, -=, :^:, :~: and ?") stdout.println(" Non-web helper methods cannot be protected") stdout.println($healthResult)
Other ways to ask this
- What triggers E07740 SERVICE_WITH_NO_BODY_PROVIDED?
- What triggers E07670 SERVICE_OPERATOR_NOT_SUPPORTED?
- Why is a protected helper method in a service rejected with E07240?
- What operators can services use for CRUD?
Coming from another language?
Java Spring: controllers can have private helper methods. Python Flask: handler functions are plain Python. Go: handlers are plain functions. EK9: services hold HTTP endpoints plus plain or private helper methods (never protected), with a fixed set of operators and every method given a body.
Keywords: E07670, CRUD, E07240, method, E07740, web, service, body, basics, operator