beer-api package¶
A beer-manager API including user reviews, favorites lists, and glass-styles. Built on Python3.3 with the Flask microframework and SQLAlchemy.
Dependencies: Python3.3, SQLite3. Needed python packages are listed in requirements.txt, pass this to PIP for easy installation.
Installation Instructions¶
- Clone the GitHub repository git clone https://github.com/binaryatrocity/beer-api.git
- Move into the app’s directory cd beer-api
- Create a Python3 virtual environment pyvenv-3.3 venv
- Activate the new environment source venv/bin/activate
- Download easy_install setup file wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py
- Install easy_install into the venv venv/bin/python ez_setup.py
- Use easy_install to setup PIP venv/local/bin/easy_install pip
- Let PIP handle requirements file venv/local/bin/pip install -r requirements.txt
- Cleanup some setup files rm ez_setup.py; rm setuptools*.zip
- Build SQLite3 database for operation ./run.py –builddb
- Run API with Flask development server ./run.py
This will run the application with the Flask development server, appropriate for testing. The API will be available externally from http://YOURDOMAIN.tld:5000/beer/api/v0.1/. Additional instructions for letting Apache serve the API are below.
Apache HTTPD WSGI Instructions (Untested with pyvenv3.3)¶
- Install mod_wsgi for Apache if needed pacman -S libapache2-mod-wsgi OR apt-get install libapache2-mod-wsgi
see http://code.google.com/p/modwsgi/wiki/QuickInstallationGuide for other installation methods
Create a new Apache VirtualHost for the API reference http://flask.pocoo.org/docs/deploying/mod_wsgi/#configuring-apache for example file
Enable the new Apache host sudo a2ensite <virtualHostFilename>
Restart Apache httpd to enable new configuration
API Endpoint Routes¶
- app.routes.get_auth_token()[source]¶
Generates an authentication token for current user. Pass the token as username with an empty password as an alternate means of authentication.
URL: /beer/api/v0.1/tokenMethod: GETQuery Args: NoneAuthentication: Password Only
- app.routes.list_users()[source]¶
List all users in the database.
URL: /beer/api/v0.1/usersMethod: GETQuery Args: sort_by=<column name> <desc?>Authentication: NoneExamples:
Get list of users
GET http://domain.tld/beer/api/v0.1/users
Sorted by creation date
GET http://domain.tld/beer/api/v0.1/users?sort_by=created_on
Sorted by username descending
GET http://domain.tld/beer/api/v0.1/users?sort_by=username%20desc
- app.routes.get_user(id)[source]¶
Retrieve information about a particular user.
URL: /beer/api/v0.1/users/<user_id>Method: GETQuery Args: NoneAuthentication: NoneExample:
Get data for user with id# 5
GET http://domain.tld/beer/api/v0.1/users/5
- app.routes.get_user_reviews(id)[source]¶
Return list of reviews authored by a particular user.
URL: /beer/api/v0.1/users/<user_id>/reviewsMethod: GETQuery Args: sort_by=<column_name> <desc>Authentication: NoneExample:
Get reviews for user with id# 2
GET http://domain.tld/beer/api/v0.1/users/5/reviews
Get reviews for user with id# 1 sorted by aroma
GET http://domain.tld/beer/api/v0.1/users/5/reviews?sort_by=aroma
- app.routes.create_user()[source]¶
Creates a new user and saves it to the database.
URL: /beer/api/v0.1/usersMethod: POSTQuery Args: NoneAuthentication: NoneExpected Data: username, passwordOptional Data: emailExample:
Create user ‘john’ with password ‘suchsafety’ and email ‘john@inter.net’
POST http://domain.tld/beer/api/v0.1/users data={"username":"john", "email":"john@inter.net", "password":"suchsafety"}
- app.routes.edit_user(id)[source]¶
Allows editing of a user in the database.
URL: /beer/api/v0.1/users/<user_id>Method: PUTQuery Args: NoneAuthentication: Token/PasswordOptional Data: email, username, passwordExample:
Edit user with id#1, change email to ‘john@newisp.com’
PUT http://domain.tld/beer/api/v0.1/users/1 data={"email":"john@newisp.com"}
- app.routes.delete_user(id)[source]¶
Delete a user from the database.
URL: /beer/api/v0.1/users/<user_id>Method: DELETEQuery Args: NoneAuthentication: Token/PasswordExample:
Delete user with id# 4
DELETE http://domain.tld/beer/api/v0.1/users/4
- app.routes.list_glasses()[source]¶
List glass types in the database.
URL: /beer/api/v0.1/glassesMethod: GETQuery Args: sort_by=<column name> <desc>Authentication: NoneExample:
List all glass styles in the database
GET http://domain.tld/beer/api/v0.1/glasses
List glass styles by name descending
GET http://domain.tld/beer/api/v0.1/glasses?sort_by=name%20desc
- app.routes.get_glass(id)[source]¶
Get data about a particular glass in the database.
URL: /beer/api/v0.1/glasses/<glass_id>Method: GETQuery Args: NoneAuthentication: NoneExample:
Get data about glass with id# 3
GET http://domain.tld/beer/api/v0.1/glasses/3
- app.routes.create_glass()[source]¶
Add a new glass type to the database.
URL: /beer/api/v0.1/glassesMethod: POSTQuery Args: NoneAuthentication: Token/PasswordExpected Data: nameExample:
Create a glass-type with name ‘tumbler’
POST http://domain.tld/beer/api/v0.1/glasses data={"name":"tumbler"}
- app.routes.edit_glass(id)[source]¶
Edit the name of a glass-type.
URL: /beer/api/v0.1/glasses/<glass_id>Method: PUTQuery Args: NoneAuthentication: Token/PasswordExample:
Rename glass with id# 2 to ‘Goblet’
PUT http://domain.tld/beer/api/v0.1/glasses/2 data={"name":"Goblet"}
- app.routes.delete_glass(id)[source]¶
Delete a glass-type from the database.
URL: /beer/api/v0.1/glasses/<glass_id>Method: DELETEQuery Args: NoneAuthentication: Token/PasswordExample:
Delete glass-type with id# 5
DELETE http://domain.tld/beer/api/v0.1/glasses/5
- app.routes.list_beers()[source]¶
List all of the beers in the database.
URL: /beer/api/v0.1/beersMethod: GETQuery Args: sort_by=<column_name> <desc>Authentication: NoneExample:
List all beers in the system
GET http://domain.tld/beer/api/v0.1/beers
Sort beers by ABV%
GET http://domain.tld/beer/api/v0.1/beers?sort_by=abv
Sort beers by calories descending
GET http://domain.tld/beer/api/v0.1/beers?sort_by=calories%20desc
- app.routes.get_beer(id)[source]¶
Get data about a particular beer.
URL: /beer/api/v0.1/beers/<beer_id>Method: GETQuery Args: NoneAuthentication: NoneExample:
Return data about beer with id# 5
GET http://domain.tld/beer/api/v0.1/beers/5
- app.routes.get_beer_reviews(id)[source]¶
Return list of reviews about a particular beer.
URL: /beer/api/v0.1/beers/<beer_id>/reviewsMethod: GETQuery Args: NoneAuthentication: NoneExample:
Retrieve list of reviews about beer with id# 2
GET http://domain.tld/beer/api/v0.1/beers/2/reviews
Get reviews of beer with id# 4 sorted by taste descending
GET http://domain.tld/beer/api/v0.1/beers/4/reviews?sort_by=taste desc
- app.routes.create_beer()[source]¶
Add a new beer to the database and return the object.
URL: /beer/api/v0.1/beersMethod: POSTQuery Args: NoneAuthentication: Token/PasswordExpected Data: name, style, abvOptional Data: brewer, ibu, calories, brew_location, glass_typeExample:
Create a beer named ‘Mayan Chocolate’ by ‘Mobcraft Beers’, style ‘Chocolate Chili Ale’, abv 6.3%
POST http://domain.tld/beer/api/v0.1/beers data={"name":"Mayan Chocolate", "style":"Chocolate Chili Ale", "brewer":"Mobcraft", "abv":6.4}
Create a beer named ‘Riverwest Stein’ style ‘Amber Lager’ abv 5.6% linked to glass_type 2
POST http://domain.tld/beer/api/v0.1/beers data={"name":"Riverwest Stein", "glass_type":"http://domain.tld/beer/api/v0.1/glasses/2", "abv":5.6, "style":"Amber lager"}
Create a beer named ‘African Amber’ style ‘Amber Ale’ abv 4.6% brewer ‘Mac & Jacks’ linked to glass_type 4
POST http://domain.tld/beer/api/v0.1/beers data={"abv":5.6, "style":"Amber Lager", "glass_type":4, "name":"African Amber"}
- app.routes.edit_beer(id)[source]¶
Edit an existing beer in the database.
URL: /beer/api/v0.1/beers/<beer_id>Method: PUTQuery Args: NoneAuthentication: Token/PasswordOptional Data: brewer, ibu, calories, brew_location, glass_type, brewer, style, abvExample:
Change the abv value of beer with id# 23 to 3.4
PUT http://domain.tld/beer/api/v0.1/beers/23 data={"abv":3.4}
Change the style and brew_location of beer with id# 6
PUT http://domain.tld/beer/api/v0.1/beers/6 data={"style":"Pale Ale", "brew_location":"Milwaukee, WI"}
- app.routes.delete_beer(id)[source]¶
Remove a particular beer from the database.
URL: /beer/api/v0.1/beers/<beer_id>Method: DELETEQuery Args: NoneAuthentication: Token/PasswordExample:
Delete the beer with id# 4
DELETE http://domain.tld/beer/api/v0.1/beers/4
- app.routes.list_reviews()[source]¶
Return a list of all reviews in the database.
URL: /beer/api/v0.1/reviewsMethod: GETQuery Args: sort_by=<column_name> <desc>Authentication: NoneExamples:
List all reviews in the system
GET http://domain.tld/beer/api/v0.1/reviews
List reviews sorted by aroma rating
GET http://domain.tld/beer/api/v0.1/reviews?sort_by=aroma
- app.routes.get_review(id)[source]¶
Return data about a specific review.
URL: /beer/api/v0.1/reviews/<review_id>Method: GETQuery Args: NoneAuthentication: NoneExample:
Get data about review with id# 5
GET http://domain.tld/beer/api/v0.1/reviews/5
- app.routes.create_review()[source]¶
Post a new review to the database. Return the review object.
URL: /beer/api/v0.1/reviewsMethod: POSTQuery Args: NoneAuthentication: Token/PasswordExpected Data: beer_id, aroma, appearance, taste, palate, bottle_styleExample:
Review beer with id# 4 with scores, 3, 3, 8, 4, 1
POST http://domain.tld/beer/api/v0.1/reviews data={"beer_id":4, "aroma":3, "appearance":3, "taste":8, "palate":4, "bottle_style":1}
Review beer with id# 2 with scores, 1, 1, 5, 5, 5
POST http://domain.tld/beer/api/v0.1/reviews data={"aroma":"1", "appearance":"1", "taste":"5", "palate":"5", "bottle_style":"5", "beer_id":"http://domain.tld/beer/api/v0.1/beers/2"}
- app.routes.edit_review(id)[source]¶
Edit an existing review.
URL: /beer/api/v0.1/reviews/<review_id>Method: PUTQuery Args: NoneAuthentication: Token/PasswordOptional Data: aroma, appearance, taste, palate, bottle_styleExample:
Change the aroma score to ‘5’ on review with id# 3
PUT http://domain.tld/beer/api/v0.1/reviews/3 data={"aroma":5}
Change the scores of review with id# 1
PUT http://domain.tld/beer/api/v0.1/reviews/1 data={"aroma":"5", "appearance":"1", "taste":"3", "palate":"3", "bottle_style":"2"}
- app.routes.delete_review(id)[source]¶
Delete a review from the database.
URL: /beer/api/v0.1/reviews/<review_id>Method: DELETEQuery Args: NoneAuthentication: Token/PasswordExample:
Delete the review with id# 3
DELETE http://domain.tld/beer/api/v0.1/reviews/3
- app.routes.get_user_favorites(id)[source]¶
Return a list of users favorite beers.
URL: /beer/api/v0.1/users/<user_id>/favoritesMethod: GETQuery Args: NoneAuthentication: NoneExample:
Retrieve a list of favorites for user with id# 12
GET http://domain.tld/beer/api/v0.1/users/12/favorites
- app.routes.create_user_favorites_list(id)[source]¶
Create a fresh list of favorite beers for a user.
URL: /beer/api/v0.1/users/<user_id>/favoritesMethod: POSTQuery Args: NoneAuthentication: NoneExpected Data: beers (list of id’s)Example:
Create favorites list including beers with id#’s 2, 6, 3, 19 for user with id# 5
POST http://domain.tld/beer/api/v0.1/users/5/favorites data={"beers":["2", 6, 3, "http://domain.tld/beer/api/v0.1/beers/19"]}
- app.routes.edit_user_favorites(id)[source]¶
Add or remove a particular beer from a users favorites list.
URL: /beer/api/v0.1/users/<user_id>/favoritesMethod: PUTQuery Args: NoneAuthentication: Token/PasswordExpected Data: beer, actionExample:
Add beer with id# 8 to user with id# 3
POST http://domain.tld/beer/api/v0.1/users/3/favorites data={"beer":8, "action":"add"}
Remove beer with id# 2 from user with id# 3
POST http://domain.tld/beer/api/v0.1/users/3/favorites data={"beer":"http://www.domain.tld/beer/api/v0.1/beers/2", "action":"remove"}
Add a beer with id# 71 to user with id# 12
POST http://domain.tld/beer/api/v0.1/users/12/favorites data={"beer":71, "action":"add"}
- app.routes.delete_users_favorites_list(id)[source]¶
Delete a users entire favorites list.
URL: /beer/api/v0.1/users/<user_id>/favoritesMethod: DELETEQuery Args: NoneAuthentication: Token/PasswordExample:
Delete favorites list for user with id# 4
DELETE http://domain.tld/beer/api/v0.1/users/4/favorites
- app.routes.list_all_user_favorites()[source]¶
List favorites list for each user in database.
URL: /beer/api/v0.1/favoritesMETHOD: GETQuery Args: NoneAuthentication: Token/PasswordExample:
Get all favorites-list in system
GET http://domain.tld/beer/api/v0.1/favorites
- app.routes.before_request()[source]¶
Checks for Content-Type: application/json on all POST/PUT/DELETE routes.
- app.routes.after_request(response)[source]¶
Update a users last_activity field after each authenticated api request.
- app.routes.malformed_error(error)[source]¶
Returns a 400 error when recieving a malformed request. Adds any messages that have been flash()’ed.
- app.routes.not_found_error(error)[source]¶
Return a 404 error, usually when <int:id> in the route is not a valid id# for that model.
- app.routes.method_unallowed_error(error)[source]¶
Return a 405 error when an unsupported HTTP method is used on an endpoint.
Returns a 403 error when attempting to access data without authorization.
Database Models¶
- app.models.is_model_id_or_uri(session, model, data)[source]¶
Return a valid model.primary_key or None.
Keyword arguments:
session – the SQLAlchemy sessionmodel – the db.Model class to lookupdata – the data to parse (expecting an int(id) or an api linkIf data is a digit, lookup that primary_key for model, otherwise try to parse the last chunk from an api ‘link’ uri.
- class app.models.User(username, email, password)[source]¶
Bases: flask_sqlalchemy.Model
Database model representing a single User.
Properties:
username – the users name/nickname.email – the users email address (unused).password – the users password hash.created_on – datetime from moment of creation.last_activity – datetime from last authenticated api call.last_beer_added – datetime from last added beer (for 24 hour limit).reviews – reviews writen by the User.favorites – list of User’s favorite beers.
- class app.models.Glass(name)[source]¶
Bases: flask_sqlalchemy.Model
Database model representing a style of beer Glass.
Properties:
name – The name of the glass-style (e.g. ‘Tumbler’)beers – List of beers that should be served in said glass-type
- class app.models.Beer(name, brewer, ibu, calories, abv, style, brew_location)[source]¶
Bases: flask_sqlalchemy.Model
Database model representing an individual Beer.
- class app.models.Review(beer_id, author_id, data)[source]¶
Bases: flask_sqlalchemy.Model
Database model representing a beer Review.
Properties:
aroma – Score category, 1-5appearance – Score category, 1-5taste – Score category, 1-10palate – Score category, 1-5bottle_style – Score category, 1-5