What are the rules for valid service URI paths and method mapping?

← Web Services · Ref: Q684

EK9 services map URI paths to methods and operators. Several rules govern valid service definitions to prevent runtime routing errors.

VALID URI PATHS (E07790)

Service paths must follow URI syntax. The base path is declared on the service name, and each method adds a relative path:

  ProductService :/products
    listAll() as GET for :/all

Invalid paths (missing colon, empty segments) trigger E07790.

NO DUPLICATE ENDPOINTS (E07800)

Two methods or operators cannot map to the same HTTP verb and path combination. Each endpoint must be unique within the service.

PATH PARAMETER MATCHING (E07820)

Path parameters like '/{productId}' must have a corresponding method parameter:

  findById() as GET for :/{productId}
    -> productId as String

Missing the parameter in the method signature triggers E07820.

METHOD PARAMETER RULES (E07860)

Service method parameters have specific type requirements. Path parameters must be String type.

See Q657 for URI mapping basics. See Q658 for path parameter binding. See Q659 for service return types.

Example

defines module qa.webdeep.uripaths

  defines constant

    JSON_CONTENT_TYPE <- "application/json"
    ENGLISH_LANGUAGE <- "en"

  defines service

    <?-
      Service demonstrating valid URI paths with distinct endpoints.
      Base path plus method-level paths, all unique.
    -?>
    ProductService :/products open

      //GET /products/featured — no path params
      featured() as GET for :/featured
        <- response as HTTPResponse: () with trait HTTPResponse
          override content()
            <- rtn as String: `["featured-item"]`
          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=120"
          override contentLanguage() as pure
            <- rtn as String: ENGLISH_LANGUAGE
          default operator ?

      //GET /products/{productId} — path param matches method param
      findById() as GET for :/{productId}
        -> productId as String
        <- response as HTTPResponse: (capturedId: productId) 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 /products/{categoryName}/items — different path, no conflict
      byCategory() as GET for :/{categoryName}/items
        -> categoryName as String
        <- response as HTTPResponse: (capturedCategory: categoryName) with trait HTTPResponse
          override content()
            <- rtn as String: `{"category": "${capturedCategory}"}`
          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

    ProductApp
      register ProductService()

  defines program

    ServiceUriPathsDemo()
      stdout <- Stdout()
      stdout.println("Service URI paths:")
      stdout.println("  GET /products/featured")
      stdout.println("  GET /products/{productId}")
      stdout.println("  GET /products/{categoryName}/items")

Common mistakes

E50001 — The function getUriPaths is not defined in this module. See ek9 -h E50001 for details.

Incorrect:

stdout.println(getUriPaths())

Correct:

stdout.println("Service URI paths:")

E50001 — The function getFeaturedPath is not defined in this module. See ek9 -h E50001 for details.

Incorrect:

stdout.println(getFeaturedPath())

Correct:

stdout.println("  GET /products/featured")
Other ways to ask this
  • What is E07790 invalid service URI path?
  • What is E07800 duplicate service endpoint?
  • What is E07820 path parameter not in method signature?
  • What is E07860 service method parameter error?

Coming from another language?

Java: @RequestMapping with @PathVariable annotations. Python: Flask @app.route('/path/<param>'). Go: gorilla/mux with {param} syntax. Rust: Actix web::resource().route(). EK9: service-level :/path syntax with compile-time validation of path-to-parameter binding.

Keywords: E07800, E07790, function, service, URI, duplicate, dict, endpoint, http, path, E07820, REST, E07860