Skip to content

Commit

Permalink
Add ARCHITECTURE.rst and module docstrings (#1368)
Browse files Browse the repository at this point in the history
* Add ARCHITECTURE.rst and module docstrings

* fix flake8

Co-authored-by: Henning Jacobs <henning@zalando.de>
  • Loading branch information
RobbeSneyders and hjacobs authored Jul 9, 2021
1 parent 594ded9 commit 2066503
Show file tree
Hide file tree
Showing 48 changed files with 311 additions and 9 deletions.
74 changes: 74 additions & 0 deletions ARCHITECTURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
Architecture
============

This document describes the high-level architecture of Connexion.

.. image:: docs/images/architecture.png
:width: 800
:align: center
:alt: Connexion architecture

Apps
----

A Connexion ``App`` or application wraps a specific framework application (currently Flask or
AioHttp) and exposes a standardized interface for users to create and configure their Connexion
application.

While a Connexion app implements the WSGI interface, it only acts ass a pass-through and doesn't
actually intercept requests and responses. Connexion does all request and response manipulation
by wrapping the user view function in a Connexion ``Operation``. The underlying framework
application handles incoming requests and routes them to the correct Connexion ``Operation``.

Api
---

A connexion ``API`` takes in an OpenAPI specification and translates the operations defined in it to
a set of Connexion ``Operations``. This set of operations is implemented as a framework blueprint
(A `Flask blueprint`_ or framework-specific equivalent), which can be registered on the framework
application.

For each operation, the ``API`` resolves the user view function to link to the operation, wraps it
with a Connexion ``Operation`` which it configures based on the OpenAPI spec, and finally adds it as
a route on the framework blueprint.

When the ``API`` is registered on the Connexion ``APP``, the underlying framework blueprint is
registered on the framework app.

Operations
----------

A Connexion ``Operation`` implements an OpenAPI operation (`swagger 2`_, `OpenAPI 3`_), which
describes a single API operation on a path. It wraps the view function linked to the operation with
decorators to handle security, validation, serialization etc. based on the OpenAPI specification,
and exposes the result to be registered as a route on the application.

These decorators intercept incoming requests and outgoing responses of the operation and allow
Connexion to manipulate them while leaving the routing up to the underlying framework. The split
into separate decorators allows for a clean layered implementation of Connexion functionality.

The result is equivalent to the following user code, but instead Connexion implements this
automatically based on the OpenAPI spec.

.. code-block:: python
@request_response_lifecycle
@secure_endpoint
@validate_inputs
@deserialize_function_inputs
@serialize_function_outputs
@validate_outputs
def user_provided_view_function():
...
Connexion requests and responses
--------------------------------

Connexion defines a request and response interface for internal use. The outermost decorator of
the operation casts framework specific requests to ``ConnexionRequests`` and ``ConnexionResponses``
to framework specific responses.

.. _Flask blueprint: https://flask.palletsprojects.com/en/2.0.x/blueprints/
.. _swagger 2: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md#operation-object
.. _OpenAPI 3: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#operationObject
3 changes: 3 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,9 @@ Contributing to Connexion/TODOs
We welcome your ideas, issues, and pull requests. Just follow the
usual/standard GitHub practices.

You can find out more about how Connexion works and where to apply your changes by having a look
at our `ARCHITECTURE.rst <ARCHITECTURE.rst>`_.

Unless you explicitly state otherwise in advance, any non trivial
contribution intentionally submitted for inclusion in this project by you
to the steward of this repository (Zalando SE, Berlin) shall be under the
Expand Down
9 changes: 9 additions & 0 deletions connexion/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
"""
Connexion is a framework that automagically handles HTTP requests based on OpenAPI Specification
(formerly known as Swagger Spec) of your API described in YAML format. Connexion allows you to
write an OpenAPI specification, then maps the endpoints to your Python functions; this makes it
unique, as many tools generate the specification based on your Python code. You can describe your
REST API in as much detail as you want; then Connexion guarantees that it will work as you
specified.
"""

import sys

import werkzeug.exceptions as exceptions # NOQA
Expand Down
4 changes: 4 additions & 0 deletions connexion/__main__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module provides an entrypoint for Connexion's CLI.
"""

from connexion.cli import main # pragma: no cover

main() # pragma: no cover
15 changes: 15 additions & 0 deletions connexion/apis/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
"""
This module defines Connexion APIs. A connexion API takes in an OpenAPI specification and
translates the operations defined in it to a set of Connexion Operations. This set of operations
is implemented as a framework blueprint (A Flask blueprint or framework-specific equivalent),
which can be registered on the framework application.
For each operation, the API resolves the user view function to link to the operation, wraps it
with a Connexion Operation which it configures based on the OpenAPI spec, and finally adds it as
a route on the framework blueprint.
When the API is registered on the Connexion APP, the underlying framework blueprint is registered
on the framework app.
"""


from .abstract import AbstractAPI # NOQA
4 changes: 4 additions & 0 deletions connexion/apis/abstract.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines an AbstractAPI, which defines a standardized interface for a Connexion API.
"""

import abc
import logging
import pathlib
Expand Down
5 changes: 5 additions & 0 deletions connexion/apis/aiohttp_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines an AioHttp Connexion API which implements translations between AioHttp and
Connexion requests / responses.
"""

import asyncio
import logging
import re
Expand Down
5 changes: 5 additions & 0 deletions connexion/apis/flask_api.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines a Flask Connexion API which implements translations between Flask and
Connexion requests / responses.
"""

import logging
import warnings
from typing import Any
Expand Down
4 changes: 4 additions & 0 deletions connexion/apis/flask_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines utility functions related to the Flask framework.
"""

import functools
import random
import re
Expand Down
5 changes: 5 additions & 0 deletions connexion/apps/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
"""
This module defines Connexion applications. A Connexion App wraps a specific framework application
and exposes a standardized interface for users to create and configure their Connexion application.
"""

from .abstract import AbstractApp # NOQA
5 changes: 5 additions & 0 deletions connexion/apps/abstract.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines an AbstractApp, which defines a standardized user interface for a Connexion
application.
"""

import abc
import logging
import pathlib
Expand Down
4 changes: 4 additions & 0 deletions connexion/apps/aiohttp_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines an AioHttpApp, a Connexion application to wrap an AioHttp application.
"""

import logging
import os.path
import pkgutil
Expand Down
4 changes: 4 additions & 0 deletions connexion/apps/flask_app.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines a FlaskApp, a Connexion application to wrap a Flask application.
"""

import datetime
import logging
import pathlib
Expand Down
5 changes: 5 additions & 0 deletions connexion/cli.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines a command-line interface (CLI) that runs an OpenAPI specification to be a
starting point for developing your API with Connexion.
"""

import logging
import sys
from os import path
Expand Down
3 changes: 3 additions & 0 deletions connexion/decorators/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
This module defines decorators which Connexion uses to wrap user provided view functions.
"""
Empty file.
5 changes: 5 additions & 0 deletions connexion/decorators/decorator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines a BaseDecorator to wrap a user view function and a RequestResponseDecorator
which manages the lifecycle of a request internally in Connexion.
"""

import asyncio
import functools
import logging
Expand Down
5 changes: 5 additions & 0 deletions connexion/decorators/metrics.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines view function decorator to collect UWSGI metrics and expose them via an
endpoint.
"""

import functools
import os
import time
Expand Down
4 changes: 4 additions & 0 deletions connexion/decorators/parameter.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines a decorator to convert request parameters to arguments for the view function.
"""

import builtins
import functools
import inspect
Expand Down
5 changes: 4 additions & 1 deletion connexion/decorators/produces.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Decorators to change the return type of endpoints
"""
This module defines decorators to change the return type of a view function.
"""

import functools
import logging

Expand Down
5 changes: 4 additions & 1 deletion connexion/decorators/response.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Decorators to change the return type of endpoints
"""
This module defines a view function decorator to validate its responses.
"""

import asyncio
import functools
import logging
Expand Down
5 changes: 4 additions & 1 deletion connexion/decorators/uri_parsing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
# Decorators to split query and path parameters
"""
This module defines view function decorators to split query and path parameters.
"""

import abc
import functools
import json
Expand Down
4 changes: 4 additions & 0 deletions connexion/decorators/validation.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines view function decorators to validate request and response parameters and bodies.
"""

import collections
import copy
import functools
Expand Down
6 changes: 5 additions & 1 deletion connexion/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines Exception classes used by Connexion to generate a proper response.
"""

import warnings

from jsonschema.exceptions import ValidationError
Expand All @@ -14,7 +18,7 @@ class ProblemException(ConnexionException):
def __init__(self, status=400, title=None, detail=None, type=None,
instance=None, headers=None, ext=None):
"""
This exception is holds arguments that are going to be passed to the
This exception holds arguments that are going to be passed to the
`connexion.problem` function to generate a proper response.
"""
self.status = status
Expand Down
4 changes: 4 additions & 0 deletions connexion/handlers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines error handlers, operations that produce proper response problems.
"""

import logging

from .exceptions import AuthenticationProblem, ResolverProblem
Expand Down
4 changes: 4 additions & 0 deletions connexion/http_facts.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module contains definitions of the HTTP protocol.
"""

FORM_CONTENT_TYPES = [
'application/x-www-form-urlencoded',
'multipart/form-data'
Expand Down
4 changes: 4 additions & 0 deletions connexion/json_schema.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
Module containing all code related to json schema validation.
"""

from collections.abc import Mapping
from copy import deepcopy

Expand Down
15 changes: 14 additions & 1 deletion connexion/jsonifier.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
"""
This module centralizes all functionality related to json encoding and decoding in Connexion.
"""

import datetime
import json
import uuid


class JSONEncoder(json.JSONEncoder):
"""The default Connexion JSON encoder. Handles extra types compared to the
built-in :class:`json.JSONEncoder`.
- :class:`datetime.datetime` and :class:`datetime.date` are
serialized to :rfc:`822` strings. This is the same as the HTTP
date format.
- :class:`uuid.UUID` is serialized to a string.
"""

def default(self, o):
if isinstance(o, datetime.datetime):
if o.tzinfo:
Expand All @@ -25,7 +38,7 @@ def default(self, o):

class Jsonifier:
"""
Used to serialized and deserialize to/from JSon
Central point to serialize and deserialize to/from JSon in Connexion.
"""
def __init__(self, json_=json, **kwargs):
"""
Expand Down
8 changes: 8 additions & 0 deletions connexion/lifecycle.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
"""
This module defines interfaces for requests and responses used in Connexion for authentication,
validation, serialization, etc.
"""


class ConnexionRequest:
"""Connexion interface for a request."""
def __init__(self,
url,
method,
Expand Down Expand Up @@ -27,6 +34,7 @@ def json(self):


class ConnexionResponse:
"""Connexion interface for a response."""
def __init__(self,
status_code=200,
mimetype=None,
Expand Down
4 changes: 4 additions & 0 deletions connexion/mock.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module contains a mock resolver that returns mock functions for operations it cannot resolve.
"""

import functools
import logging

Expand Down
8 changes: 8 additions & 0 deletions connexion/operations/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
"""
This module defines Connexion Operation classes. A Connexion Operation implements an OpenAPI
operation, which describes a single API operation on a path. It wraps the view function linked to
the operation with decorators to handle security, validation, serialization etc. based on the
OpenAPI specification, and exposes the result to be registered as a route on the application.
"""

from .abstract import AbstractOperation # noqa
from .openapi import OpenAPIOperation # noqa
from .secure import SecureOperation # noqa
Expand Down
5 changes: 5 additions & 0 deletions connexion/operations/abstract.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
"""
This module defines an AbstractOperation class which implements an abstract Operation interface
and functionality shared between Swagger 2 and OpenAPI 3 specifications.
"""

import abc
import logging

Expand Down
4 changes: 3 additions & 1 deletion connexion/operations/compat.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# This is a dummy module for backwards compatibility with < v2.0
"""
This is a dummy module for backwards compatibility with < v2.0.
"""
from .secure import * # noqa
from .swagger2 import * # noqa
4 changes: 4 additions & 0 deletions connexion/operations/openapi.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
"""
This module defines an OpenAPIOperation class, a Connexion operation specific for OpenAPI 3 specs.
"""

import logging
from copy import copy, deepcopy

Expand Down
Loading

0 comments on commit 2066503

Please sign in to comment.