API template
DESCRIPTION
-
The
models
file can be found in the User class which serves as a basic template. It meets all the requirements essential to get started with. -
Each user has a
public_id
which is used as aunique identifier
when querying the database to prevent the case when people seek to find out how many users are stored in there and numerous other inconveniences.The values are generated byuuid.uuid4()
. -
@token_required
makes sure that before querying the user exist and has a valid token. Each token isencoded
using theconfig['SECRET_KEY']
and has a lifespan of 365 days by default. -
The encryption for passwords is done by
werkzeug.security
module and the algorithm used issha256
-
Usually during the development process, even if I know it is not ideal I like to tweak the database schema. To keep track of all those changes
flask-migrate
comes in handy. Once you update themodels.py
file run from the root directory.
python migrate.py db migrate
python migrate.py db upgrade
Getting started
First of all we have to establish a connection with the database. To do so fill those fields which can be found inside app/__init__.py
# DATABASE CREDENTIALS
ENGINE = 'mysql'
USERNAME = 'name'
PASSWORD = 'password'
HOST = 'localhost'
PORT = '3306'
DATABASE = 'api'
Then create the tables. Make sure that you run those command from the root folder
python migrate.py db init
python migrate.py db migrate
python migrate.py db upgrade
Endpoints
- Each one has a MethodView class file with the name of the model in
/api/endpoints
- Stand-alone routes are written in
endpoints/stand_alone_views
- After creating a new endpoint don't forget to import it in
__init__.py
Template for new endpoints
class Endpoint(MethodView):
def get(self, endpoint_id):
if endpoint_id is None:
# return a list of endpoints
pass
else:
# expose a single endpoint
pass
def post(self):
# create a new user
pass
def delete(self, endpoint_id):
# delete a single endpoint
pass
def put(self, endpoint_id):
# update a single endpoint
pass
endpoint_view = Endpoint.as_view('endpoint_api')
app.add_url_rule('/endpoint/', defaults={'endpoint_id': None},
view_func=endpoint_view, methods=['GET',])
app.add_url_rule('/endpoint/', view_func=endpoint_view, methods=['POST',])
app.add_url_rule('/endpoint/<int:endpoint_id>', view_func=endpoint_view,
methods=['GET', 'PUT', 'DELETE'])
Easy to customize content-delivery
For example the endpoint user GET
delivers its content as following
current_user = self.get_user_by_token()
if current_user.admin:
if public_id is None:
users = User.query.all()
output = []
for user in users:
user_data = {'public_id': user.public_id, 'email': user.email, 'password': user.password,
'admin': user.admin}
output.append(user_data)
return jsonify({'users': output}), 200
else:
user = User.query.filter_by(public_id=public_id).first()
if not user:
return jsonify({"message": "No user found!"}), 204
user_data = {'public_id': user.public_id, 'email': user.email, 'password': user.password,
'admin': user.admin}
return jsonify({"user": user_data}), 200
else:
if public_id is None:
return jsonify({"message": "Cannot perform that function!"}), 401
else:
if current_user.public_id == public_id:
user = User.query.filter_by(public_id=public_id).first()
if not user:
return jsonify({"message": "No user found!"}), 204
user_data = {'public_id': user.public_id, 'email': user.email, 'password': user.password,
'admin': user.admin}
return jsonify({"user": user_data}), 200
else:
return jsonify({"message": "Cannot perform that function!"}), 401
Response for user Endpoint
RESOURCE | GET | POST | PUT | DELETE |
---|---|---|---|---|
SUCCESS | 200 | 201 | 401 | 200 |
UNAUTHORISED | 401 | 401 | 401 | 401 |
ERROR | 404 | 404 | 404 | 404 |
NOT FOUND | 204 | 204 | 204 | 204 |