DominicHamon.com
Life is like a grapefruit
URL shortener in go
I recently combined all my various blogs into this one and then realised that, yet again, the length of my name is a pain. Especially when it comes to URLs. I also realised that I’d never tried to build a URL shortener, so I did. Full source available here.
There are a few tutorials around about writing one in PHP, but I decided to use Go. The basic idea is the same.
Database setup
The URL shortener uses a single table with the following structure:
Field | Type | Null | Default | Extra |
---|---|---|---|---|
id | int(11) | No | None | AUTO_INCREMENT |
short | varchar(8) | No | None | |
long | varchar(64) | No | None | |
created | timestamp | No | CURRENT_TIMESTAMP | |
accessed | timestamp | No | 0000-00-00 00:00:00 | |
access_count | int(11) | No | 0 |
I think the fields are self-explanatory.
Code
The code itself is really simple. The idea is to handle every HTTP request and capture the path of the URI. Look the path up in the database, and return either a redirect or not found. I decided to use go-sql-driver for the mysql integration and gorilla mux for more advanced request routing.
func main() {
flag.Parse()
c, err := sql.Open("mysql", *user+":"+*pwd+"@("+*host+")/"+*db)
if err != nil {
log.Fatal("Failed to open sql dbConnection")
}
dbConn = c
defer dbConn.Close()
r := mux.NewRouter()
r.HandleFunc("/{shorturl}", Handler).Methods("GET")
http.Handle("/", r)
log.Fatal(http.ListenAndServe(":"+*port, nil))
}
As you can see, all we do in main is open the connection to the database given the passed-in connection parameters, then set up a simple request routing table.
func Handler(w http.ResponseWriter, r *http.Request) {
shorturl := mux.Vars(r)["shorturl"]
// lookup shorturl
var longurl string
var access_count int
err := dbConn.QueryRow("select `long`,`access_count` from `url` where short=?", shorturl).Scan(&longurl, &access_count)
switch {
case err == sql.ErrNoRows:
log.Printf("%q not found", shorturl)
http.NotFound(w, r)
case err != nil:
log.Fatal(err)
default:
access_count++
log.Printf("%q -> %q", shorturl, longurl)
http.Redirect(w, r, longurl, http.StatusFound)
}
}
The single handler is almost as straightforward. It queries the database to see if the short URL is registered and then either returns a redirect or not found, or fatals in the case of a SQL error. An extra feature that I might use later in a dashboard view is that it tracks the access count and last accessed time for each registered short URL.
We also don’t need to worry about little Bobby Tables as Go escapes the parameters for us.
Running
One final wrinkle is that I use Dreamhost for hosting and so can’t run a native Go server. However, with a little mod_rewrite trickery I can persuade Apache to forward requests to my server. Here’s the relevant lines of the .htaccess file:
RewriteEngine on
RewriteCond %{SERVER_PORT} !^4242$
RewriteRule ^(.*) http://%{SERVER_NAME}:4242%{REQUEST_URI} [R=301,L]
This ensures that the given port isn’t already the one our server is listening on, and then redirects to the host with the write port number.
Next steps
Currently, short URLs have to be added manually through a SQL interface. Ideally, there’d be some UI for adding short URLs, and maybe even generating them through some hash function. Though checking for and handling hash collisions in a database is a pain.
Posted on 2014/01/19 in coding, web | | Leave a comment
Leave a Reply Cancel reply
Your email address will not be published. Required fields are marked *
Comment
Name *
Email *
Website
Recent Posts
- London Calling
- The Rise and Fall of Ziggy Stardust
- The only winning move is not to play
- s/GOOG/TWTR/
- URL shortener in go
- All the small things
- gomud
- Hole hearted
- Typed data for performance boost
Archives
- April 2018
- May 2015
- August 2014
- February 2014
- January 2014
- November 2013
- September 2013
- June 2013
- May 2013
- March 2013
- February 2013
- December 2012
- November 2012
- September 2012
- May 2012
- March 2012
- January 2012
- September 2011
- May 2011
- April 2011
- February 2011
- January 2011
- December 2010
- November 2010
- October 2010
- September 2010
- August 2010
- July 2010
- June 2010
- May 2010
- April 2010
- March 2010
- February 2010
- January 2010
- December 2009
- November 2009
- October 2009
- July 2009
- May 2009
- April 2009
- March 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
Search
Search
Copyright © Dominic Hamon 2021. WordPress theme by Ryan Hellyer.