How To Validate Url In Go

Validation is part of every programmer life, especially when working on backend services, validation must be done right. In this blog post we talk about how to properly validate a URL in Go (Golang).
URL stands for Unique Resource Locator, and is a sub-type of URI (even though many people interchangeably use the two terms). A URL is a reference to a web resource, typically seen as a web address (eg https://golang.org/project/)

Below you can see the structure of a URL, which conforms with he structure of a URI

URI = scheme:[//authority]path[?query][#fragment]
authority = [userinfo@]host[:port]

How do you validate a URL in Go (Golang)?

I’ve always been impressed by the number of native packages in the Go standard library. Also this time we have a package that fulfils our needs. The net/url package https://golang.org/pkg/net/url/

We can use url.ParseRequestURI in order to validate our URL

func ParseRequestURI(rawurl string) (*URL, error)

The behaviour is described below

ParseRequestURI parses rawurl into a URL structure. It assumes that rawurl was received in an HTTP request, so the rawurl is interpreted only as an absolute URI or an absolute path. The string rawurl is assumed not to have a #fragment suffix. (Web browsers strip #fragment before sending the URL to a web server.)

Caveat: ParseRequestURI vs Parse

There is also another method that is supposed to be used for Parsing URL strings, but there are some caveats. It allows relative URLs making the validation a bit more loose. It’s url.Parse

func Parse(rawurl string) (*URL, error)

As described on the docs

Parse parses rawurl into a URL structure.
The rawurl may be relative (a path, without a host) or absolute (starting with a scheme). Trying to parse a hostname and path without a scheme is invalid but may not necessarily return an error, due to parsing ambiguities.

Parse URL Example

Let’s see now an example on how to parse and validate a URL in Go using ParseRequestURI

package main

import (
  "log"
  "net/url"
)

func main() {
  u, err := url.ParseRequestURI("hi/there?")	
  log.Printf("hi/there?: err=%+v url=%+v\n", err, u)
  
  u, err = url.ParseRequestURI("http://golang.cafe/")	
  log.Printf("hi/there?: err=%+v url=%+v\n", err, u)
  
  u, err = url.ParseRequestURI("http://golang.org/index.html?#page1")	
  log.Printf("hi/there?: err=%+v url=%+v\n", err, u)
  
  u, err = url.ParseRequestURI("golang.org")	
  log.Printf("hi/there?: err=%+v url=%+v\n", err, u)
}

Which outputs the following

2009/11/10 23:00:00 hi/there?: err=parse hi/there?: invalid URI for request url=<nil>
2009/11/10 23:00:00 hi/there?: err=<nil> url=http://golang.cafe/
2009/11/10 23:00:00 hi/there?: err=<nil> url=http://golang.org/index.html?#page1
2009/11/10 23:00:00 hi/there?: err=parse golang.org: invalid URI for request url=<nil>
Join the Golang Developers Community on Golang Cafe