フラスコ静止API -パート4
17477 ワード
第4部:例外処理
危ない!シリーズの前で、我々は我々が加えることができる方法を学びました
authentication
and authorization
. この部分では、エラーに対してフラスコアプリケーションをより強力にし、適切なエラーメッセージをクライアントに送信する方法を学びます.コンピュータプログラムで何かがうまくいかないとき、プログラムは特定のものをスローする
Exception
何が間違っていたユーザーにいくつかのヒントを与える.我々のアプリケーションで何かが間違っているときにユーザーが既に使用されるメールアドレスを別のアカウントを作成しようとすると、彼らはInternal Server Error
そして、クライアントは彼らが何を間違っていたか全くわからない.そこで、このような問題を解決するためにException Handling
このような例外をキャッチし、エラーメッセージをクライアントに送信し、間違ったことを示します.我々は本当に便利な機能を使用するつもりです
flask-restful
それは我々を定義させますCustom Error Messages . 新しいファイルを作りましょう
errors.py
インサイドresources
フォルダを追加し、次のコードを追加しますcd resources
touch errors.py
#~/movie-bag/resources/errors.py
class InternalServerError(Exception):
pass
class SchemaValidationError(Exception):
pass
class MovieAlreadyExistsError(Exception):
pass
class UpdatingMovieError(Exception):
pass
class DeletingMovieError(Exception):
pass
class MovieNotExistsError(Exception):
pass
class EmailAlreadyExistsError(Exception):
pass
class UnauthorizedError(Exception):
pass
errors = {
"InternalServerError": {
"message": "Something went wrong",
"status": 500
},
"SchemaValidationError": {
"message": "Request is missing required fields",
"status": 400
},
"MovieAlreadyExistsError": {
"message": "Movie with given name already exists",
"status": 400
},
"UpdatingMovieError": {
"message": "Updating movie added by other is forbidden",
"status": 403
},
"DeletingMovieError": {
"message": "Deleting movie added by other is forbidden",
"status": 403
},
"MovieNotExistsError": {
"message": "Movie with given id doesn't exists",
"status": 400
},
"EmailAlreadyExistsError": {
"message": "User with given email address already exists",
"status": 400
},
"UnauthorizedError": {
"message": "Invalid username or password",
"status": 401
}
}
最初に見ることができるようにException
別のカスタム例外を作成し、errors
各例外のエラーメッセージとステータスコードを含む辞書.さて、これらのエラーをflask-restful
Api
クラス.更新
app.py
最近インポートするインポートerrors
辞書として追加しますApi
クラス.#~/movie-bag/app.py
from database.db import initialize_db
from flask_restful import Api
from resources.routes import initialize_routes
+from resources.errors import errors
app = Flask(__name__)
app.config.from_envvar('ENV_FILE_LOCATION')
-api = Api(app)
+api = Api(app, errors=errors)
bcrypt = Bcrypt(app)
jwt = JWTManager(app)
最後に、アプリケーションでいくつかの例外処理を行う準備ができました.更新movie.py
以下の関数を表示します#~/movie-bag/resources/movie.py
from flask import Response, request
from database.models import Movie, User
from flask_jwt_extended import jwt_required, get_jwt_identity
from flask_restful import Resource
+
+from mongoengine.errors import FieldDoesNotExist, \
+NotUniqueError, DoesNotExist, ValidationError, InvalidQueryError
+
+from resources.errors import SchemaValidationError, +MovieAlreadyExistsError, \
+InternalServerError, UpdatingMovieError, DeletingMovieError, +MovieNotExistsError
+
class MoviesApi(Resource):
def get(self):
@@ -11,32 +15,57 @@ class MoviesApi(Resource):
@jwt_required
def post(self):
- user_id = get_jwt_identity()
- body = request.get_json()
- user = User.objects.get(id=user_id)
- movie = Movie(**body, added_by=user)
- movie.save()
- user.update(push__movies=movie)
- user.save()
- id = movie.id
- return {'id': str(id)}, 200
-
+ try:
+ user_id = get_jwt_identity()
+ body = request.get_json()
+ user = User.objects.get(id=user_id)
+ movie = Movie(**body, added_by=user)
+ movie.save()
+ user.update(push__movies=movie)
+ user.save()
+ id = movie.id
+ return {'id': str(id)}, 200
+ except (FieldDoesNotExist, ValidationError):
+ raise SchemaValidationError
+ except NotUniqueError:
+ raise MovieAlreadyExistsError
+ except Exception as e:
+ raise InternalServerError
+
+
class MovieApi(Resource):
@jwt_required
def put(self, id):
- user_id = get_jwt_identity()
- movie = Movie.objects.get(id=id, added_by=user_id)
- body = request.get_json()
- Movie.objects.get(id=id).update(**body)
- return '', 200
+ try:
+ user_id = get_jwt_identity()
+ movie = Movie.objects.get(id=id, added_by=user_id)
+ body = request.get_json()
+ Movie.objects.get(id=id).update(**body)
+ return '', 200
+ except InvalidQueryError:
+ raise SchemaValidationError
+ except DoesNotExist:
+ raise UpdatingMovieError
+ except Exception:
+ raise InternalServerError
@jwt_required
def delete(self, id):
- user_id = get_jwt_identity()
- movie = Movie.objects.get(id=id, added_by=user_id)
- movie.delete()
- return '', 200
+ try:
+ user_id = get_jwt_identity()
+ movie = Movie.objects.get(id=id, added_by=user_id)
+ movie.delete()
+ return '', 200
+ except DoesNotExist:
+ raise DeletingMovieError
+ except Exception:
+ raise InternalServerError
def get(self, id):
- movies = Movie.objects.get(id=id).to_json()
- return Response(movies, mimetype="application/json", status=200)
+ try:
+ movies = Movie.objects.get(id=id).to_json()
+ return Response(movies, mimetype="application/json", status=200)
+ except DoesNotExist:
+ raise MovieNotExistsError
+ except Exception:
+ raise InternalServerError
の例を見ましょうpost
メソッドMoviesApi
クラスdef post(self):
try:
user_id = get_jwt_identity()
body = request.get_json()
user = User.objects.get(id=user_id)
movie = Movie(**body, added_by=user)
movie.save()
user.update(push__movies=movie)
user.save()
id = movie.id
return {'id': str(id)}, 200
except (FieldDoesNotExist, ValidationError):
raise SchemaValidationError
except NotUniqueError:
raise MovieAlreadyExistsError
except Exception as e:
raise InternalServerError
ここでは、我々は全体のビューのopetationstry...except
ブロック.私たちは例外連鎖を実行しました.したがって、どんな例外も得るとき、私たちは私たちが2000年に定義した例外を投げますerrors.py
and flask-restful
で定義した値に基づいてレスポンスを生成するerrors
辞書.ある場合
FieldDoesNotExist
例外ValidationError
例外mongoengine
我々は上げるSchemaValidationError
クライアントがリクエストJSONが無効であることを通知する例外です.同様に、ユーザーが既に存在する名前でムービーを作成しようとするとmongoengine
スローするNotUniqueError
例外を取得し、例外をキャッチしますMovieAlreadyExistsError
これは、ユーザーが映画名が既に存在することを伝えます.そして最後に、もし我々が期待していない例外を得るなら、私たちは
InternalServerError
. 同様の例外処理を追加しましょう
auth.py
#~/movie-bag/resources/auth.py
from database.models import User
from flask_restful import Resource
import datetime
+from mongoengine.errors import FieldDoesNotExist, NotUniqueError, DoesNotExist
+from resources.errors import SchemaValidationError, EmailAlreadyExistsError, UnauthorizedError, \
+InternalServerError
class SignupApi(Resource):
def post(self):
- body = request.get_json()
- user = User(**body)
- user.hash_password()
- user.save()
- id = user.id
- return {'id': str(id)}, 200
+ try:
+ body = request.get_json()
+ user = User(**body)
+ user.hash_password()
+ user.save()
+ id = user.id
+ return {'id': str(id)}, 200
+ except FieldDoesNotExist:
+ raise SchemaValidationError
+ except NotUniqueError:
+ raise EmailAlreadyExistsError
+ except Exception as e:
+ raise InternalServerError
class LoginApi(Resource):
def post(self):
- body = request.get_json()
- user = User.objects.get(email=body.get('email'))
- authorized = user.check_password(body.get('password'))
- if not authorized:
- return {'error': 'Email or password invalid'}, 401
- expires = datetime.timedelta(days=7)
- access_token = create_access_token(identity=str(user.id), expires_delta=expires)
- return {'token': access_token}, 200
+ try:
+ body = request.get_json()
+ user = User.objects.get(email=body.get('email'))
+ authorized = user.check_password(body.get('password'))
+ if not authorized:
+ raise UnauthorizedError
+
+ expires = datetime.timedelta(days=7)
+ access_token = create_access_token(identity=str(user.id), expires_delta=expires)
+ return {'token': access_token}, 200
+ except (UnauthorizedError, DoesNotExist):
+ raise UnauthorizedError
+ except Exception as e:
+ raise InternalServerError
それは、人々です.さて、我々のアプリケーションのエラーがあるときに適切なエラーメッセージを適切なステータスコードを取得します.ユーザーを作成してみましょう
/api/auth/signup
どんな電子メールアドレスでも、言いましょう[email protected]
. 次に、同じメールアドレスで別のユーザーを作成してみましょう.以下のようなレスポンスを得る.{
"message": "User with given email address already exists",
"status": 400
}
今、我々のアプリケーションのユーザーが簡単に何が間違って知っていることができます.この部分の完全なコードを見つけることができますhere
我々がシリーズのこの部分から学んだこと?
それまでハッピーコーディング😊
Reference
この問題について(フラスコ静止API -パート4), 我々は、より多くの情報をここで見つけました https://dev.to/paurakhsharma/flask-rest-api-part-4-exception-handling-5c6aテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol