How do I bind path parameters and request body in EK9 services?

← Web Services · Ref: Q202

EK9 services bind path parameters and request content automatically using URI templates and binding keywords.

PATH PARAMETERS (IMPLICIT)

Path segments in braces bind to parameters by name:

  - the method is declared byId() as GET for :/{id}
  - its parameter is declared -> id as String

The {id} in the path automatically binds to the id parameter.

EXPLICIT PATH BINDING

Use :=: PATH for explicit binding to a named path segment:

  -> itemId as String :=: PATH "item-id"

Binds parameter 'itemId' to the path segment named 'item-id'.

CONTENT BINDING

Access the request body with :=: CONTENT:

  -> content as String :=: CONTENT

The entire request body is bound to the parameter.

REQUEST BINDING

Access the full request object with :=: REQUEST:

  -> request as HTTPRequest :=: REQUEST

Provides access to all request information.

See Q199 for REST GET endpoints. See Q200 for CRUD operators. See Q112 for full service example.

Example

#!ek9
defines module qa.web.parameters

  defines service

    Products for :/products open

      // Path parameter implicit binding
      byId() as GET for :/{id}
        -> id as String
        <- response as HTTPResponse?

        itemId <- String(id)
        response: (itemId) with trait HTTPResponse
          override content()
            <- rtn as Bytes: Bytes().withUtf8(`{"id": "${itemId}"}`)
          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 ?

      // Content binding for POST body
      operator += for :/
        -> content as String :=: CONTENT
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as Bytes: Bytes().withUtf8(`{"received": true}`)
          override status() as pure
            <- rtn as Integer: 201
          override contentType() as pure
            <- rtn as String: "application/json"
          override cacheControl() as pure
            <- rtn as String: "no-store"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    ProductApp
      register Products()

  defines program

    ParameterBindingDemo()
      stdout <- Stdout()

      stdout.println("Path parameter binding:")
      stdout.println("  -> id as String (implicit from {id})")
      stdout.println("Content binding:")
      stdout.println("  -> content as String :=: CONTENT")
      stdout.println("Request binding:")
      stdout.println("  -> request as HTTPRequest :=: REQUEST")

Common mistakes

E50060 — Stdout does not have a display() method. The correct method is println(). Calling a non-existent method triggers E50060 — method not resolved. See ek9 -h E50060 for details.

Incorrect:

stdout.display("Path parameter binding:")

Correct:

stdout.println("Path parameter binding:")
Other ways to ask this
  • How does automatic parameter binding work in EK9 services?
  • How do I access the request body in EK9?
  • How does parameter binding work in EK9 services?

Coming from another language?

Java: JAX-RS @PathParam("id"), @RequestBody. Python: Flask route('<id>') and request.json. Rust: axum Path(id) and Json(body) extractors. Go: mux.Vars(r)["id"] and io.ReadAll(r.Body). Kotlin: Ktor call.parameters["id"] and call.receive(). EK9: {id} in path auto-binds, :=: CONTENT for body, :=: REQUEST for full request.

Keywords: bind, body, content, extract, http, parameter, path, request, rest, service, uri