diff --git a/api_reflector/admin.py b/api_reflector/admin.py index 0a0f4ea..44c72cc 100644 --- a/api_reflector/admin.py +++ b/api_reflector/admin.py @@ -1,16 +1,36 @@ """ Declares the flask-admin instance and sets up the model views. """ +import json +from json import JSONDecodeError + from flask import redirect, url_for from flask_admin import Admin, AdminIndexView from flask_admin.contrib.sqla import ModelView from flask_admin.menu import MenuLink from jinja2.runtime import Context from slugify import slugify +from wtforms import validators from api_reflector import auth, db, models +def is_valid_json(data: str) -> None: + """ + Validator function for checking whether form field content is a valid JSON. + """ + + try: + json.loads(data) + except JSONDecodeError as exc: + raise validators.ValidationError("Response content data must be a valid JSON object or empty.") from exc + + +form_validators = { + "application/json": is_valid_json, +} + + def admin_view(model: db.Model): """ Registers a model with the admin. @@ -97,6 +117,11 @@ class ResponseView(RestrictedView): form_widget_args = {"content": {"rows": 8, "style": "font-family: monospace;"}} column_searchable_list = ("name",) + def on_model_change(self, form, model, is_created): + if validator := form_validators.get(form.content_type.data): + validator(form.content.data) + super().on_model_change(form, model, is_created) + def content_formatter(self, _ctx: Context, model: models.Model, _name: str): """ Limits the content field to a maximum length in the list view. diff --git a/api_reflector/models.py b/api_reflector/models.py index 7eb9bf2..2cafd1b 100644 --- a/api_reflector/models.py +++ b/api_reflector/models.py @@ -74,7 +74,7 @@ class Response(Model): status_code = Column(Integer, nullable=False, default=200) content_type = Column(String, nullable=False, default="application/json") - content = Column(Text, nullable=False, default="") + content = Column(Text, nullable=False, default="{}") is_active = Column(Boolean, nullable=False, default=True)