How do HTTP verbs, URI path variables, and parameter qualifiers work in EK9 services?

← Web Services · Ref: Q945

An EK9 service method becomes a web endpoint through its header, and its parameters say where each value comes from.

1. VERB AND PATH

A web method is written 'name() as VERB for :/path', with VERB one of GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS. The verb may be left out ('name() for :/path'), in which case the default verb is used. Path variables go in braces in the METHOD path: 'findUser() as GET for :/{userId}'.

2. NO VARIABLES IN THE SERVICE BASE PATH (E07680)

The base path on the service name is fixed text. 'UserService :/users/{tenant}' is E07680: a URI placeholder variable is not supported in that context.

3. HTTP QUALIFIERS ONLY ON WEB METHODS (E07690)

A parameter source marker such as ':=: QUERY "q"' only means something on a web method. On a method with no verb and no path - an ordinary helper - it is E07690 (HTTP access not supported in this context).

4. PARAMETER QUALIFIERS AND THEIR NAMES (E07710, E07720)

Each parameter can say where its value comes from: PATH, QUERY, HEADER, REQUEST, CONTENT or CONTEXT (there is no COOKIE qualifier). A path parameter needs no qualifier at all - it is bound from the matching '{name}' segment - and a bare PATH also compiles.

  -> term as String :=: QUERY "q"

QUERY and HEADER must name the query parameter or header: a bare QUERY or HEADER is E07710. REQUEST, CONTENT and CONTEXT take no name: 'REQUEST "r"' is E07720.

See Q657 for URI mapping. See Q846 for parameter types. See Q868 for path parameter types.

Example

defines module qa.services.uripath.params

  defines constant

    JSON_TYPE <- "application/json"

  defines class

    <?-
      Models a user lookup response.
      Demonstrates how path variables bind to parameters in services.
    -?>
    UserResponse
      userId as Integer: 0
      contentKind as String: JSON_TYPE

      UserResponse()
        -> givenUserId as Integer
        this.userId :=: givenUserId

      userId()
        <- rtn as Integer: Integer(userId)

      contentKind()
        <- rtn as String: String(contentKind)

      toJson()
        <- rtn as String: `{"userId": ${userId}}`

      operator $ as pure
        <- rtn as String: `UserResponse[${userId}]`
      operator #^ as pure
        <- rtn as String: $this
      default operator ?

    <?-
      Models a user list response.
    -?>
    UserListResponse
      userCount as Integer: 0

      UserListResponse()
        -> givenCount as Integer
        this.userCount :=: givenCount

      toJson()
        <- rtn as String: `{"users": [], "count": ${userCount}}`

      operator $ as pure
        <- rtn as String: `UserListResponse[${userCount}]`
      operator #^ as pure
        <- rtn as String: $this
      default operator ?

    <?-
      Simulates a user service with path parameter binding.
      In real services, GET /users/{userId} binds userId from the URI.
    -?>
    UserEndpoint

      findUser()
        -> userId as Integer
        <- rtn as UserResponse: UserResponse(userId)

      listUsers()
        <- rtn as UserListResponse: UserListResponse(0)

      operator $ as pure
        <- rtn as String: "UserEndpoint"
      operator #^ as pure
        <- rtn as String: $this
      default operator ?

  defines program

    ServiceUriParamsDemo()
      stdout <- Stdout()
      endpoint <- UserEndpoint()
      userResult <- endpoint.findUser(42)
      listResult <- endpoint.listUsers()

      stdout.println("Service URI parameters:")
      stdout.println("  GET /users/{userId} -> path variable binding")
      stdout.println("  GET /users/list -> no parameters")
      stdout.println(userResult.toJson())
      stdout.println(listResult.toJson())
Other ways to ask this
  • What triggers E07680 SERVICE_URI_WITH_VARS_NOT_SUPPORTED?
  • What triggers E07690 SERVICE_HTTP_ACCESS_NOT_SUPPORTED?
  • Why must a QUERY or HEADER service parameter be given a name (E07710)?
  • Why can a REQUEST service parameter not take a qualifier name (E07720)?
  • How do I bind path variables to parameters?

Coming from another language?

Java Spring: @GetMapping, @PathVariable, @RequestParam, @RequestHeader. Python Flask: @app.route with <param>. Go: mux.Vars(r) for path variables. EK9: 'as VERB for :/path/{var}' on the method (the verb is optional), path variables bound by name, and ':=: QUERY "q"' / ':=: HEADER "h"' qualifiers for other sources.

Keywords: verb, E07720, E07690, HEADER, HTTP, URI, QUERY, parameter, E07710, E07680, path, service