Skip to content

Conversation

CostcoFanboy
Copy link
Contributor

@CostcoFanboy CostcoFanboy commented Jun 27, 2023

Checklist:

  • Run pytest tests and no failed.
  • Run flake8 flask_openapi3 tests examples and no failed.
  • Run mypy flask_openapi3 and no failed.
  • Run mkdocs serve and no failed.

@CostcoFanboy
Copy link
Contributor Author

CostcoFanboy commented Jun 27, 2023

If there's another way that you'd prefer to manage this that would allow a user to modify the 422 to a 400, please feel free to point it out.

Would this be better in a config file? I was thinking about overwriting it using a global.
Ideally I'd like to overwrite it at the OpenAPI(DEFAULT_VALIDATION_ERROR_STATUS=400) level. But the amount of code to be moved would be disruptive to this lib. If it's ok, I'll do it though.

@luolingchun
Copy link
Owner

Thanks @CostcoFanboy for working this.

I prefer to accept an explicit parameter validation_error_status rather than a constant DEFAULT_VALIDATION_ERROR_STATUS, like this:

app = OpenAPI(__name__, validation_error_status="400")

Can you follow this idea and continue to complete it?

And also requires a unit test.

@CostcoFanboy
Copy link
Contributor Author

CostcoFanboy commented Jul 1, 2023

Thanks @CostcoFanboy for working this.

I prefer to accept an explicit parameter validation_error_status rather than a constant DEFAULT_VALIDATION_ERROR_STATUS, like this:

app = OpenAPI(__name__, validation_error_status="400")

Can you follow this idea and continue to complete it?

And also requires a unit test.

Why did you use a custom library of strings instead of the official HTTPStatus lib built-in in Python everywhere?
flask_openapi3/http.py vs from http import HTTPStatus

There's inconsistencies vs HTTP Status as a string and HTTP Status as an int.
There's also from http import HTTPMethod for methods.

Would you be open to change this? Not necessarily same PR.

@CostcoFanboy CostcoFanboy marked this pull request as draft July 1, 2023 14:13
@CostcoFanboy
Copy link
Contributor Author

CostcoFanboy commented Jul 1, 2023

Self-Checklist:

  • Code modular validation_error_status everywhere as param
  • Old Pytest, mypy, docs, etc. work
  • Write new unit tests
  • Be able to change 422 default response schema

image

Will resume when more free time.

@CostcoFanboy CostcoFanboy changed the title Using DEFAULT_VALIDATION_ERROR_STATUS instead of hardcoded "422" to be able to change to 400 if needed [Feature Request] Be able to change 422 validation errors to other http response status code (e.g. 400) Jul 1, 2023
@luolingchun
Copy link
Owner

@CostcoFanboy It is unreasonable to add validation_error_status to each API method. Imagine that the same error response as get and post has different http status codes.

But I am also stuck in a stalemate, adding validation_error_status to OpenAPI does not solve the problems with APIBlueprint and APIView.

We need to find a better solution.

@luolingchun
Copy link
Owner

@CostcoFanboy I improve implement validation_error_status and I hope this solution can help you. Can you review it?

@CostcoFanboy
Copy link
Contributor Author

CostcoFanboy commented Jul 4, 2023

@CostcoFanboy It is unreasonable to add validation_error_status to each API method. Imagine that the same error response as get and post has different http status codes.

Agreed, I tried to initially avoid that with the global var. Otherwise need to replace it everywhere. But in one sense it does make sense to have it everywhere like this because maybe we should allow the http status code to be overwritten depending on the endpoint 🤔. I think this would be more of a "validation_error_status v2.0" effort though and we're doing v1.1

@CostcoFanboy I improve implement validation_error_status and I hope this solution can help you. Can you review it?

Anything that can change the HTTP response code can help.
In Flask you'd intercept with Flask-WTF the validation errors, but you handle them manually in this package.
And in FastAPI (what pydantic is more designed for), they overwrite it with an exception handler:

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
    request: Request,
    exc: RequestValidationError
):
    return JSONResponse(
        status_code=status.HTTP_400_BAD_REQUEST,
        content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
    )

So my first idea was to have a global variable I can use to overwrite the variable you have to make it non-intrusive.

By the way, why not use inheritance for the get, post, put, patch, etc? They are 95% similar.

Great work on the library otherwise, please don't see my comments as hate, I'm a fan of the package.

I will try to test it tomorrow in free time.

openapi_extensions: Extensions to the OpenAPI Schema.
See https://spec.openapis.org/oas/v3.0.3#specification-extensions.
validation_error_status: HTTP Status of the response given when a validation error is detected by pydantic.
Defaults to 422
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defaults in English would be more accurate.
"It defaults to" vs "it default to".

Not important of course.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

English is not my native language, thank you for pointing out.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, it's not mine either, we're all here to help each other out for a common goal :)

spec.paths = self.paths

# Add ValidationErrorResponseModel to components schemas
self.components_schemas[ValidationErrorResponseModel.__name__] = Schema(**ValidationErrorResponseModel.schema())
Copy link
Contributor Author

@CostcoFanboy CostcoFanboy Jul 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be addable by the user when initializing the application? What if the user doesn't use validation but chooses to use your library?

I agree that it's a strange/weird scenario if he chooses that though. May not be valid. Mostly brainstorming.

@luolingchun
Copy link
Owner

@CostcoFanboy I realize that you may have misunderstood:

  1. ValidationErrorResponseModel is model about Pydantic Error Handling. When parameter validation fails, a ValidationError will be triggered, So users do not need to customize the ValidationErrorResponseModel. What we are discussing here is only changing the default HTTP status for ValidationErrorResponse. At the beginning, I even think that the HTTP status code of ValidationErrorResponse must be 422 and cannot be changed.
  2. This library does not provide responses like the JSONResponse of FastAPI. But it is fully compatible with Flask style responses. You can return http status for every endpoint. like:
    @app.get("/book", responses={"404": NotFoundResponse})
    def get_book(query: BookQuery):
        return "Not Found", 404
    
    @app.post("/book", responses={"400": BadReauestResponse})
    def create_book(query: BookQuery):
        return "Bad Request", 400

Please be free to point out my mistake, I am open to it.

@luolingchun luolingchun marked this pull request as ready for review July 21, 2023 02:59
@luolingchun
Copy link
Owner

@CostcoFanboy @atistler I think I have already completed this issue.

Can you do a test to ensure that my implementation meets everyone's requirements?

@higorsnt
Copy link

Hi, do you have any prediction of when this feature will be published?
This error message customization is a problem I'm facing in a project and it would help a lot

@CostcoFanboy
Copy link
Contributor Author

Hey @luolingchun sorry for the delay I was on vacation then this escaped my mind.

I did a quick test using your changes and this is more than satisfactory. Great work!

@higorsnt Feel free to actually contribute instead of just asking when things will be ready.

@luolingchun
Copy link
Owner

@higorsnt It's preliminarily completed, and I will do the final round of testing, probably in the first week of August.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants