I use python as it was the easier yet fast enough language for me. Also, it's cross platform, easily dockerized, well maintained and with a lot of web resources and community.
I try to keep dependencies as it's minimum.
Every new POST urls are stored in memory.
- Non-existing route will return 404
- Non-existing identifier will return 404
- I do not validate url, so it's basically a string shortener. It's up to the user to make sure provided url is a working url.
I choose to store everything in a dictonnary key:value. Keys are blake2 hashes of urls. It's indempotent, so a url will always return the same shorten id.
I used blake as it was fast, support digest_size
so I could reduce it to 10 chars, and support salt. It's also future proof, as we can tweak identifiers (for exemple, increase length to 12 or 15).
The benefit of indempotency is a cleaner "database" (or dictonnary in this case). We don't store multiple keys for the same url. Less wasted space, faster search.
The drawback is less privacy because you can predict what key matches what url. IMO, it's not that bad, as URLshortener are not and should not be considered as a privacy feature. Though, as it will be used as privacy shield by some people who didn't read the docs, I used salt to stem this a bit.
Also, salt makes shorten urls unique to our service. Users could not reverse urls locally without the server.
Due to short notice I did not try to get bonus points, like autoredirect.
I was confused by your POST requirement "in url", while POST uses body to provide data. I choose to ignore it as body is the way to go.
During debug, I implemented an additional route GET /api/v1/list
which will return all urls and identifiers. I choose to keep it but it's a privacy risk and should be removed or hidden behind auth before going live.
I also used Vegeta to test my code and provided the template I used. Here is the results I got on my machine :
❯ cd vegeta-testing/
❯ vegeta attack -duration 300s -rate 100 -targets=target.list | tee results.bin | vegeta report
Requests [total, rate, throughput] 30000, 100.00, 100.00
Duration [total, attack, wait] 5m0s, 5m0s, 3.847ms
Latencies [min, mean, 50, 90, 95, 99, max] 767.096µs, 3.397ms, 3.711ms, 4.206ms, 4.405ms, 4.953ms, 19.254ms
Bytes In [total, mean] 705000, 23.50
Bytes Out [total, mean] 3660000, 122.00
Success [ratio] 100.00%
Status Codes [code:count] 200:30000
Error Set:
- Python3
- pip
- virtualenv
This will create a rest api server, listening on localhost:5000.
virtualenv element
source element/bin/activate
pip install -r requirements.txt
chmod +x server.py
./server.py
Do not change virtualenv name, or change it also in server.py line1.
Request a shorten url :
curl -H "Content-Type: application/json" -X POST -d '{"url":"https://verylongurl.com"}' localhost:5000/api/v1/shorten
Lookup a URL :
curl http://localhost:5000/api/v1/lookup/7848c90f5b
cd vegeta-testing/
vegeta attack -duration 300s -rate 100 -targets=target.list | tee results.bin | vegeta report
- Validate URL !
- Domain and Salt should be passed as a variable, not hardcoded, using os.getenv or similar
- Docker image
- persistent storage, for exemple with sqlite as it's light and portable