Golang: Building Dynamic URLs

Noah Kreiger
2 min readJun 24, 2021
https://undo.io/assets/thumbnail/600/840/890/webp/None/80/

You see a lot of stories on medium about how to do complex tasks or architect a production-level project. What you don’t see enough is how to do something as simple as building URLs with Golang, a task almost every micro-service does, however, nobody has a good way to do it…

In this tutorial, we will walk through how to build URLs cleanly, config-driven, and best of all, testable :). Let’s write some code.

First, we are going to define our struct, the struct will be our basis for building config-driven URLs. Almost every REST URL is made up of static (host, schema, etc) and dynamic parts (query and route parameters). The struct will host all of our static parts derived from the application configuration.

We will give the struct default values, but in a real-world application, I would recommend populating the struct through a config file.

From the example above you can see I am simulating a connection to the free, external REST API api.weatherapi.com.

Second, let’s define our first dynamic endpoint and than break it down piece by piece to make sure we truly understand it.

At the top, we have our Formatter return type, which is basically just defining what our method receiver will return. A string for the HTTP method, and the Golang built-in type url.URL as the second.

Next, we are creating our base url.URL object with the values held in the struct, since this is a go method receiver. These should be the config-driven static values that you add to that specific URL.

Below the static values, we are adding the dynamic query parameters to the URL, which we encode and assign.

Let’s take a look at our main.go integration with our new URL building receiver.

go run main.go
2021/06/22 22:36:51 GET
2021/06/22 22:36:51 https://api.weatherapi.com/forecast.json?dateKey=testDate&regionKey=testRegion

Wrapping the URL building functions in a struct allows you to easily combine static and dynamic values, with granular control over each route but the flexibility to handle any variation. Moreover, this strategy allows you to mock and test entire groups of routes at a time, that can be copied and pasted across micro-services. The functional response can easily become a parameter in other methods to attain the desired information, and you only have to update it in one place if you decide to make changes.

While this seems like a trivial part of the application, as you begin to add more and more APIs, the route building to connect them all can quickly get out of control. It is consistent strategies like these across your application that allow you to remain bug-free…and sane.

Thanks for reading!

--

--

Noah Kreiger

Software Engineer, DevOps Focus. Always learning and improving.