Dans Article précédent, j'ai créé une application conceptuelle pour les micro-services utilisant flask, cerberus et peewee. Cette fois, je vais vous expliquer comment vérifier Content-Type par flacon, qui a été omis à ce moment-là. En outre, je voudrais vous présenter comment créer un décorateur de fonction qui vérifie Content-Type.
@ content_type
introduites cette foisroute ()
function of flask Accordé à la fonction qui accorde le décorateur (c'est-à-dire l'API REST)@content_exemple d'utilisation du décorateur de fonction de type
# rest api
@app.route('/questions', methods=['POST'])
@content_type('application/json')
def register_question():
Dans flask, vous pouvez vous référer aux informations d'en-tête de requête HTTP avec request.headers
.
request.headers
est un objet de type dictionnaire dont la clé est le nom de l'en-tête.
Ainsi, lors de la vérification de Content-Type, obtenez la valeur en utilisant Content-Type comme clé.
Voir http://flask.pocoo.org/docs/0.12/api/#incoming-request-data pour plus d'informations.
Pas un bon exemple de code
# -*- coding: utf-8 -*-
import os
from flask import Flask, abort, request, make_response, jsonify
# flask
app = Flask(__name__)
# rest api
@app.route('/questions', methods=['POST'])
def register_question():
#Type de contenu (application/json) vérifier
if not request.headers.get("Content-Type") == 'application/json':
error_message = {
'error':'not supported Content-Type'
}
return make_response(jsonify(error_message), 400)
# omitted :Exécution de la logique métier
#Retour du résultat du traitement (format JSON)
return make_response(jsonify({'result': True}))
@app.route('/questions/<string:question_code>', methods=['PUT'])
def update_question(question_code):
#Type de contenu (application/json) vérifier
if not request.headers.get("Content-Type") == 'application/json':
error_message = {
'error':'not supported Content-Type'
}
return make_response(jsonify(error_message), 400)
# omitted :Exécution de la logique métier
#Retour du résultat du traitement (format JSON)
return make_response(jsonify({'result': True}))
# main
if __name__ == "__main__":
app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
port=os.getenv("APP_PORT", 3000))
Comme il existe de nombreux endroits pour vérifier le type de contenu, des problèmes de clonage / duplication de code se produiront. Elle peut être définie comme une fonction d'utilité, mais comme elle ne remplit pas les conditions préalables avant d'appeler l'API, c'est juste une impression personnelle, mais je ne voulais pas décrire le processus d'appel de l'utilitaire.
Un décorateur de fonction vous permet d'appeler la fonction cible (API REST dans ce cas) uniquement si la vérification est réussie, c'est-à-dire si les conditions préalables sont remplies. En conséquence, j'ai décidé d'implémenter le décorateur de fonction illustré ci-dessous.
@ content_type
pour un look modernecontent_type_check_app.py
# -*- coding: utf-8 -*-
import os
from flask import Flask, abort, request, make_response, jsonify
import functools
# flask
app = Flask(__name__)
# check content-type decorator
def content_type(value):
def _content_type(func):
@functools.wraps(func)
def wrapper(*args,**kwargs):
if not request.headers.get("Content-Type") == value:
error_message = {
'error': 'not supported Content-Type'
}
return make_response(jsonify(error_message), 400)
return func(*args,**kwargs)
return wrapper
return _content_type
# rest api
@app.route('/questions', methods=['POST'])
@content_type('application/json')
def register_question():
# omitted :Exécution de la logique métier
#Retour du résultat du traitement (format JSON)
return make_response(jsonify({'result': True}))
@app.route('/questions/<string:question_code>', methods=['PUT'])
@content_type('application/json')
def update_question(question_code):
# omitted :Exécution de la logique métier
#Retour du résultat du traitement (format JSON)
return make_response(jsonify({'result': True}))
# main
if __name__ == "__main__":
app.run(host=os.getenv("APP_ADDRESS", 'localhost'), \
port=os.getenv("APP_PORT", 3000))
Vous pouvez maintenant simplement ajouter @ content_type ('application / json')
aux fonctions de l'API REST.
Vous pouvez voir intuitivement que Content-Type doit être application / json sans le problème de clonage de code.
(Si nécessaire, rendez application / json constante)
** Au fait, si vous modifiez l'ordre de description de @ app.route
et @ content_type
, une erreur se produira. ** **
Les décorateurs de fonction Python ne sont pas des points de repère comme les annotations Java, mais une imbrication de fonction, donc l'ordre d'imbrication affecte le flux de traitement.
C'est parce que la fonction de flask est appelée dans le traitement de @ content_type
, il est donc nécessaire d'exécuter d'abord flask en tant que nest.
democlient.py
# -*- coding: utf-8 -*-
import requests
import json
def register_question_none_content_type(url, data):
print("[POST] /questions : none content-type")
response = requests.post(url, json.dumps(question))
print(response.status_code)
print(response.content)
def register_question(url, data):
print("[POST] /questions : content-type application/json")
response = requests.post(url, json.dumps(question), \
headers={'Content-type': 'application/json'})
print(response.status_code)
print(response.content)
# main
if __name__ == "__main__":
url = 'http://localhost:3000/questions'
question = {
'question_code' : '9999999999',
'category' : 'demo',
'message' : 'hello'
}
# Content-Aucun type
register_question_none_content_type(url, question)
# Content-Type : application/json
register_question(url, question)
Comme décrit dans Article précédent, si vous spécifiez des données dans l'argument json comme json = data
, les requêtes s'appliqueront automatiquement / Définissez le Content-Type de json.
Puisque cette fonction n'est pas utilisée cette fois, les données de transmission directe (json.dumps (question)
) sont définies dans le deuxième argument.
Démarrage du serveur (et journal d'exécution)
C:\tmp\>python content_type_check_app.py
* Running on http://localhost:3000/ (Press CTRL+C to quit)
127.0.0.1 - - [16/Aug/2017 20:02:30] "POST /questions HTTP/1.1" 400 -
127.0.0.1 - - [16/Aug/2017 20:02:30] "POST /questions HTTP/1.1" 200 -
La première ligne du journal d'exécution est une requête HTTP pour laquelle Content-Type n'est pas spécifié et l'état HTTP est 400. La deuxième ligne correspond à la requête HTTP spécifiée. Dans ce cas, le processus est exécuté normalement et 200 est renvoyé.
Exécution du client
C:\tmp\python democlient.py
[POST] /questions : none content-type
400
{
"error": "not supported Content-Type"
}
[POST] /questions : content-type application/json
200
{
"result": true
}
Nous avons confirmé que les requêtes HTTP qui ne spécifient pas Content-Type renverront une erreur 400 avec le statut HTTP et le contenu de l'erreur {'error': 'not supported Content-Type'}
comme prévu.
Étant donné que la demande suivante spécifie application / json pour Content-Type, elle réussit la vérification Content-Type et renvoie le résultat de traitement correct avec un statut HTTP de 200.
Cette fois, j'ai expliqué comment vérifier Content-Type avec flask.
** Si le flask peut effectuer le mappage de requêtes même avec Content-Type, Content-Type sera garanti lorsque l'API REST sera appelée **, donc le @ content_type
créé cette fois ne sera pas nécessaire.
De plus, j'ai créé un décorateur de fonctions pour la première fois cette fois, mais comme je peux ajouter des fonctions plus tard comme AOP, j'ai senti qu'il pouvait être utilisé de diverses autres manières.
Recommended Posts