Repository: tiangolo/fastapi

Issue:
Support HTTPStatus
### Is your feature request related to a problem

We typically use [HTTPStatus](https://docs.python.org/3/library/http.html#http.HTTPStatus) in our code. When used as a value for `status_code` in path functions this results in the string literal in the documentation and when "trying" the response is shown as undocumented because it doesn't match the actual response code

### The solution you would like

I want to use HTTPStatus enum values and have it work exactly like the `starlette.status` pseudo enum values





Discussion:
For now you can create your own HTTPStatus class (you can't subclass Enums) and add a `__str__` method to convert it to the string representation of the actual status code, for example:
```python
class MyHTTPStatus(IntEnum):
    OK = 200
    ...
    def __str__(self):
        return str(int(self))
```
or use `int(HTTPStatus)` in the endpoint decorator.
Thanks for the help @retnikt ! :bow: 

Yeah, @hmvp you can probably use that for your use case.
I am sorry to disagree...

It is indeed quite easy to workaround this. For example by just importing status from starlette and using that in the decorators. 

However `HTTPStatus` is part of the standard lib and since we use it extensively in the rest of our code I would like to use that instead of the starlette status. The second reason is that I expected it to work (since its part of stdlib) and it somewhat did but gave unexpected results.. This is a papercut/pitfall/surpising behavior of fastapi and given the high standard of the rest of the library this should not be there 

I am not sure if @retnikt  understood what I am trying to do here.. Adding another class is a weird suggestion given that both `HTTPStatus` and `starlette.status` already exist
The ASGI spec uses `int`s for status codes, not enums. That's why it takes `int`s.

Also, @retnikt has been helping a lot here, answering a lot of questions, trying to help others like you, for free. Just out of being a cool person. Please try to be more respectful to the community that is here trying to help.

If you really want to use `HTTPStatus` enums you can use the `int` value, it's quite simple, e.g. `HTTPStatus.OK.value`.
I did not want to be disrespectful to @retnikt and I value his contribution for other people that might have a similar but different issue. I just don't see how it is relevant for my issue. I am sorry if my wording was to strong... As a non-native English speaker I might miss some subtleties.

With regards to the ASGI spec, I did not know that, but I also was not aware that the `status_code` code argument followed the ASGI spec in that regard, especially since putting in a HTTPStatus code enum value just works, but will give a weird result in the docs. It should not be to difficult to add some code along the line of:
```
if isinstance(HTTPStatus, status_code):
     status_code = status_code.value
```
or  just `status_code = int(status_code)` to the path functions, which would solve a papercut and would still be valid ASGI.  Otherwise I would expect the path functions to be noisy about wrong input..

On the other hand, this is indeed not a big issue and if you don't want to change anything, thats fine with me. I just wanted to signal that this is a [papercut](https://en.wikipedia.org/wiki/Paper_cut_bug) in fastapi
Cool, thanks!

Yeah, I would accept a PR checking if a status code is an enum to get its value first. :nerd_face: :heavy_check_mark: 
Working on it!

Resolving patch:
diff --git a/fastapi/routing.py b/fastapi/routing.py
--- a/fastapi/routing.py
+++ b/fastapi/routing.py
@@ -1,4 +1,5 @@
 import asyncio
+import enum
 import inspect
 from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Type, Union
 
@@ -295,6 +296,9 @@ def __init__(
         dependency_overrides_provider: Any = None,
         callbacks: Optional[List["APIRoute"]] = None,
     ) -> None:
+        # normalise enums e.g. http.HTTPStatus
+        if isinstance(status_code, enum.IntEnum):
+            status_code = int(status_code)
         self.path = path
         self.endpoint = endpoint
         self.name = get_name(endpoint) if name is None else name


Test patch:
diff --git a/tests/main.py b/tests/main.py
--- a/tests/main.py
+++ b/tests/main.py
@@ -1,3 +1,5 @@
+import http
+
 from fastapi import FastAPI, Path, Query
 
 app = FastAPI()
@@ -184,3 +186,8 @@ def get_query_param_required(query=Query(...)):
 @app.get("/query/param-required/int")
 def get_query_param_required_type(query: int = Query(...)):
     return f"foo bar {query}"
+
+
+@app.get("/enum-status-code", status_code=http.HTTPStatus.CREATED)
+def get_enum_status_code():
+    return "foo bar"
diff --git a/tests/test_application.py b/tests/test_application.py
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -1078,6 +1078,18 @@
                 ],
             }
         },
+        "/enum-status-code": {
+            "get": {
+                "responses": {
+                    "201": {
+                        "description": "Successful Response",
+                        "content": {"application/json": {"schema": {}}},
+                    },
+                },
+                "summary": "Get Enum Status Code",
+                "operationId": "get_enum_status_code_enum_status_code_get",
+            }
+        },
     },
     "components": {
         "schemas": {
@@ -1149,3 +1161,9 @@ def test_redoc():
     assert response.status_code == 200, response.text
     assert response.headers["content-type"] == "text/html; charset=utf-8"
     assert "redoc@next" in response.text
+
+
+def test_enum_status_code_response():
+    response = client.get("/enum-status-code")
+    assert response.status_code == 201, response.text
+    assert response.json() == "foo bar"