Why can't I bind HTTPContext to a QUERY parameter in an EK9 service?

← Web Services · Ref: Q1331

HTTPContext is the whole-request context object, so it can only be bound with the :=: CONTEXT access type. Binding it with :=: QUERY, :=: PATH, :=: HEADER or :=: CONTENT triggers E07793 because those access types extract a single named value from the URI, path, headers or body — they cannot reconstruct the full context object.

CORRECT PATTERN

  info() as GET for :/info
    -> ctx as HTTPContext :=: CONTEXT

HTTPContext bound with CONTEXT gives access to the entire request context.

If you only need a single query value, bind a simple type instead:

  search() as GET for :/search
    -> term as String :=: QUERY "q"

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

Example

defines module qa.webdeep.service.httpcontext.access

  defines constant

    PLAIN_TEXT <- "text/plain"

  defines service

    <?-
      Service showing the two correct bindings: HTTPContext must use
      :=: CONTEXT, while a single query value uses a simple String type.
    -?>
    Info :/info open

      context() as GET for :/context
        -> ctx as HTTPContext :=: CONTEXT
        <- response as HTTPResponse: (capturedId: ctx.requestId()) with trait HTTPResponse
          override content()
            <- rtn as String: `context request id ${capturedId}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: PLAIN_TEXT
          override cacheControl() as pure
            <- rtn as String: "no-store"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

      search() as GET for :/search
        -> term as String :=: QUERY "q"
        <- response as HTTPResponse: (capturedTerm: term) with trait HTTPResponse
          override content()
            <- rtn as String: `searched for ${capturedTerm}`
          override status() as pure
            <- rtn as Integer: 200
          override contentType() as pure
            <- rtn as String: PLAIN_TEXT
          override cacheControl() as pure
            <- rtn as String: "no-store"
          override contentLanguage() as pure
            <- rtn as String: "en"
          default operator ?

  defines application

    InfoApp
      register Info()

  defines program

    HttpContextAccessDemo()
      stdout <- Stdout()
      stdout.println("HTTPContext must bind with :=: CONTEXT")
      stdout.println("A single query value binds with :=: QUERY using a simple type")

Common mistakes

E07793 — HTTPContext is the whole-request context object and can only be bound with the :=: CONTEXT access type. Binding it with :=: QUERY (or PATH, HEADER, CONTENT) extracts a single named value and cannot produce a context object, so the compiler raises E07793. Use :=: CONTEXT for HTTPContext, or bind a simple type like String for a query value. See ek9 -h E07793 for details.

Incorrect:

        -> ctx as HTTPContext :=: QUERY "q"

Correct:

        -> ctx as HTTPContext :=: CONTEXT
Other ways to ask this
  • What triggers E07793 when using HTTPContext in a service parameter?
  • Which access type must HTTPContext use in EK9 services?
  • Why does EK9 reject HTTPContext with :=: QUERY, PATH, HEADER or CONTENT?

Coming from another language?

Java Spring: any controller argument can be annotated freely (@RequestParam, @RequestBody) with no compile-time check that the type matches the binding source. C# ASP.NET: model binding is convention-based and resolved at runtime. Go/Python: the request context is read manually with no binding metadata. EK9: the compiler enforces at compile time that HTTPContext is only ever bound with :=: CONTEXT, so a context object can never be wired to a query, path, header or body source.

Keywords: CONTEXT, QUERY, access, service, rest, E07793, http, HTTPContext, binding