A small framework for creating simple JSON endpoints.
from flask_yoloapi import endpoint, parameter
@app.route('/api/login', methods=['GET', 'POST'])
@endpoint.api(
parameter('username', type=str, required=True),
parameter('password', type=str, required=True),
parameter('remember', type=bool, required=False, default=False)
)
def login(username, password, remember):
"""
Logs the user in.
:param username: The username of the user
:param password: The password of the user
:param expiration: Session expiration time in seconds
:return: The logged in message!
"""
return "user logged in!"
The response:
{
data: "user logged in!"
}
- You don't want to write boilerplate code that involves classes just to make some API routes (flask-restful).
- You don't want to fish incoming parameters out of
request.args
, or wait, was itrequest.form
? No,request.json
😴 - You don't need to hook your endpoints directly to SQLa models.
- You don't care about providing REST compliancy - you just want somewhat consistent JSON endpoints, damnit!
In short, this is a simple library for simple JSON endpoints.
pip install flask-yoloapi
In the example above, a string was returned. The following types are also supported:
str
,unicode
,int
,float
,dict
,list
,datetime
,bool
,flask.Response
.
@app.route('/wishlist')
@endpoint.api(
parameter('category', type=str, required=False)
)
def wishlist(category):
if category == "cars":
return ['volvo xc60', 'mclaren mp4-12c']
{
"data": [
"volvo xc60",
"mclaren mp4-12c"
]
}
To return different status codes, return a 2-length tuple
with the second index being the status code itself.
@app.route('/create_foo')
@endpoint.api()
def create_foo():
return 'created', 201
You can still use Flask's route parameters in conjunction with endpoint parameters.
@app.route('/hello/<name>')
@endpoint.api(
parameter('age', type=int, required=True)
)
def hello(name, age):
return {'name': name, 'age': age}
/hello/sander?age=27
{
"data": {
"age": 27,
"name": "sander"
}
}
You can define default values for endpoint parameters via default
.
@app.route('/hello/<name>')
@endpoint.api(
parameter('age', type=int, required=False, default=10)
)
def hello(name, age):
return {'name': name, 'age': age}
/hello/sander
{
"data": {
"age": 10,
"name": "sander"
}
}
Parameter types are required, except when type annotations are in use.
A Python 3.5 example:
@app.route('/hello/', methods=['POST'])
@endpoint.api(
parameter('age', required=True),
parameter('name', required=True)
)
def hello(name: str, age: int):
return {'name': name, 'age': age}
Python 2 equivalent:
@app.route('/hello/', methods=['POST'])
@endpoint.api(
parameter('age', type=int, required=True),
parameter('name', type=str, required=True)
)
def hello(name, age):
return {'name': name, 'age': age}
Note that type annotations are only supported from Python 3.5 and upwards (PEP 484).
Additional parameter validation can be done by providing a validator function. This function takes 1 parameter; the input.
def custom_validator(value):
if value > 120:
raise Exception("you can't possibly be that old!")
@app.route('/hello/<name>')
@endpoint.api(
parameter('age', type=int, required=True, validator=custom_validator)
)
def hello(name, age):
return {'name': name, 'age': age}
/hello/sander?age=130
{
"data": "parameter 'age' error: you can't possibly be that old!"
}
When the validation proves to be unsuccessful, you may do 2 things:
- Raise an
Exception
, it will automatically construct a JSON response. This is shown above. - Return a
Flask.Response
object, where you may construct your own HTTP response
If you need more flexibility regarding incoming types use the flask_yoloapi.types.ANY
type.
This library is rather opportunistic about gathering incoming parameters, as it will check in the following 3 places:
request.args
request.json
request.form
An optional location
argument can be provided to specify the source of the parameter.
@app.route('/login')
@endpoint.api(
parameter('username', type=str, location='form', required=True),
parameter('password', type=str, location='form', required=True),
)
def login(username, password):
return "Wrong password!", 403
The following 3 locations are supported:
args
- GET parametersform
- parameters submitted via HTTP form submissionjson
- parameters submitted via a JSON encoded HTTP request
To output datetime objects in ISO 8601
format (which are trivial to parse in Javascript via Date.parse()
), use a custom JSON encoder.
from datetime import date
from flask.json import JSONEncoder
class ApiJsonEncoder(JSONEncoder):
def default(self, obj):
if isinstance(obj, (date, datetime)):
return obj.isoformat()
return super(ApiJsonEncoder, self).default(obj)
app = Flask(__name__)
app.json_encoder = ApiJsonEncoder
When the view function itself raises an exception, a JSON response is generated that includes:
- The error message
- Docstring of the view function
- HTTP 500
This error response is also generated when endpoint requirements are not met.
{
data: "argument 'password' is required",
docstring: {
help: "Logs the user in.",
return: "The logged in message!",
params: {
username: {
help: "The username of the user",
required: true,
type: "str"
}
},
...
MIT.