Repository: sanic-org/sanic

Issue:
Blueprint ignores error_format option
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Describe the bug

`add_route` and its route-decorator friends respect the `error_format` option to specify "text", "json", or "html", as documented [here](https://sanic.dev/en/guide/best-practices/exceptions.html#built-in-error-handling).
But if I wrap the route in a blueprint, the `error_format` option no longer works, it just uses the default.

### Code snippet

#### Without Blueprint
```python
from sanic import Sanic
import sanic.exceptions

app = Sanic("MyHelloWorldApp")

@app.get("/", error_format="json")
async def hello_world(request):
    raise sanic.exceptions.SanicException("Big Mistake, Huge.", status_code=400)
```

// Elsewhere...
```bash
$ curl localhost:8000/ -i
HTTP/1.1 400 Bad Request
content-length: 73
connection: keep-alive
content-type: application/json

{"description":"Bad Request","status":400,"message":"Big Mistake, Huge."}
```

#### With Blueprint
```python
from sanic import Sanic
import sanic.exceptions

app = Sanic("MyHelloWorldApp")

bp = sanic.Blueprint("MyBlueprint")

@bp.get("/", error_format="json")
async def hello_world(request):
    raise sanic.exceptions.SanicException("Big Mistake, Huge.", status_code=400)

app.blueprint(bp)
```

// Elsewhere...
```bash
$ curl localhost:8000/ -i
HTTP/1.1 400 Bad Request
content-length: 68
connection: keep-alive
content-type: text/plain; charset=utf-8

⚠️ 400 — Bad Request
====================
Big Mistake, Huge.
```

### Expected Behavior

I expect the `error_format` option to be applied to the blueprint route the same as if applied to an app route.

### How do you run Sanic?

Sanic CLI

### Operating System

Mac OSX 12.3

### Sanic Version

23.3.0

### Additional context

_No response_

Discussion:
ahopkins: Thank you @moshe742!

Can you also add a test for this? In `./tests/test_errorpages.py` there is this test:

```py
def test_route_error_response_from_explicit_format(app):
    ...
```

You can copy the test and just attach the routes to a Blueprint object instead like in the issue.
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/sanic-org/sanic/pull/2773?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org) Report
Patch coverage: **`100.000`**% and project coverage change: **`+0.001`** :tada:
> Comparison is base [(`e374409`)](https://app.codecov.io/gh/sanic-org/sanic/commit/e3744095675df170398a374cc20832470200ea40?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org) 88.919% compared to head [(`15603aa`)](https://app.codecov.io/gh/sanic-org/sanic/pull/2773?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org) 88.920%.

> :exclamation: Current head 15603aa differs from pull request most recent head f0b940c. Consider uploading reports for the commit f0b940c to get more accurate results

<details><summary>Additional details and impacted files</summary>


```diff
@@              Coverage Diff              @@
##              main     #2773       +/-   ##
=============================================
+ Coverage   88.919%   88.920%   +0.001%     
=============================================
  Files           92        92               
  Lines         6976      6977        +1     
  Branches      1190      1190               
=============================================
+ Hits          6203      6204        +1     
  Misses         529       529               
  Partials       244       244               
```


| [Impacted Files](https://app.codecov.io/gh/sanic-org/sanic/pull/2773?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org) | Coverage Δ | |
|---|---|---|
| [sanic/blueprints.py](https://app.codecov.io/gh/sanic-org/sanic/pull/2773?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org#diff-c2FuaWMvYmx1ZXByaW50cy5weQ==) | `91.743% <100.000%> (+0.038%)` | :arrow_up: |


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/sanic-org/sanic/pull/2773?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=sanic-org).


Patch:
diff --git a/sanic/blueprints.py b/sanic/blueprints.py
index a52495b9..fc9408fe 100644
--- a/sanic/blueprints.py
+++ b/sanic/blueprints.py
@@ -319,6 +319,10 @@ class Blueprint(BaseSanic):
             # Prepend the blueprint URI prefix if available
             uri = self._setup_uri(future.uri, url_prefix)
 
+            route_error_format = (
+                future.error_format if future.error_format else error_format
+            )
+
             version_prefix = self.version_prefix
             for prefix in (
                 future.version_prefix,
@@ -358,7 +362,7 @@ class Blueprint(BaseSanic):
                 future.unquote,
                 future.static,
                 version_prefix,
-                error_format,
+                route_error_format,
                 future.route_context,
             )
 


Test patch:
diff --git a/tests/test_errorpages.py b/tests/test_errorpages.py
index a2df90b3..6c4334b7 100644
--- a/tests/test_errorpages.py
+++ b/tests/test_errorpages.py
@@ -2,6 +2,7 @@ import logging
 
 import pytest
 
+import sanic
 from sanic import Sanic
 from sanic.config import Config
 from sanic.errorpages import TextRenderer, exception_response, guess_mime
@@ -205,6 +206,27 @@ def test_route_error_response_from_explicit_format(app):
     assert response.content_type == "text/plain; charset=utf-8"
 
 
+def test_blueprint_error_response_from_explicit_format(app):
+    bp = sanic.Blueprint("MyBlueprint")
+
+    @bp.get("/text", error_format="json")
+    def text_response(request):
+        raise Exception("oops")
+        return text("Never gonna see this")
+
+    @bp.get("/json", error_format="text")
+    def json_response(request):
+        raise Exception("oops")
+        return json({"message": "Never gonna see this"})
+
+    app.blueprint(bp)
+    _, response = app.test_client.get("/text")
+    assert response.content_type == "application/json"
+
+    _, response = app.test_client.get("/json")
+    assert response.content_type == "text/plain; charset=utf-8"
+
+
 def test_unknown_fallback_format(app):
     with pytest.raises(SanicException, match="Unknown format: bad"):
         app.config.FALLBACK_ERROR_FORMAT = "bad"