E02070: PATH is duplicated in terms of structure/naming

Category: E02xxx Symbol definition · Reported in phase: EXPLICIT_TYPE_SYMBOL_DEFINITION · Classification: SERVICE_HTTP_PATH_DUPLICATED · All error codes

What went wrong

Two web service methods have the same HTTP path pattern. Each URL path must map to exactly one handler method.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 1305 (Why does EK9 reject two service methods that share the...)

How to fix it

  • Use distinct path patterns for each method
  • If paths look different but match same URLs, make them structurally different

Common causes

  • Copy-paste creating duplicate endpoints
  • Path patterns that look different but match same URLs
  • Forgetting to change path when creating similar endpoints

Note

Path parameters are matched STRUCTURALLY, not by name:

/users/{id} and /users/{userId} are the SAME path.

Examples

Every example is compiled by the EK9 compiler: the first fails exactly as captioned, the others fix it.

Fails with E02070: PATH is duplicated in terms of structure/naming

#!ek9
defines module error.e02070.bad

  defines service

    Resources for :/api open

      resource() as GET for :/{id}
        -> id as String
        <- response as HTTPResponse: () with trait of HTTPResponse

      //Same verb, same path structure: {userId} and {id} are both just a path variable
      user() as GET for :/{userId}
        -> userId as String
        <- response as HTTPResponse: () with trait of HTTPResponse

Fixed: Give each operation its own path structure, or a different HTTP verb

#!ek9
defines module error.e02070.good

  defines function

    textResponse()
      -> body as String
      <- response as HTTPResponse: (body) with trait of HTTPResponse
        override content()
          <- rtn as Bytes: Bytes().withUtf8(body)
        default operator ?

  defines service

    Resources for :/api open

      resource() as GET for :/{id}
        -> id as String
        <- response as HTTPResponse: textResponse(id)

      user() as GET for :/users/{userId}
        -> userId as String
        <- response as HTTPResponse: textResponse(userId)

      replaceResource() as PUT for :/{id}
        -> id as String
        <- response as HTTPResponse: textResponse("replaced " + id)

Questions and answers

These Q&A entries show E02070 and its fix: