Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
3 tasks
archit-harness opened this issue Mar 27, 2024 · 3 comments
Closed
3 tasks

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

archit-harness opened this issue Mar 27, 2024 · 3 comments

Comments

@archit-harness
Copy link

archit-harness commented Mar 27, 2024

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

  • Dependencies installed
  • No typos
  • Searched existing issues and docs

Expected behaviour

Actual behaviour

Steps to reproduce

Working code to debug

package main

func main() {
}

Version/commit

@aldas
Copy link
Contributor

aldas commented Mar 27, 2024

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
Copy link
Author

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
Copy link
Contributor

aldas commented Mar 27, 2024

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants