Skip to content

Commit

Permalink
app: Update template-application-flask to version 0.4.0.post4.dev0+…
Browse files Browse the repository at this point in the history
…60d5c78
  • Loading branch information
nava-platform-bot committed Mar 6, 2025
1 parent 35e4cdb commit 7eb8c21
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 109 deletions.
2 changes: 1 addition & 1 deletion .template-application-flask/app.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Changes here will be overwritten by Copier
_commit: v0.4.0-3-g612ac3d
_commit: v0.4.0-4-g60d5c78
_src_path: https://github.com/navapbc/template-application-flask
app_local_port: 8080
app_name: app
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@ Which format and structure should these records follow?

## Considered Options

* [MADR](https://adr.github.io/madr/) 2.1.2 – The Markdown Architectural Decision Records
* [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) – The first incarnation of the term "ADR"
* [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) – The Y-Statements
* Other templates listed at <https://github.com/joelparkerhenderson/architecture_decision_record>
* Formless – No conventions for file format and structure
- [MADR](https://adr.github.io/madr/) 2.1.2 – The Markdown Architectural Decision Records
- [Michael Nygard's template](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions) – The first incarnation of the term "ADR"
- [Sustainable Architectural Decisions](https://www.infoq.com/articles/sustainable-architectural-design-decisions) – The Y-Statements
- Other templates listed at <https://github.com/joelparkerhenderson/architecture_decision_record>
- Formless – No conventions for file format and structure

## Decision Outcome

Chosen option: "MADR 2.1.2", because

* Implicit assumptions should be made explicit.
- Implicit assumptions should be made explicit.
Design documentation is important to enable people to understand the decisions later on.
See also [A rational design process: How and why to fake it](https://doi.org/10.1109/TSE.1986.6312940).
* The MADR format is lean and fits our development style.
* The MADR structure is comprehensible and facilitates usage & maintenance.
* The MADR project is vivid.
* Version 2.1.2 is the latest one available when starting to document ADRs.
- The MADR format is lean and fits our development style.
- The MADR structure is comprehensible and facilitates usage & maintenance.
- The MADR project is vivid.
- Version 2.1.2 is the latest one available when starting to document ADRs.
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,20 @@ We aren't looking to move off of Flask at the moment as we feel that would be a

## Decision Drivers

* Connexion requires you to specify an OpenAPI spec but passes the request objects as the raw JSON. We currently use Pydantic to convert this into a Python object for additional validations & for ease of use, but this effectively means we need to define any models twice.
* Defining the OpenAPI specs first instead of defining the data models in code has often been more frustrating. While one goal of doing it this way was the ability to create mock endpoints while development is ongoing, this can also be easily handled by just making the endpoint return a static response in-code.
* Connexion's defaults for validation leave a lot to be desired. While we currently override these, it adds a lot of boilerplate to this template library, and isn't immediately obvious.
* Code first is recommended by Swagger when building internal APIs that need to be built quickly: https://swagger.io/blog/api-design/design-first-or-code-first-api-development/ which is often the case for our endpoints that aren't directly exposed to users.
- Connexion requires you to specify an OpenAPI spec but passes the request objects as the raw JSON. We currently use Pydantic to convert this into a Python object for additional validations & for ease of use, but this effectively means we need to define any models twice.
- Defining the OpenAPI specs first instead of defining the data models in code has often been more frustrating. While one goal of doing it this way was the ability to create mock endpoints while development is ongoing, this can also be easily handled by just making the endpoint return a static response in-code.
- Connexion's defaults for validation leave a lot to be desired. While we currently override these, it adds a lot of boilerplate to this template library, and isn't immediately obvious.
- Code first is recommended by Swagger when building internal APIs that need to be built quickly: https://swagger.io/blog/api-design/design-first-or-code-first-api-development/ which is often the case for our endpoints that aren't directly exposed to users.

## Considered Options

* [APIFlask](#apiflask) **Recommended Approach**
* [Flask OpenAPI3](#flask-openapi3)
* [Flasgger](#flasgger)
* [Flask Smorest](#flask-smorest)
* [APISpec](#apispec)
* [Flask RESTX](#flask-restx)
* [APIFairy](#apifairy)
- [APIFlask](#apiflask) **Recommended Approach**
- [Flask OpenAPI3](#flask-openapi3)
- [Flasgger](#flasgger)
- [Flask Smorest](#flask-smorest)
- [APISpec](#apispec)
- [Flask RESTX](#flask-restx)
- [APIFairy](#apifairy)

## Decision Outcome

Expand Down Expand Up @@ -130,12 +130,12 @@ def create_user(user: User):
```
</details>

* Good, because the documentation is immensely thorough, and does a great job of explaining all the customization options while providing sane defaults.
* Good, because you can [register custom error processors](https://apiflask.com/error-handling/#custom-error-response-processor) which would allow us to reuse and adapt our existing error processors - although it looks like the defaults are more sane - as all errors, not just the first get added to the error response.
* Good, because [authentication looks to be flexible](https://apiflask.com/authentication/), and allows you to define it as if you were writing the OpenAPI.
* Good, because the [API uses Marshmallow](https://apiflask.com/schema/) for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - and additionally supports [Marshmallow Dataclass](https://apiflask.com/schema/#use-dataclass-as-data-schema) which is a wrapper that allows you to interact directly with dataclass objects which further improves runtime typing.
* Meh, because methods end up with several decorators, although you can [group route methods into classes](https://apiflask.com/usage/#use-class-based-views) and make them share decorators (eg. set the authentication decorator on the class).
* Bad, because APIFlask 1.0 only released in May 2022, with the first beta release about a year earlier, so the project is still somewhat young.
- Good, because the documentation is immensely thorough, and does a great job of explaining all the customization options while providing sane defaults.
- Good, because you can [register custom error processors](https://apiflask.com/error-handling/#custom-error-response-processor) which would allow us to reuse and adapt our existing error processors - although it looks like the defaults are more sane - as all errors, not just the first get added to the error response.
- Good, because [authentication looks to be flexible](https://apiflask.com/authentication/), and allows you to define it as if you were writing the OpenAPI.
- Good, because the [API uses Marshmallow](https://apiflask.com/schema/) for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - and additionally supports [Marshmallow Dataclass](https://apiflask.com/schema/#use-dataclass-as-data-schema) which is a wrapper that allows you to interact directly with dataclass objects which further improves runtime typing.
- Meh, because methods end up with several decorators, although you can [group route methods into classes](https://apiflask.com/usage/#use-class-based-views) and make them share decorators (eg. set the authentication decorator on the class).
- Bad, because APIFlask 1.0 only released in May 2022, with the first beta release about a year earlier, so the project is still somewhat young.


### Flask OpenAPI3
Expand Down Expand Up @@ -205,11 +205,11 @@ if __name__ == "__main__":

</details>

* Good, because the API model definitions use Pydantic, which is a well-supported library we are already familiar with.
* Good, because the API definitions are minimal and pretty intuitive to read.
* Bad, because the documentation isn't fully detailed, and the errors that occur when trying to get the API running aren't very clear. In ~30 minutes of debugging, I hadn't figured out how to get the API to fully run.
* Bad, while it generates swagger docs, and can display example responses, it doesn't appear that you can specify example requests or parameters. This effectively makes Swagger unusable.
* Bad, because it appears that the library is primarily [maintained by one person](https://github.com/luolingchun/flask-openapi3/commits/master), and appears to still be going through early implementation fixes.
- Good, because the API model definitions use Pydantic, which is a well-supported library we are already familiar with.
- Good, because the API definitions are minimal and pretty intuitive to read.
- Bad, because the documentation isn't fully detailed, and the errors that occur when trying to get the API running aren't very clear. In ~30 minutes of debugging, I hadn't figured out how to get the API to fully run.
- Bad, while it generates swagger docs, and can display example responses, it doesn't appear that you can specify example requests or parameters. This effectively makes Swagger unusable.
- Bad, because it appears that the library is primarily [maintained by one person](https://github.com/luolingchun/flask-openapi3/commits/master), and appears to still be going through early implementation fixes.

### Flasgger

Expand All @@ -221,9 +221,9 @@ Note that Flasgger has several different ways to define the schema. This specifi

No example implementation as the ones presented in the docs didn't actually function out of the box.

* Good, because there is a lot of variety in how you set up your schema, although most require defining the JSON/YAML yourself.
* Bad, because the non-JSON/YAML approaches don't appear to be the main purpose of this API, and little documentation/examples exist regarding their usage.
* Bad, because it seems the approach for running using [Marshmallow for the schema](https://github.com/flasgger/flasgger#using-marshmallow-schemas) isn't valid anymore as the parameters that Flask takes in don't match the example. From reading various other docs, Flask seems to have had a major version update that changed it a bit in recent years, so that is likely the cause.
- Good, because there is a lot of variety in how you set up your schema, although most require defining the JSON/YAML yourself.
- Bad, because the non-JSON/YAML approaches don't appear to be the main purpose of this API, and little documentation/examples exist regarding their usage.
- Bad, because it seems the approach for running using [Marshmallow for the schema](https://github.com/flasgger/flasgger#using-marshmallow-schemas) isn't valid anymore as the parameters that Flask takes in don't match the example. From reading various other docs, Flask seems to have had a major version update that changed it a bit in recent years, so that is likely the cause.

### Flask Smorest

Expand Down Expand Up @@ -304,11 +304,11 @@ if __name__ == "__main__":

</details>

* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
* Good, because it is fairly straightforward and just seems to work as expected.
* Bad, because the documentation is pretty minimal beyond getting OpenAPI running. Seems like this is just an OpenAPI wrapper with no other additional features.
* Bad, because it is pretty barebones. It just sets up a swagger endpoint and does the object validation, but doesn't handle anything beyond that regarding authentication.
* Bad, because even the maintainers recognize it needs a [bit more work](https://github.com/apiflask/apiflask/discussions/14#discussioncomment-571898)
- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
- Good, because it is fairly straightforward and just seems to work as expected.
- Bad, because the documentation is pretty minimal beyond getting OpenAPI running. Seems like this is just an OpenAPI wrapper with no other additional features.
- Bad, because it is pretty barebones. It just sets up a swagger endpoint and does the object validation, but doesn't handle anything beyond that regarding authentication.
- Bad, because even the maintainers recognize it needs a [bit more work](https://github.com/apiflask/apiflask/discussions/14#discussioncomment-571898)

### APISpec

Expand Down Expand Up @@ -422,10 +422,10 @@ if __name__ == "__main__":
```
</details>

* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
* Good, because it gives a lot of flexibility for defining the OpenAPI docs, [including security](https://apispec.readthedocs.io/en/latest/special_topics.html#documenting-security-schemes).
* Bad, because you still have to specify some of the OpenAPI docs as a comment on the function. The primary gain is being able to use Marshmallow to define the schema models, but the routes are still largely yaml.
* Bad, because apispec doesn't actually run the swagger docs, it just generates them. You would need to use one of the other approaches here in tandem.
- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow) - it's in the same project.
- Good, because it gives a lot of flexibility for defining the OpenAPI docs, [including security](https://apispec.readthedocs.io/en/latest/special_topics.html#documenting-security-schemes).
- Bad, because you still have to specify some of the OpenAPI docs as a comment on the function. The primary gain is being able to use Marshmallow to define the schema models, but the routes are still largely yaml.
- Bad, because apispec doesn't actually run the swagger docs, it just generates them. You would need to use one of the other approaches here in tandem.

### Flask RESTX

Expand Down Expand Up @@ -499,11 +499,11 @@ if __name__ == "__main__":
```
</details>

* Good, because the way it organizes namespaces (ie. tags), and parameters is intuitive and fairly readable.
* Good, because it provides implicit [masking logic](https://flask-restx.readthedocs.io/en/latest/mask.html) that makes masking responses easy which is helpful when working with PII.
* Bad, because while you define a model, you define it as a dictionary, not a class, and thus end up working with just dictionaries. If we wanted any well-structured classes, we'd need to define that separately.
* Bad, because they have an entire section of documentation about [request parsing](https://flask-restx.readthedocs.io/en/latest/parsing.html) that is deprecated - and seems to have been replaced quite some time ago (not well maintained?).
* Bad, because the last release was over a year ago, and there have only been a very small number of commits this year.
- Good, because the way it organizes namespaces (ie. tags), and parameters is intuitive and fairly readable.
- Good, because it provides implicit [masking logic](https://flask-restx.readthedocs.io/en/latest/mask.html) that makes masking responses easy which is helpful when working with PII.
- Bad, because while you define a model, you define it as a dictionary, not a class, and thus end up working with just dictionaries. If we wanted any well-structured classes, we'd need to define that separately.
- Bad, because they have an entire section of documentation about [request parsing](https://flask-restx.readthedocs.io/en/latest/parsing.html) that is deprecated - and seems to have been replaced quite some time ago (not well maintained?).
- Bad, because the last release was over a year ago, and there have only been a very small number of commits this year.


### APIFairy
Expand Down Expand Up @@ -594,9 +594,8 @@ if __name__ == "__main__":
```
</details>

* Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow).
* Good, because the decorators are named fairly intuitively and help make the methods clearer.
* Bad, because it insists Marshmallow "just works" but.. doesn't (see the hacky `jsonify` I had to do in the example). The very unhelpful error messages it gave about `jsonify` not existing were very frustrating.
* Bad, because the documentation doesn't have any fully working examples making it difficult to figure out a minimal viable implementation. It is written as if you're adjusting a fully-formed Marshmallow-based Flask app, and not starting from scratch.
* Bad, because there doesn't appear to be a ton of support - no questions posted anywhere, and only one article about it.

- Good, because the API uses Marshmallow for its data schema, which is a [well-maintained library](https://github.com/marshmallow-code/marshmallow).
- Good, because the decorators are named fairly intuitively and help make the methods clearer.
- Bad, because it insists Marshmallow "just works" but.. doesn't (see the hacky `jsonify` I had to do in the example). The very unhelpful error messages it gave about `jsonify` not existing were very frustrating.
- Bad, because the documentation doesn't have any fully working examples making it difficult to figure out a minimal viable implementation. It is written as if you're adjusting a fully-formed Marshmallow-based Flask app, and not starting from scratch.
- Bad, because there doesn't appear to be a ton of support - no questions posted anywhere, and only one article about it.
Loading

0 comments on commit 7eb8c21

Please sign in to comment.