What are the basic rules for EK9 service definitions?

← Web Services · Ref: Q944

EK9 services enforce three fundamental rules:

1. CONCRETE BODIES REQUIRED (E07240)

Every service method must have a concrete implementation body. Abstract methods cannot serve HTTP requests.

2. SUPPORTED OPERATORS ONLY (E07670)

Services support specific operators for CRUD patterns:

  += for POST (create)
  -= for DELETE
  :~: for PATCH (merge)
  :^: for PUT (replace)

Other operators like ==, <, + are not valid on services.

3. NO PROTECTED NON-WEB METHODS (E07740)

All service methods must be HTTP-bound (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS). Private helper methods and protected non-web methods are not allowed because services expose only HTTP endpoints.

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 (E07240).
    -?>
    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("  Only CRUD operators: +=, -=, :~:, :^:")
      stdout.println("  All methods must be HTTP-bound")
      stdout.println($healthResult)
Other ways to ask this
  • What triggers E07240 SERVICE_METHOD_NEEDS_BODY?
  • What triggers E07670 SERVICE_OPERATOR_NOT_SUPPORTED?
  • What triggers E07740 SERVICE_NON_WEB_METHOD_NOT_ALLOWED?
  • 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 are strictly HTTP-endpoint containers with enforced method rules.

Keywords: service, web, E07740, method, E07240, CRUD, E07670, operator, basics, body