Last active
August 29, 2015 13:56
-
-
Save rochacon/9244596 to your computer and use it in GitHub Desktop.
Simple URL shortener built with Pyramid (just for fun)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
Simple URL shortener built with Pyramid. | |
# Setup | |
## Dependencies | |
* pyramid>=1.5a3 | |
* sqlalchemy>=0.9 | |
* pyramid_tm | |
* zope.sqlalchemy | |
* gunicorn (or another WSGI container) | |
## Setup DB | |
python -c "from shortener import create_app, Base; a = create_app(); Base.metadata.create_all(a.registry.dbmaker().bind)" | |
# Run | |
gunicorn shortener | |
""" | |
import random | |
import string | |
from pyramid.config import Configurator | |
from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPPreconditionFailed | |
from pyramid.view import view_config | |
from sqlalchemy import create_engine, Column, Integer, String | |
from sqlalchemy.ext.declarative import declarative_base | |
from sqlalchemy.orm import sessionmaker | |
from zope.sqlalchemy import ZopeTransactionExtension | |
# Model | |
Base = declarative_base() | |
class URL(Base): | |
__tablename__ = 'urls' | |
id = Column(Integer, primary_key=True) | |
key = Column(String(10), unique=True) | |
url = Column(String(255)) | |
@classmethod | |
def generate_key(cls): | |
return ''.join(random.choice(string.ascii_letters + string.digits) for x in range(10)) | |
# Views | |
def get_url(request): | |
key = request.matchdict.get('key') | |
url = request.db.query(URL).filter_by(key=key).first() | |
if url is None: | |
raise HTTPNotFound() | |
# TODO return would be better for the redirect | |
raise HTTPFound(url.url) | |
def put_url(request): | |
if 'url' not in request.json: | |
raise HTTPPreconditionFailed() | |
url = URL(key=URL.generate_key(), url=request.json['url']) | |
request.db.add(url) | |
return {'url': url.url, 'key': url.key} | |
def delete_url(request): | |
key = request.matchdict.get('key') | |
url = request.db.query(URL).filter_by(key=key).first() | |
if url is None: | |
raise HTTPNotFound() | |
request.db.delete(url) | |
return {} | |
def list_urls(request): | |
urls = request.db.query(URL).all() | |
return [{"key": u.key, "url": u.url, "href": request.route_url('url', key=u.key)} for u in urls] | |
# App | |
def create_app(): | |
cfg = Configurator() | |
cfg.include('pyramid_tm') | |
engine = create_engine('sqlite:///pyramidurlshortener.db') | |
cfg.registry.dbmaker = sessionmaker(bind=engine, extension=ZopeTransactionExtension()) | |
def db(request): | |
"""db request method""" | |
maker = request.registry.dbmaker | |
session = maker() | |
def cleanup(request): | |
session.close() | |
request.add_finished_callback(cleanup) | |
return session | |
cfg.add_request_method(db, reify=True) | |
cfg.add_route('root', '/') | |
cfg.add_view(list_urls, route_name='root', renderer='json', request_method='GET') | |
cfg.add_view(put_url, route_name='root', renderer='json', request_method='PUT') | |
cfg.add_route('url', '/{key}') | |
cfg.add_view(get_url, route_name='url', request_method='GET') | |
cfg.add_view(delete_url, route_name='url', renderer='json', request_method='DELETE') | |
return cfg.make_wsgi_app() | |
application = create_app() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment