The standard library now has all you need for advanced routing in Go.

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
since go 1.22 was released the net HTTP package is now all you need but knowing how to use the HTTP serve M type can be rather elusive especially for advanced features such as middleware sub routing path parameters HTTP methods and passing through context so in this video we're going to look at how to implement each of these using only the go standard Library the first implementation we're going to look at is path parameters to add a path parameter to a route is pretty similar to other Frameworks such as gorilla MX or Chi and involves wrapping the path component you want to parameterize in braces with the name of the parameter inside in this example we've added the path parameter of ID to our / item path with our parameter defined we can then pull this out inside of our Handler by using the path Value method of the request type if we run this code and send up the following requests our endpoint is now returning the last path component to us which is what's being captured in the ID path parameter one thing to note however is that in order to have access to path parameters you'll need to make sure you're using go 1.22 and that you have go 1.22 specified in your go mod file any earlier versions won't have access to this feature whilst setting up path parameters is rather simple there is one caveat to be aware of the caveat is conflicting paths and precedence for example here I have two routes that conflict with one another despite this however if I send a request to the path ending in/ latest it will still be routed to the correct Handler even though both of the registered paths match this works because go determines which path is correct based on a precedent ordering of most specific wins in our case that's the path that ends in/ latest in rare cases however it's difficult for go to determine which is the more specific path take the following two paths as an example if I sent up a request to/ posts SL latest which one would resolve in this case they're both as specific as each other each having one path parameter if we try and run this code however go will Det protect the conflict and panic when we try to register our paths ultimately this is a good thing as it prevents any requests being routed to the wrong Handler the next feature for advanced hdtp routing is the ability to easily handle different hdtp methods before version 1.22 this was done by having to perform a check on the request inside of the HTTP Handler whilst it worked it was pretty tedious now however it's pretty easy all we have to do is Define the method at the start of the matcher string by adding the post method to the start of the path the create monster Handler will only be invoked for requests that contain a post method method-based routing can also be set up for the other HTTP methods such as put get delete patch and options if a path has no explicit method defined then it will handle any methods that haven't been explicitly defined for that path for example here I have two entries to the/ monster slid endpoint the first is set up to explicitly handle a PCH request however the second has no explicit method defined and therefore will be routed to for any HTTP method that isn't a put in this example you can see the Handler is being called for get post delete and even patch in order to limit an endpoint to a method you'll need to explicitly Define it now when we send up any requests that aren't a get method we'll receive a response of method not allowed one thing to be aware of is that when defining a method for your path it requires a single space after it anything more than a single space will cause the route to no longer match as was the case with path parameters method-based routing also requires 1.22 to be specified inside of the Project's go mod file if an earlier version of go is specified then your expected endpoints will return a 44 the next Advanced routing feature is to perform handling based on a host name rather than just a path we can achieve this by passing in the host domain that we want the router to handle on in my case I'm setting this to be dreams of code. Vu which will handle any requests sent to that host we can test this locally with curl by passing in the host header however we can also make this a little more real world by using an actual domain but where to get one for an affordable price that's where the sponsor of this video can help us pork bun.com whether you need a domain to Showcase your latest app that will change the world or you just want to be the developer that ships pork bun has you covered porkbun offers TOS that are perfect for software development projects such asapp dodev and my personal favorite do Fu the best part is through this video's referral link you can get one of these domains for just $5 for the first year which is pretty much unheard of in this economy for this project I registered the dreams of code. Food domain with pork bun and by using pork Bun's intuitive UI I've easily managed to point the a records to the VPS server that I'm running my app on not only are these TOS affordable but they're also secure as each requires https in order to load forban again has us covered as they provide a free let's encrypt SSL CT with every domain name registration perfect for when you want to ship quickly without worrying about infrastructure we can add TLS by first copying over the SSL bundle to our server followed by extracting the archive then you'll want to copy over the domain seert and the private key into your project directory afterwards we can open up our main.go file and add in the following lines to create a TLS configuration from the certificate and private key we can then use this configuration with our server followed by telling it to listen with TLS lastly make sure to change the port to 443 now if we build and run our API we should be able to hit it at its domain using https great for getting started in production you'll probably want to automate the generation of SSL SS using something like cbot let me know if you want to see a video on that in the future whilst this app likely won't change the world we have managed to ship it with TLS enabled by using only the standard library and a Little Help from pork bun so to get your own domain for $5 use the promo code appdev fu5 or click the link in the description down below a big thank you to porkbun for sponsoring this video the next feature is actually the one that was most requested in my video about Go's 1.22 release this feature was middleware and how to add it with HTTP serve MX on initial thoughts it may seem that this feature is lacking but this is where the beauty of the net / HTTP package really shines let's look at how to do this by first adding in a simple logging middleware to do so let's first create a new function that accepts an HTTP Handler as its parameter and returns an HTTP Handler as its result the HTTP Handler type is actually an interface in the standard Library which describes any type that has the function serve HTTP these are the building blocks of HTTP routing when it comes to go inside of our middleware function we can then return a new HTTP Handler Funk this type allows us to easily wrap a closure conforming it to the HTTP Handler interface the code inside of this closure is what makes up the middleware logic and will be called for each request inside let's add a new variable to capture the start time of the request being handled then we'll pass the request and response down the Chain by calling the serve HTTP method of the next Handler afterwards we can then call the log. print line function passing in the request method the request path and the amount of time that has passed since the start timestamp this wraps up our actual middleware function now we need to add it into our routing stack to do so let's head on over to where our router is defined inside of main.go then in order to use our logging middleware we first need to import the middleware package now we're ready to add logging to each of our defined paths as the HTTP serm router conforms to the HTTP Handler interface then we can pass it as the argument to our middleware function this essentially creates a new router that is wrapped in the logging middleware now when we run this code and send up a couple of requests using curl we can see that each of these are logged to the server's standard out which prints the method path and time it took for the request to be handled one Improvement we can make is to also log the HTTP status of the response as well however if we try to do this we run into an issue the response writer type doesn't provide us a method to read the HTTP status code fortunately because this is an interface there is a way to expose it inside of our middleware package we can create a new type called a wrapped writer which itself extends an HTTP response writer but also contains a status code property we can then implement the right header method in order to intercept and capture the given HTTP status code then inside of our middleware we can use this new type to wrap the response writer provided to our middleware Handler we'll also set the status code to be HTTP status okay then we'll pass this waps writer to our next HTTP Handler then in our log. print line function we're able to access the status code found in the wrapped type now when we test this code we'll also see the response status code being printed to the console as well with that we've managed to easily add some middleware into our router however when building API Services you'll often use multiple when it comes to your middleware stack as this stack starts to grow your code will look less like go and more like lisp to tidy this up we can use something called middleware chaining which turns our code from looking like this into this to achieve this let's head on over to the middleware package and first Define a new type this will be the middleware type which is going to be a function that accepts an HTTP Handler as its input and returns an HTTP Handler this is the same function definition as our logging middleware next we can Define the method to wrap our middleware in our case this is going to be called create stack this method will accept a vartic array of middleware as its argument and return a middleware as its result for the implementation of this method let's first return our middleware closure then we can add the following implementation to apply each middleware in the stack this will cause us to return the topmost middleware which itself will Nest all of the subsequent middleware underneath now if we head on over to our main function we can then refactor our previously wrapped code using this create stack function if we go ahead and run this code we can see that our middleware chain works as it did before but now our code is just that little bit more readable the next feature to implement is sub routing which enables us to split our routing logic across multiple routers to see how to implement this let's first start with this example which is a simple router that has some paths already configured to perform crud operations on a monster resource let's say we receive a ticket that specifies that this API should be versioned under a V1 path prefix instead of adding this prefix to each path manually we can use another router to achieve this to do so we can call the handle function on our new router passing in the V1 path prefix in order for this to work it needs to have the trailing slash as well for the Handler we need to use the HTTP strip prefix function to remove the SL V1 From the Path before it's sent to our next router now when I run this code and send up a couple of Cur requests to the slv1 monsters end points we can see that our requests are being handled as expected as well as nesting paths sub routers are also useful when it comes to Middle W for example in this case I have two different routers one that's intended to be used by anybody and the other containing routes that are restricted to admins only in order to require authorization to our admin routes we can add the following Handler to our router wrapping the admin routes in the ensure admin middleware if we then go ahead and test this out we can see that our get request doesn't require an admin credential but our post requests do the last feature I want to look at is how to pass data down through your routing stack for example let's say we have an isauthenticated middleware that will pull out and validate the user's information from an authorization header let's improve this middleware by making the user ID available to any Downstream handlers we can achieve this by making use of the context type from the context package normally this type is used for cancellation in asynchronous tasks but it also enables the ability to store arbitrary data using key values every HTTP request has an Associated context which we can easily extend and override to do so let's head back back on over to our middleware code and first import the context package next we need to define a unique key that we can use to both set and get this value from our requests context then scrolling down to our middlewares Handler let's first remove the log. print line and replace it with the following code this line calls the with Value method of the context package taking in the requests context our new key and our user ID value this method returns a new child context which contains the key value pair inside therefore we need to assign this new context value to our request we can do so using the with context method passing in our new context value this will return a new copy of the request that contains this new context therefore we need to pass this new value down to the next Handler that wraps up the implementation in our mware now we need to pull the user ID out of the context in the Handler function if we navigate over to the Handler where we want to pull out this user ID we can do so by adding in the following line because the context. context stores values in a type unsafe manner we'll need to perform a typ cast by adding in the following code at the end of the line we can verify that this type cast was okay by capturing a second return value which is a Boolean describing whether or not the cast was successful now if we run this code and send up a cur request with an authorization header our Handler is able to access the user ID contained due to the middleware extracting the value with that we've managed to implement Advanced routing capabilities by only using the standard library for some things you may still want to consider using a third party package however if you decide you want to stick with the standard Library the net / HTTP package now has everything you need I want to give a big thank you to my newest Channel member Eduardo Diaz thank you for supporting the channel and allowing me to bring my content to hundreds of thousands of viewers around the world
Info
Channel: Dreams of Code
Views: 101,139
Rating: undefined out of 5
Keywords:
Id: H7tbjKFSg58
Channel Id: undefined
Length: 13min 52sec (832 seconds)
Published: Sat Mar 23 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.