labstack / echo

High performance, minimalist Go web framework
https://echo.labstack.com
MIT License
29.01k stars 2.21k forks source link

How to read a path param with echo that can contain slashes? #2617

Closed archit-harness closed 3 months ago

archit-harness commented 3 months ago

Issue Description

Consider following example -

package main

import (
    "github.com/labstack/echo"
)
func main() {
    e := echo.New()

    e.Get("/:repo/:image/manifests/:reference", func(e *echo.Context) error {
        return nil
    })

    e.Run(":8080")
}

now i want the image field to contains slashes and be able to query 3 different path params, which are - repo, image and reference and only image can contain slashes.

How should i write my route?

Checklist

Expected behaviour

Actual behaviour

Steps to reproduce

Working code to debug

package main

func main() {
}

Version/commit

aldas commented 3 months ago

This is not possible with current router matching logic but you can achieve same result like that:

func main() {
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    // "/:repo/:image/manifests/:reference"
    e.GET("/:repo/:param", func(c echo.Context) error {
        param := c.Param("param")
        idx := strings.LastIndex(param, "/manifests/")
        if idx == -1 {
            return errors.New("invalid url")
        }
        image := param[0:idx]
        reference := param[idx+11:] // TODO: check if length is ok for idx+11

        repo := c.Param("repo")
        return c.JSON(http.StatusOK, map[string]string{
            "repo":      repo,
            "image":     image,
            "reference": reference,
        })
    })

    s := http.Server{
        Addr:    ":8080",
        Handler: e,
    }

    if err := s.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
        log.Fatal(err)
    }
}
archit-harness commented 3 months ago

Point is i had various routes for this for which i created different route file and handler which was clean.

Now to adopt this, would need to create switch/if cases based on whether param contains which field.

Like i have another route as -

g.GET("/:repo/:image/tags/list", handler.GetTags)

What do you recommend?

aldas commented 3 months ago

probably one handler that checks that param for specifics parts

    // "/:repo/:image/manifests/:reference"
    // "/:repo/:image/tags/list"
    e.GET("/:repo/:param", func(c echo.Context) error {
        repo := c.Param("repo")

        param := c.Param("param")
        idx := strings.LastIndex(param, "/manifests/")
        if idx != -1 {
            image := param[0:idx]
            reference := param[idx+11:] // TODO: check if length is ok for idx+11

            // call manifest handler ()
            return c.JSON(http.StatusOK, map[string]string{
                "repo":      repo,
                "image":     image,
                "reference": reference,
            })
        }

        idx = strings.LastIndex(param, "/tags/list")
        if idx == -1 {
            return errors.New("invalid url")
        }
        image := param[0:idx]

        // call tags list handler ()
        return c.JSON(http.StatusOK, map[string]string{
            "repo":  repo,
            "image": image,
        })
    })

This is limitation of Echo router. There exists routers that support regext etc. If this is a must-have feature then you are probably better of switching Echo with something else. Maybe https://github.com/go-chi/chi