Why does EK9 reject two service methods that share the same HTTP path?
← Web Services · Ref: Q1305
Each HTTP verb plus URI path must map to exactly one handler method. When two methods on a service share the same verb and structurally identical path, EK9 raises E02070 at compile time - there is no way to know which handler should run for that URL.
Path parameters are compared STRUCTURALLY, not by name: :/{id} and :/{userId} are the SAME path, so renaming a path variable does NOT resolve the conflict. The fix is to make the paths genuinely distinct (a different literal segment, an extra segment, or a different HTTP verb).
See Q684 for valid URI path rules. See Q946 for path-variable-to-parameter matching.
Example
defines module qa.webdeep.duplicatepath defines constant JSON_CONTENT_TYPE <- "application/json" ENGLISH_LANGUAGE <- "en" defines service <?- Service demonstrating distinct endpoints that avoid E02070. Each HTTP verb plus path combination is unique. Note that :/{id} and :/{name}/profile differ structurally (extra segment), so they are NOT duplicates even though both contain a path variable. -?> UserService :/users open //GET /users/{id} — lookup by identifier findById() as GET for :/{id} -> id as String <- response as HTTPResponse: (capturedId: id) with trait HTTPResponse override content() <- rtn as String: `{"id": "${capturedId}"}` override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: JSON_CONTENT_TYPE override cacheControl() as pure <- rtn as String: "no-cache" override contentLanguage() as pure <- rtn as String: ENGLISH_LANGUAGE default operator ? //GET /users/{name}/profile — distinct path (extra literal segment), //so no E02070 conflict with findById even though both have a variable. byName() as GET for :/{name}/profile -> name as String <- response as HTTPResponse: (capturedName: name) with trait HTTPResponse override content() <- rtn as String: `{"name": "${capturedName}"}` override status() as pure <- rtn as Integer: 200 override contentType() as pure <- rtn as String: JSON_CONTENT_TYPE override cacheControl() as pure <- rtn as String: "max-age=60" override contentLanguage() as pure <- rtn as String: ENGLISH_LANGUAGE default operator ? defines application UserApp register UserService() defines program DuplicateServicePathDemo() stdout <- Stdout() stdout.println("Distinct service endpoints (no E02070):") stdout.println(" GET /users/{id}") stdout.println(" GET /users/{name}/profile")
Common mistakes
E02070 — Two GET methods both mapping to :/{id} and :/{nick} are the SAME endpoint because path variables match structurally, not by name - so EK9 cannot pick a handler and raises E02070. Make the paths genuinely distinct (add a literal segment such as :/{name}/profile, or use a different HTTP verb). See ek9 -h E02070 for details.
Incorrect:
byNick() as GET for :/{nick}
Correct:
byName() as GET for :/{name}/profile
Other ways to ask this
- What triggers E02070 duplicate service path/operation?
- Why can't two GET methods map to the same URI in EK9?
- How do I fix a duplicated service endpoint path in EK9?
Coming from another language?
Java Spring: two @GetMapping("/x") methods compile fine and only collide at startup with an AmbiguousMappingException - a runtime failure. Python Flask: a duplicate @app.route raises only when the app boots. Go: last route silently wins. EK9: the duplicate endpoint is a compile-time error (E02070), so the ambiguous routing can never ship.
Keywords: path, http, endpoint, URI, duplicate, E02070, GET, webservice, service, route