What I have here is a relatively simple endpoint for a small site I’m making. Idea is to take:
and create an entry in the database. It works properly.
I threw this together as something that should work and tried to make it clean (like with the error list that gets returned) but clearly I’m doing this all by hand. Are there best practices for writing these API-style endpoints that I’m not following?
I looked under the hood at a few sites (such as SO) and noticed they are using JSON as encoding for the response. That’s why I used it too.
On the input validation front, is my system decently robust or is it too flimsy?
I also tried to make the code safe by catching any exceptions that might pop up. If there’s something I’ve overlooked please let me know.
@main.route('/createpost', methods=('POST'))
@login_required
def createpost():
resp = {
'success': False
}
err = ()
u = current_user.id # 2458017363
title = request.values.get('title')
_tags = request.values.get('tags') # JSON btw
content = request.values.get('content')
# _attachments = request.files.getlist('file')
# attachments = ()
# for f in _attachments:
# if f.filename.rsplit('.', 1)(1).lower() not in ALLOWED_EXTENSIONS:
# filepath = os.path.join(UPLOAD_DIR, secure_filename(f.filename))
# f.save(filepath)
# attachments.append(filepath)
# else:
# err.append('File ' + f.filename + "is not permitted!")
if not title or len(title) > 100:
err.append('Your title must exist and be less than 100 characters.')
try:
tags = json.loads(_tags)
if not tags or len(tags) > 3:
err.append('Choose between 1-3 tags so people know what your post is about!')
except Exception:
err.append('Choose between 1-3 tags so people know what your post is about!')
if not content or len(content) < 50:
err.append('Your content must be at least 50 characters.')
if err:
resp('error') = err
print('err')
return Response(json.dumps(resp), mimetype='text/json')
# PROVIDED EVERYTHING IS CORRECT
while True:
try:
dbentry = Post(id=snowflake(),
author_id=u,
title=bleach.clean(str(title)),
tags=bleach.clean(str(_tags)),
content=bleach.clean(str(content)).encode(),
)
db.session.add(dbentry)
db.session.commit()
except IntegrityError:
continue
break
resp('success') = True
return Response(json.dumps(resp), mimetype='text/json')
imports are as follows:
# main.py
import json
import os
import bleach
from sqlalchemy.exc import IntegrityError
from .models import Post # sqlalchemy model for posts
from flask import Blueprint, render_template, request, Response
from flask_login import login_required, current_user
from werkzeug.utils import secure_filename
from . import db
from .utils import snowflake # random number generator
# (hence why i have a while loop around the db entry creation since there is a
# miniscule chance it will give the same number again)