URL Shortener

Building a simple URL shortener

Following the rant on how learning programming should be a more practical, code first experience, I created a small project to better illustrate my vision. It is a very simple API for a URL shortener created in Flask. The API is not implemented, but there are tests provided and I will also provide a separate solution to compare against your own.

Implementing this API will teach you a few important concepts:

The setup

This project is designed to be run and tested in a docker container. Well, two actually. What this means is that you don’t need to have python or flask installed on your operating system to be able to complete the exercises. Still, you’ll need docker and docker-compose.

You don’t need to understand how docker works, but you’ll need a few basic commands.

To run the server, execute:

$ link_shortener: docker-compose up --build

This will run the two docker containers, web and nginx. To see them, run docker ps:

$ link_shortener: docker ps
CONTAINER ID        IMAGE                 COMMAND                  CREATED             STATUS              PORTS                         NAMES
b9236681ed18        linkshortener_nginx   "nginx -g 'daemon ..."   15 seconds ago      Up 14 seconds       0.0.0.0:80->80/tcp, 443/tcp   linkshortener_nginx_1
7602d01a0fcc        linkshortener_web     "/usr/local/bin/gu..."   16 seconds ago      Up 14 seconds       8000/tcp                      linkshortener_web_1

To run the tests, you need to run the nose2 command inside the web container (while the containers are running, so do thi from a different terminal tab).

$ link_shortener: docker exec -it 7602d01a0fcc nose2
.......
----------------------------------------------------------------------
Ran 7 tests in 0.023s

OK

Of course, not your all tests will pass in the beginning.

You can interact with the service using curl to make GET and POST requests. I recommend using curl in the beginning to see what your code is actually doing, not just relying on the tests. For example:

$ link_shortener: curl http://0.0.0.0/ping
pong

HTTP

Hyper Text Transfer Protocol (HTTP) is the protocol that makes the web work. It’s based on HTTP Requests and Responses.

The most basic types of requests are GET and POST.

A GET result just asks for some data from the server by giving a URL and a list of params. For example, when you go to this article you do a GET request to https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol and no params.

A POST request is used to send data to the server, such as sending a username and password for logging in. You can read more about HTTP Requests here.

Each HTTP request sends back an HTTP Response, that contains (among others) a body and a status code. For example, for the wikipedia article linked earlier, the response body is the HTML code of the page, and the status code is 200 (meaning OK). Should the page not exist, you would get status code 404 (Not found).

You can also use curl to create HTTP. For example:

curl -L http://wikipedia.com

Makes a GET request to wikipedia and shows you the response, which is the actual page (html, css, js).

Requirements

You are going to build simplified version of an URL shortener service (not the web app itself), that should implement the following interface:

GET /ping
Should respond with 'pong'

This method is already implemented as an example and the corresponding test should pass.
This is a basic health check that the server is running.
POST /ping
Should respond with 'postpong'

Just making sure you can figure out POST requests too.
The body of the request should be ignored.
POST 'url=$URL' /add_url
Should respond with a string that represents the short link.
Should return a 500 status code if the URL is invalid.

The URL should be a valid http or https url.
The returned string should have a length of 10 and only contain lowercase letters and digits.
GET /$short_url
Should respond with the URL corresponding to the $short_url.
Should respond with a status code 404 if $short_url does not exist.

This is the way a shortened URL is visited.
GET /info/$short_url
Should respond a JSON with information about $short_link:
{
  url: the original url,
  short_url: the short_url,
  visits: the number of times the short link was visited

}
Should respond with a status code 404 if $short_url does not exist.

This is the way a shortened URL is visited.

Tech tips

Flask routing:

Accept GET and POST requests:

@app.route('/test', methods=['GET', 'POST'])

Tell GET and POST requests apart:

request.method == 'GET' # or 'POST'

Create dynamic route

@app.route('/<url>', methods=['GET'])
def visit_url(url):
  return url

Return HTTP error code. Default is 200 (HTTP OK).

@app.route('/<url>', methods=['GET'])
def visit_url(url):
  return 'Error', 404 # Returns 404 Not Found error code

Further steps

If you have completed the project and all tests are passing, but want to dig deeper, I suggest reading this for more ideas of features, or trying to implement a UI for it. I made a script that just calls /ping if you want to play around with it. You’ll need to install CORS for it to work, though, and obviously the docker containers need to be running. Be careful, it breaks some sites when it’s activated.