Why must a service parameter bound with :=: REQUEST be typed as HTTPRequest in EK9?

← Web Services · Ref: Q1327

The :=: REQUEST binding hands the service method the entire HTTP request object, so the parameter it binds to must be typed as HTTPRequest. Binding REQUEST to any other type (String, Integer, a record, etc.) triggers E07770 because the compiler cannot deliver a full request into a parameter that is not an HTTPRequest.

CORRECT PATTERN

  handle() as GET for :/
    -> request as HTTPRequest :=: REQUEST

The single parameter receives the whole request.

INCORRECT PATTERN

  handle() as GET for :/
    -> request as String :=: REQUEST

String cannot receive a full request, so E07770 is raised.

This is the mirror of E07790 (HTTPRequest used with a non-REQUEST binding such as PATH or QUERY): REQUEST and HTTPRequest must always go together, and a REQUEST parameter must stand by itself in the method. For individual values use :=: PATH, :=: QUERY or :=: HEADER with simple parseable types like Integer or String.

See Q868 for the inverse restriction. See Q202 for parameter binding. See Q112 for a full service example.

Example

defines module qa.webdeep.service.request.binding

  defines constant

    JSON_TYPE <- "application/json"

  defines service

    <?-
      A service whose handler needs the full request object.
      The :=: REQUEST binding requires an HTTPRequest parameter.
    -?>
    EchoService :/echo open

      handle() as GET for :/
        -> request as HTTPRequest :=: REQUEST
        <- response as HTTPResponse: (body: request.content()) with trait HTTPResponse
          override content()
            <- rtn as String: `{"received": "${body}"}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: JSON_TYPE
          override cacheControl() as pure
            <- rtn as String: "no-cache"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    EchoApp
      register EchoService()

  defines program

    RequestBindingDemo()
      stdout <- Stdout()
      stdout.println("REQUEST binding requires an HTTPRequest parameter.")
      stdout.println("For individual values use PATH, QUERY or HEADER with simple types.")

Common mistakes

E07770 — The :=: REQUEST binding delivers the entire HTTP request, so its parameter must be typed as HTTPRequest. Binding REQUEST to a String (or any non-HTTPRequest type) cannot receive a full request and raises E07770. Type the parameter as HTTPRequest, or for individual values use :=: PATH/QUERY/HEADER with simple types. See ek9 -h E07770 for details.

Incorrect:

        -> request as String :=: REQUEST

Correct:

        -> request as HTTPRequest :=: REQUEST
Other ways to ask this
  • What triggers E07770 SERVICE_INCOMPATIBLE_PARAM_TYPE_REQUEST?
  • Why can't I bind :=: REQUEST to a String parameter?
  • What type does the :=: REQUEST binding require in an EK9 service?

Coming from another language?

Java Spring: a controller can inject HttpServletRequest or bind individual values via @RequestParam/@PathVariable, with no compile-time link between the binding annotation and the parameter type. C# ASP.NET: HttpRequest and model binding mix freely. Go: handlers always receive *http.Request and parse manually. EK9: the binding keyword and the parameter type are checked together at compile time, so REQUEST is only ever allowed against an HTTPRequest parameter.

Keywords: HTTPRequest, binding, service, E07770, REQUEST, type, parameter, http