E07731: each HTTP PATH variable must be bound by exactly one PATH parameter

Category: E07xxx Full resolution · Reported in phase: EXPLICIT_TYPE_SYMBOL_DEFINITION · Classification: SERVICE_HTTP_PATH_PARAM_BINDING_INVALID · All error codes

What went wrong

Each path variable in a service operation's URI must appear only once and be bound by exactly ONE PATH parameter. Matching counts are not enough: two parameters bound to the same variable make up the number for a variable that nothing binds, so a request segment would silently never reach the operation.

Worked examples

Compilable examples demonstrating this error and the correct fix:

  • ek9 -q 946 (How must path variable counts match parameters in EK9 services?)

How to fix it

  1. Bind every path variable with exactly one PATH parameter
  2. Give each path variable a distinct name within the URI

The [EXAMPLE] section below shows one variable bound twice (explicitly, and once by an inferred name) and one repeated in the URI, then each variable bound exactly once.

Common causes

  • Copying a parameter line and not changing its PATH "name"
  • An inferred PATH parameter (named like the variable) plus an explicit :=: PATH to the same variable
  • Reusing one variable name twice in the URI

See also

  • E07731: path variable bound twice, or repeated in the URI (this error)
  • E07730: path variable/parameter count mismatch
  • E07700: invalid path parameter format

Examples

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

Fails with E07731: each HTTP PATH variable must be bound by exactly one PATH parameter

#!ek9
defines module error.e07731.bad

  defines service

    Items for :/items open

      //Valid control: each placeholder bound once.
      pair() for :/{a}/{b}/pair.html
        ->
          first as String :=: PATH "a"
          second as String :=: PATH "b"
        <-
          response as HTTPResponse: () with trait of HTTPResponse

      //Both explicit parameters bind {a}; {b} is never bound.
      twiceExplicit() for :/{a}/{b}/twiceExplicit.html
        ->
          first as String :=: PATH "a"
          second as String :=: PATH "a"
        <-
          response as HTTPResponse: () with trait of HTTPResponse

      //'a' is an inferred PATH "a" binding, and the explicit parameter binds {a} again; {b} unbound.
      twiceInferred() for :/{a}/{b}/twiceInferred.html
        ->
          a as String
          other as String :=: PATH "a"
        <-
          response as HTTPResponse: () with trait of HTTPResponse

      //The same placeholder twice in one URI has no single meaning, so it is rejected outright.
      repeated() for :/{a}/{a}/repeated.html
        ->
          first as String :=: PATH "a"
          second as String :=: PATH "a"
        <-
          response as HTTPResponse: () with trait of HTTPResponse

Fixed: Bind each path variable once

#!ek9
defines module error.e07731.good

  defines class

    TextResponse with trait of HTTPResponse
      text as String?

      default private TextResponse()

      TextResponse()
        -> body as String
        this.text: body

      override contentType() as pure
        <- rtn as String: "text/plain"

      override content()
        <- rtn as Bytes: Bytes().withUtf8(text)

      override status() as pure
        <- rtn as Integer: 200

      default operator ?

  defines service

    Items for :/items open

      //Each variable bound exactly once
      pair() as GET for :/{a}/{b}/pair.html
        ->
          first as String :=: PATH "a"
          second as String :=: PATH "b"
        <- response as HTTPResponse: TextResponse(`${first} ${second}`)