Repository: apiflask/apiflask (python)

Issue:
Add Config field to dump Flask configuration variables
Example usage:

```py
from apiflask import APIFlask, Schema
from apiflask.fields import Config

app = APIFlask(__name__)
app.config['API_TITLE'] = 'Pet API'

class FooSchema(Schema):
    title = Config('API_TITLE')
```

Consider adding this field to the upstream flask-marshmallow.

Pull request description:
Add Config field
fixes #468

<!--
If needed, ensure each step in the checklist below is complete. If only docs were changed, these aren't relevant and can be removed.
-->

Checklist:

- [x] Add tests that demonstrate the correct behavior of the change. Tests should fail without the change.
- [x] Add or update relevant docs, in the `docs` folder and in code docstring.
- [x] Add an entry in `CHANGES.md` summarizing the change and linking to the issue.
- [x] Add `*Version changed*` or `*Version added*` note in any relevant docs and docstring.
- [x] Run `pytest` and `tox`, no tests failed.


Patch:
diff --git a/CHANGES.md b/CHANGES.md
index 59ad5fb..81bf455 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -2,6 +2,10 @@
 
 Released: -
 
+- Add `Config` field to dump Flask `app.config` variables ([issue #468][issue_468]).
+
+[issue_468]: https://github.com/apiflask/apiflask/issues/468
+
 
 ## Version 2.0.0
 
diff --git a/docs/schema.md b/docs/schema.md
index 1e09a85..85702b5 100644
--- a/docs/schema.md
+++ b/docs/schema.md
@@ -155,9 +155,10 @@ API documentation: <https://webargs.readthedocs.io/en/latest/api.html#module-web
 
 ## APIFlask fields
 
-API documentation: <https://apiflask.com/api/fields/#apiflask.fields.File>
+API documentation: <https://apiflask.com/api/fields>
 
-- `File`
+- `File`: represents a file input.
+- `Config`: dump a config value from Flask's `config` object.
 
 !!! tip
 
diff --git a/src/apiflask/fields.py b/src/apiflask/fields.py
index e6fadd3..e9ed27a 100644
--- a/src/apiflask/fields.py
+++ b/src/apiflask/fields.py
@@ -120,3 +120,44 @@ class File(Field):
         if not isinstance(value, FileStorage):
             raise self.make_error('invalid')
         return value
+
+
+class Config(Field):
+    """A field for Flask configuration values.
+
+    Examples:
+
+    ```python
+    from apiflask import APIFlask, Schema
+    from apiflask.fields import String, Config
+
+    app = APIFlask(__name__)
+    app.config['API_TITLE'] = 'Pet API'
+
+    class FooSchema(Schema):
+        user = String()
+        title = Config('API_TITLE')
+
+    @app.get('/foo')
+    @app.output(FooSchema)
+    def foo():
+        return {'user': 'test'}
+    ```
+
+    This field should only be used in an output schema. The `ValueError` will
+    be raised if the config key is not found in the app config.
+
+    *Version Added: 2.0.1*
+    """
+
+    _CHECK_ATTRIBUTE = False
+
+    def __init__(self, key, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.key = key
+
+    def _serialize(self, value, attr, obj, **kwargs) -> t.Any:
+        from flask import current_app
+        if self.key not in current_app.config:
+            raise ValueError(f'The key {self.key} is not found in the app config.')
+        return current_app.config[self.key]


Test patch:
diff --git a/tests/test_fields.py b/tests/test_fields.py
index fbe8554..d120124 100644
--- a/tests/test_fields.py
+++ b/tests/test_fields.py
@@ -1,9 +1,12 @@
 import io
 
+import pytest
 from werkzeug.datastructures import FileStorage
 
 from .schemas import Files
 from .schemas import FilesList
+from apiflask import Schema
+from apiflask.fields import Config
 
 
 def test_file_field(app, client):
@@ -79,3 +82,30 @@ def test_multiple_file_field(app, client):
     )
     assert rv.status_code == 422
     assert rv.json['detail']['files']['images']['2'] == ['Not a valid file.']
+
+
+def test_config_field(app, client):
+    app.config['API_TITLE'] = 'Pet API'
+
+    class GoodSchema(Schema):
+        title = Config('API_TITLE')
+
+    class BadSchema(Schema):
+        description = Config('API_DESCRIPTION')
+
+    @app.get('/good')
+    @app.output(GoodSchema)
+    def good():
+        return {}
+
+    rv = client.get('/openapi.json')
+    assert rv.status_code == 200
+
+    rv = client.get('/good')
+    assert rv.status_code == 200
+    assert rv.json == {'title': 'Pet API'}
+
+    with pytest.raises(ValueError, match=r'The key.*is not found in the app config.'):
+        with app.app_context():
+            bad = BadSchema()
+            bad.dump({})