Task: URL shortener




Go: 
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "math/rand"
    "net/http"
    "time"
)

const (
    chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
    host  = "localhost:8000"
)

type database map[string]string

type shortener struct {
    Long string `json:"long"`
}

func (db database) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    switch req.Method {
    case http.MethodPost: 
        body, err := ioutil.ReadAll(req.Body)
        if err != nil {
            w.WriteHeader(http.StatusBadRequest) 
            return
        }
        var sh shortener
        err = json.Unmarshal(body, &sh)
        if err != nil {
            w.WriteHeader(http.StatusUnprocessableEntity) 
            return
        }
        short := generateKey(8)
        db[short] = sh.Long
        fmt.Fprintf(w, "The shortened URL: http:
    case http.MethodGet: 
        path := req.URL.Path[1:]
        if v, ok := db[path]; ok {
            http.Redirect(w, req, v, http.StatusFound) 
        } else {
            w.WriteHeader(http.StatusNotFound) 
            fmt.Fprintf(w, "No such shortened url: http:
        }
    default:
        w.WriteHeader(http.StatusNotFound) 
        fmt.Fprintf(w, "Unsupprted method: %s\n", req.Method)
    }
}

func generateKey(size int) string {
    key := make([]byte, size)
    le := len(chars)
    for i := 0; i < size; i++ {
        key[i] = chars[rand.Intn(le)]
    }
    return string(key)
}

func main() {
    rand.Seed(time.Now().UnixNano())
    db := make(database)
    log.Fatal(http.ListenAndServe(host, db))
}




Python: 

import sqlite3
import string
import random

from http import HTTPStatus

from flask import Flask
from flask import Blueprint
from flask import abort
from flask import current_app
from flask import g
from flask import jsonify
from flask import redirect
from flask import request
from flask import url_for


CHARS = frozenset(string.ascii_letters + string.digits)
MIN_URL_SIZE = 8
RANDOM_ATTEMPTS = 3


def create_app(*, db=None, server_name=None) -> Flask:
    app = Flask(__name__)
    app.config.from_mapping(
        DATABASE=db or "shorten.sqlite",
        SERVER_NAME=server_name,
    )

    with app.app_context():
        init_db()

    app.teardown_appcontext(close_db)
    app.register_blueprint(shortener)

    return app


def get_db():
    if "db" not in g:
        g.db = sqlite3.connect(current_app.config["DATABASE"])
        g.db.row_factory = sqlite3.Row

    return g.db


def close_db(_):
    db = g.pop("db", None)

    if db is not None:
        db.close()


def init_db():
    db = get_db()

    with db:
        db.execute(
            "CREATE TABLE IF NOT EXISTS shorten ("
            "url TEXT PRIMARY KEY, "
            "short TEXT NOT NULL UNIQUE ON CONFLICT FAIL)"
        )


shortener = Blueprint("shorten", "short")


def random_short(size=MIN_URL_SIZE):
    
    return "".join(random.sample(CHARS, size))


@shortener.errorhandler(HTTPStatus.NOT_FOUND)
def short_url_not_found(_):
    return "short url not found", HTTPStatus.NOT_FOUND


@shortener.route("/<path:key>", methods=("GET",))
def short(key):
    db = get_db()

    cursor = db.execute("SELECT url FROM shorten WHERE short = ?", (key,))
    row = cursor.fetchone()

    if row is None:
        abort(HTTPStatus.NOT_FOUND)

    
    return redirect(row["url"], code=HTTPStatus.FOUND)


class URLExistsError(Exception):
    


class ShortCollisionError(Exception):
    


def _insert_short(long_url, short):
    
    db = get_db()

    if (
        db.execute("SELECT * FROM shorten WHERE url = ?", (long_url,)).fetchone()
        is not None
    ):
        raise URLExistsError(long_url)

    if (
        db.execute("SELECT * FROM shorten WHERE short = ?", (short,)).fetchone()
        is not None
    ):
        raise ShortCollisionError(short)

    with db:
        db.execute("INSERT INTO shorten VALUES (?, ?)", (long_url, short))


def make_short(long_url):
    
    size = MIN_URL_SIZE
    attempts = 1
    short = random_short(size=size)

    while True:
        try:
            _insert_short(long_url, short)
        except ShortCollisionError:
            
            if not attempts % RANDOM_ATTEMPTS:
                size += 1

            attempts += 1
            short = random_short(size=size)
        else:
            break

    return short


@shortener.route("/", methods=("POST",))
def shorten():
    data = request.get_json()

    if data is None:
        abort(HTTPStatus.BAD_REQUEST)

    long_url = data.get("long")

    if long_url is None:
        abort(HTTPStatus.BAD_REQUEST)

    db = get_db()

    
    cursor = db.execute("SELECT short FROM shorten WHERE url = ?", (long_url,))
    row = cursor.fetchone()

    if row is not None:
        short_url = url_for("shorten.short", _external=True, key=row["short"])
        status_code = HTTPStatus.OK
    else:
        short_url = url_for("shorten.short", _external=True, key=make_short(long_url))
        status_code = HTTPStatus.CREATED

    mimetype = request.accept_mimetypes.best_match(
        matches=["text/plain", "application/json"], default="text/plain"
    )

    if mimetype == "application/json":
        return jsonify(long=long_url, short=short_url), status_code
    else:
        return short_url, status_code


if __name__ == "__main__":
    
    app = create_app()
    app.env = "development"
    app.run(debug=True)