Why can't I mix HTTPRequest with other parameters in an EK9 service operation?
← Web Services · Ref: Q1328
When a service operation takes the full request via :=: REQUEST (an HTTPRequest), that parameter must be the ONLY parameter on the operation. Adding any second parameter — a CONTENT binding, a PATH segment, anything — triggers E07780 (SERVICE_REQUEST_BY_ITSELF).
The rule exists because HTTPRequest carries the whole request, so mixing it with individually-bound parameters would bind the same request twice and create two sources of truth for the same data.
CORRECT PATTERN
process() as POST for :/process -> request as HTTPRequest :=: REQUEST <- response as HTTPResponse: ...
Read the body from the request inside the method body via request.content(). HTTPRequest offers only the body (content()), no path, query or header accessors, so an operation that needs a path, query or header value binds it with :=: PATH, QUERY or HEADER and does not take the HTTPRequest.
INCORRECT PATTERN
process() as POST for :/process -> request as HTTPRequest :=: REQUEST body as String :=: CONTENT <- response as HTTPResponse: ...
The extra body parameter alongside the full request raises E07780.
See Q202 for parameter binding. See Q868 for valid path-parameter types.
Example
defines module qa.webdeep.service.request.only defines constant JSON_RESPONSE <- "application/json" defines service <?- Operation that binds the FULL request via :=: REQUEST. HTTPRequest is the only parameter, so E07780 is not raised. Any path/query/body value is read from the request inside the body. -?> ItemService :/items open process() as POST for :/process -> request as HTTPRequest :=: REQUEST <- response as HTTPResponse: (request: request) with trait HTTPResponse override content() <- rtn as Bytes: Bytes().withUtf8(`{"received": "${request.content().toText("utf-8")}"}`) override status() as pure <- rtn as Integer: 201 override contentType() as pure <- rtn as String: JSON_RESPONSE override cacheControl() as pure <- rtn as String: "no-store" override contentLanguage() as pure <- rtn as String: "en" default operator ? defines application ItemApp register ItemService() defines program HttpRequestOnlyDemo() stdout <- Stdout() stdout.println("HTTPRequest must be the ONLY parameter on an operation.") stdout.println("Read the body from the request with request.content(); bind path, query and header values with PATH, QUERY and HEADER instead.")
Common mistakes
E07780 — An operation that binds the full request with :=: REQUEST must have HTTPRequest as its ONLY parameter. The extra CONTENT-bound body parameter makes the operation take more than one parameter, so E07780 fires. Drop the extra parameter and read the body from the request inside the method body via request.content(). See ek9 -h E07780 for details.
Incorrect:
process() as POST for :/process -> request as HTTPRequest :=: REQUEST body as String :=: CONTENT
Correct:
process() as POST for :/process -> request as HTTPRequest :=: REQUEST
Other ways to ask this
- What triggers E07780 SERVICE_REQUEST_BY_ITSELF?
- Why must HTTPRequest be the only parameter on a service operation?
- How do I get a path or query value when I also need the full HTTPRequest?
Coming from another language?
Java Spring: a handler may freely mix HttpServletRequest with @PathVariable/@RequestParam — nothing prevents the duplication. C# ASP.NET: HttpContext plus bound parameters coexist. Go net/http: you read *http.Request and also parse mux.Vars(r) together. EK9: the compiler forbids the mixture at compile time — if you take the full HTTPRequest you take only that and extract the rest from it.
Keywords: REQUEST, E07780, rest, service, binding, HTTPRequest, http, parameter