Routing is a core component of building web services of all kinds. With the release of go 1.22, the routing capabilities of the standard library net/http
package has gained powerful new features that remove the need for third-party routing tools for many applications.
Basic pattern matching
A pattern is a string with the format METHOD HOST/PATH
, used to match HTTP requests to handlers on an http.ServeMux
. Everything except the first slash between HOST
and PATH
is optional. Omitted parts match any value, for example the pattern /foo
will match all request methods and hosts for path /foo
, while the pattern POST sample.com/foo
will only match a POST
request to path /foo
on host sample.com
.
If a pattern ends with a slash /
, it will match any path prefixed by the pattern. The pattern /img
will only patch requests for the path /img
, but the pattern /img/
will match requests for any path starting with /img/
, like /img/1.jpg
or /img/logos/square/large.png
. It should be noted that a path with and without trailing slash are treated as separate: if both patterns /img
and /img/
are registered at the same time, they will work as expected. If only pattern /img/
is registered, then a request for path /img
will redirect to /img/
instead.
The trailing slash behavior is also true for the pattern /
, which will match requests for any path, making it suitable for a 404 Not Found page.
Limiting matches
Pattern matching can be limited using the special {$}
marker. It can be used in a pattern to mark the end of a request path, so that only paths are matched that end where the marker in the pattern is. For example, the pattern /{$}
will only match the literal path /
. This can also be used to disable the trailing slash behavior for other patterns, for example the pattern /img/{$}
will only match the literal path /img/
.
Matching precedence
When multiple patterns would match a request, the more specific one takes precedence. A pattern is considered more specific if it matches less requests than the other one(s). For example, if both patterns /static/
and /static/img/
are registered at the same time, the second one will match all paths starting with /static/img/
, while the first one will match all other paths starting with /static/
.
Extracting path variables
The last missing piece for common routing needs is the ability to extract path segments as variables. Suppose you wanted to construct a handler that serves blog posts at a generic url like /post/15
, where 15
is the id of the blog post to show. A pattern to match this use case would look like this: /post/{id}
. The {id}
part of the pattern signals that the path segment at this position should be extracted as a variable by name id
. The value for the actual path can then be retrieved using the *http.Request
object that was passed to the handler:
http.HandleFunc("/post/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
})
It is important to note that this syntax will only match one path segment - it will neither match multiple path segments like /post/15/comments
. To catch all path segments until the end of the path, the special ... syntax can be appended to the variable name. Using this, the pattern /static/{file...}
with a request for path /static/img/one.png
would provide value img/one.png
when calling r.Pathvalue("file")
.
With these additions to the standard library routing functionality, the gap to popular third-party routing packages like gorilla/mux has been reduced significantly, and many applications may not need to rely on packages outside the standard library anymore at all. While the most common needs are now covered with the pattern matching additions, more advanced needs like matching partial path segments or regular expressions still require the use of a more complex routing module.