What must service method bodies contain and what is prohibited?

← Web Services · Ref: Q685

EK9 service methods have specific body requirements. Methods must have concrete implementations (not abstract), and certain operations are restricted.

CONCRETE BODIES REQUIRED (E07870)

Every service method and operator must have a body. Abstract methods are not allowed in services because the runtime must be able to invoke every endpoint.

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 String: `{"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 String: `{"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 E07870 service method body requirement?
  • What is E07880 prohibited operation in service method?
  • Can service methods use stream operations?
  • 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, return HTTPResponse.

Keywords: E07880, abstract, service, http, E07870, method, concrete, HTTPResponse, body