labstack / echo

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

Routing based on Header values #286

Closed mertenvg closed 8 years ago

mertenvg commented 8 years ago

I have a use case where I would like to attach multiple handlers to the same path but select the correct handler based on a selected Header value. Does something exist (recipe or feature) for this already. If not, would this be considered part of the echo scope if I add it and create a pull request?

vishr commented 8 years ago

The handler is matched entirely based on request method and path. This is a very specific case and I would consider it to be handled outside of the framework.

CaptainCodeman commented 8 years ago

That doesn't sound like a generally-useful feature for the router to have ... maybe you can explain your use case more - what are the differences in the handlers? It may be that you can do what you need with some middleware instead.

mertenvg commented 8 years ago

The case I'm thinking of in particular is for XMLHttpRequests. The function of the endpoint remains the same but the handling of such a request (in particular the response) may be very different.

I've considered using middleware to modify the route when a specific header is encountered but if I'm not mistaken the handler is selected before the middleware is fired so modifying the path at this point will have no impact on the routing mechanism. Aside from the fact that this approach strikes me as being more of a hack than conscientious design.

Perhaps a more generic solution whereby an echo user can provide his/her own matcher function (returns a bool indicating a match or not) would allow for more granular control over routes without infringing too much on the inner workings of echo.

CaptainCodeman commented 8 years ago

You still haven't provided much of the actual use case, just a hint at the format which may be irrelevant - how is it handled differently and what header changes it and why? Why does it need to be a different handler and not something within the handler? It really comes down to this: at what point should it really be a different handler (that the client requests).

You could have a single endpoint for every app and add something to the http headers to indicate what response is needed, It could be called "X-URL" ... (joke)

There is a hook now which allows you to change the request before the route matching - look at the echo.Hook method. It may do what you need.

mertenvg commented 8 years ago

Ok some details. I have a form that will be submitted either through standard http request or when javascript is enabled be handled through an XMLHttpRequest (to the same form action endpoint). This sends me a "X-Request-With" header that I would like to match so that a different handler can be used for the ajax request.

In the case of the standard http request I need to create a context (for the entire page) and rerender the entire page template. For the the XMLHttpRequest only a small portion of the context and a specific sub-template is required in the response.

Granted a conditional statement would also work when using a single handler for both cases but this is a slippery slope to spaghetti code imho. I prefer to have my handlers devoted to a specific responsibility / use case which leads me to my 2 handlers 1 endpoint problem.

Will take a look at the echo.Hook (no rhyme intended), thanks.

CaptainCodeman commented 8 years ago

That sounds like it's mostly 'content negotiation' to decide the format for the response (with the slight complication of having more to render for the full html rendered page I'm guessing ?).

A good pattern for making this neat and avoiding duplications and lots of if / then blocks is the hexagonal / ports and adapters / onion architecture / clean code structure (yeah, it's known by many names). The parsing of web parameters and rendering responses is one implementation detail separate to the core "use case" (sometimes called 'interactor') of handling the logic. If you can separate out this core code it's simpler to create alternative wrapper for it and it also makes testing much easier as a side benefit.

mertenvg commented 8 years ago

Thanks @CaptainCodeman. I'll definitely take a look at the structure you mentioned. It's possible I've used it before without realising but don't recognise the name(s) you mentioned. It's google time :smile: