Swagger/OpenAPI First framework for Python on top of Flask with automatic endpoint validation & OAuth2 support

Overview

Connexion

Join the chat at https://gitter.im/zalando/connexion Travis CI build status Coveralls status Latest Version Development Status Python Versions License

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.

We built Connexion this way in order to:

  • simplify the development process
  • confirm expectations about what your API will look like

Connexion Features:

  • Validates requests and endpoint parameters automatically, based on your specification
  • Provides a Web Swagger Console UI so that the users of your API can have live documentation and even call your API's endpoints through it
  • Handles OAuth 2 token-based authentication
  • Supports API versioning
  • Supports automatic serialization of payloads. If your specification defines that an endpoint returns JSON, Connexion will automatically serialize the return value for you and set the right content type in the HTTP header.

Why Connexion

With Connexion, you write the spec first. Connexion then calls your Python code, handling the mapping from the specification to the code. This incentivizes you to write the specification so that all of your developers can understand what your API does, even before you write a single line of code.

If multiple teams depend on your APIs, you can use Connexion to easily send them the documentation of your API. This guarantees that your API will follow the specification that you wrote. This is a different process from that offered by frameworks such as Hug, which generates a specification after you've written the code. Some disadvantages of generating specifications based on code is that they often end up lacking details or mix your documentation with the code logic of your application.

Other Sources/Mentions

New in Connexion 2.0:

  • App and Api options must be provided through the "options" argument (old_style_options have been removed).
  • You must specify a form content-type in 'consumes' in order to consume form data.
  • The Operation interface has been formalized in the AbstractOperation class.
  • The Operation class has been renamed to Swagger2Operation.
  • Array parameter deserialization now follows the Swagger 2.0 spec more closely. In situations when a query parameter is passed multiple times, and the collectionFormat is either csv or pipes, the right-most value will be used. For example, ?q=1,2,3&q=4,5,6 will result in q = [4, 5, 6]. The old behavior is available by setting the collectionFormat to multi, or by importing decorators.uri_parsing.AlwaysMultiURIParser and passing parser_class=AlwaysMultiURIParser to your Api.
  • The spec validator library has changed from swagger-spec-validator to openapi-spec-validator.
  • Errors that previously raised SwaggerValidationError now raise the InvalidSpecification exception. All spec validation errors should be wrapped with InvalidSpecification.
  • Support for nullable/x-nullable, readOnly and writeOnly/x-writeOnly has been added to the standard json schema validator.
  • Custom validators can now be specified on api level (instead of app level).
  • Added support for basic authentication and apikey authentication
  • If unsupported security requirements are defined or x-tokenInfoFunc/x-tokenInfoUrl is missing, connexion now denies requests instead of allowing access without security-check.
  • Accessing connexion.request.user / flask.request.user is no longer supported, use connexion.context['user'] instead

How to Use

Prerequisites

Python 3.6+

Installing It

In your command line, type:

$ pip install connexion

Running It

Place your API YAML inside a folder in the root path of your application (e.g swagger/). Then run:

import connexion

app = connexion.App(__name__, specification_dir='swagger/')
app.add_api('my_api.yaml')
app.run(port=8080)

See the Connexion Pet Store Example Application for a sample specification.

Now you're able to run and use Connexion!

OAuth 2 Authentication and Authorization

Connexion supports one of the three OAuth 2 handling methods. (See "TODO" below.) With Connexion, the API security definition must include a 'x-tokenInfoUrl' or 'x-tokenInfoFunc (or set TOKENINFO_URL or TOKENINFO_FUNC env var respectively). 'x-tokenInfoUrl' must contain an URL to validate and get the token information and 'x-tokenInfoFunc must contain a reference to a function used to obtain the token info. When both 'x-tokenInfoUrl' and 'x-tokenInfoFunc' are used, Connexion will prioritize the function method. Connexion expects to receive the OAuth token in the Authorization header field in the format described in RFC 6750 section 2.1. This aspect represents a significant difference from the usual OAuth flow.

Dynamic Rendering of Your Specification

Connexion uses Jinja2 to allow specification parameterization through the arguments parameter. You can define specification arguments for the application either globally (via the connexion.App constructor) or for each specific API (via the connexion.App#add_api method):

app = connexion.App(__name__, specification_dir='swagger/',
                    arguments={'global': 'global_value'})
app.add_api('my_api.yaml', arguments={'api_local': 'local_value'})
app.run(port=8080)

When a value is provided both globally and on the API, the API value will take precedence.

Endpoint Routing to Your Python Views

Connexion uses the operationId from each Operation Object to identify which Python function should handle each URL.

Explicit Routing:

paths:
  /hello_world:
    post:
      operationId: myapp.api.hello_world

If you provide this path in your specification POST requests to http://MYHOST/hello_world, it will be handled by the function hello_world in the myapp.api module. Optionally, you can include x-swagger-router-controller (or x-openapi-router-controller) in your operation definition, making operationId relative:

paths:
  /hello_world:
    post:
      x-swagger-router-controller: myapp.api
      operationId: hello_world

Keep in mind that Connexion follows how HTTP methods work in Flask and therefore HEAD requests will be handled by the operationId specified under GET in the specification. If both methods are supported, connexion.request.method can be used to determine which request was made.

Automatic Routing

To customize this behavior, Connexion can use alternative Resolvers--for example, RestyResolver. The RestyResolver will compose an operationId based on the path and HTTP method of the endpoints in your specification:

from connexion.resolver import RestyResolver

app = connexion.App(__name__)
app.add_api('swagger.yaml', resolver=RestyResolver('api'))
paths:
  /:
    get:
       # Implied operationId: api.get
  /foo:
    get:
       # Implied operationId: api.foo.search
    post:
       # Implied operationId: api.foo.post

  '/foo/{id}':
    get:
       # Implied operationId: api.foo.get
    put:
       # Implied operationId: api.foo.put
    copy:
       # Implied operationId: api.foo.copy
    delete:
       # Implied operationId: api.foo.delete

RestyResolver will give precedence to any operationId encountered in the specification. It will also respect x-router-controller. You can import and extend connexion.resolver.Resolver to implement your own operationId (and function) resolution algorithm.

Automatic Parameter Handling

Connexion automatically maps the parameters defined in your endpoint specification to arguments of your Python views as named parameters, and, whenever possible, with value casting. Simply define the endpoint's parameters with the same names as your views arguments.

As an example, say you have an endpoint specified as:

paths:
  /foo:
    get:
      operationId: api.foo_get
      parameters:
        - name: message
          description: Some message.
          in: query
          type: string
          required: true

And the view function:

# api.py file

def foo_get(message):
    # do something
    return 'You send the message: {}'.format(message), 200

In this example, Connexion automatically recognizes that your view function expects an argument named message and assigns the value of the endpoint parameter message to your view function.

Note

In the OpenAPI 3.x.x spec, the requestBody does not have a name. By default it will be passed in as 'body'. You can optionally provide the x-body-name parameter in your requestBody schema to override the name of the parameter that will be passed to your handler function.

Warning

When you define a parameter at your endpoint as not required, and this argument does not have default value in your Python view, you will get a "missing positional argument" exception whenever you call this endpoint WITHOUT the parameter. Provide a default value for a named argument or use **kwargs dict.

Type casting

Whenever possible, Connexion will try to parse your argument values and do type casting to related Python native values. The current available type castings are:

OpenAPI Type Python Type
integer int
string str
number float
boolean bool
array list
null None
object dict

If you use the array type In the Swagger definition, you can define the collectionFormat so that it won't be recognized. Connexion currently supports collection formats "pipes" and "csv". The default format is "csv".

Connexion is opinionated about how the URI is parsed for array types. The default behavior for query parameters that have been defined multiple times is to use the right-most value. For example, if you provide a URI with the the query string ?letters=a,b,c&letters=d,e,f, connexion will set letters = ['d', 'e', 'f'].

You can override this behavior by specifying the URI parser in the app or api options.

from connexion.decorators.uri_parsing import AlwaysMultiURIParser
options = {'uri_parser_class': AlwaysMultiURIParser}
app = connexion.App(__name__, specification_dir='swagger/', options=options)

You can implement your own URI parsing behavior by inheriting from connexion.decorators.uri_parsing.AbstractURIParser.

There are a handful of URI parsers included with connection.

OpenAPIURIParser default: OpenAPI 3.0 This parser adheres to the OpenAPI 3.x.x spec, and uses the style parameter. Query parameters are parsed from left to right, so if a query parameter is defined twice, then the right-most definition will take precedence. For example, if you provided a URI with the query string ?letters=a,b,c&letters=d,e,f, and style: simple, then connexion will set letters = ['d', 'e', 'f']. For additional information see OpenAPI 3.0 Style Values.
Swagger2URIParser default: OpenAPI 2.0 This parser adheres to the Swagger 2.0 spec, and will only join together multiple instance of the same query parameter if the collectionFormat is set to multi. Query parameters are parsed from left to right, so if a query parameter is defined twice, then the right-most definition wins. For example, if you provided a URI with the query string ?letters=a,b,c&letters=d,e,f, and collectionFormat: csv, then connexion will set letters = ['d', 'e', 'f']
FirstValueURIParser This parser behaves like the Swagger2URIParser, except that it prefers the first defined value. For example, if you provided a URI with the query string ?letters=a,b,c&letters=d,e,f and collectionFormat: csv hen connexion will set letters = ['a', 'b', 'c']
AlwaysMultiURIParser This parser is backwards compatible with Connexion 1.x. It joins together multiple instances of the same query parameter.

Parameter validation

Connexion can apply strict parameter validation for query and form data parameters. When this is enabled, requests that include parameters not defined in the swagger spec return a 400 error. You can enable it when adding the API to your application:

app.add_api('my_apy.yaml', strict_validation=True)

API Versioning and basePath

Setting a base path is useful for versioned APIs. An example of a base path would be the 1.0 in http://MYHOST/1.0/hello_world.

If you are using OpenAPI 3.x.x, you set your base URL path in the servers block of the specification. You can either specify a full URL, or just a relative path.

servers:
  - url: https://MYHOST/1.0
    description: full url example
  - url: /1.0
    description: relative path example

paths:
  ...

If you are using OpenAPI 2.0, you can define a basePath on the top level of your OpenAPI 2.0 specification.

basePath: /1.0

paths:
  ...

If you don't want to include the base path in your specification, you can provide it when adding the API to your application:

app.add_api('my_api.yaml', base_path='/1.0')

Swagger JSON

Connexion makes the OpenAPI/Swagger specification in JSON format available from either swagger.json (for OpenAPI 2.0) or openapi.json (for OpenAPI 3.x.x) at the base path of the API. For example, if your base path was 1.0, then your spec would be available at /1.0/openapi.json.

You can disable serving the spec JSON at the application level:

options = {"serve_spec": False}
app = connexion.App(__name__, specification_dir='openapi/',
                    options=options)
app.add_api('my_api.yaml')

You can also disable it at the API level:

options = {"serve_spec": False}
app = connexion.App(__name__, specification_dir='openapi/')
app.add_api('my_api.yaml', options=options)

HTTPS Support

When specifying HTTPS as the scheme in the API YAML file, all the URIs in the served Swagger UI are HTTPS endpoints. The problem: The default server that runs is a "normal" HTTP server. This means that the Swagger UI cannot be used to play with the API. What is the correct way to start a HTTPS server when using Connexion?

One way, described by Flask, looks like this:

from OpenSSL import SSL
context = SSL.Context(SSL.SSLv23_METHOD)
context.use_privatekey_file('yourserver.key')
context.use_certificate_file('yourserver.crt')

app.run(host='127.0.0.1', port='12344',
        debug=False/True, ssl_context=context)

However, Connexion doesn't provide an ssl_context parameter. This is because Flask doesn't, either--but it uses **kwargs to send the parameters to the underlying werkzeug server.

The Swagger UI Console

The Swagger UI for an API is available through pip extras. You can install it with pip install connexion[swagger-ui]. It will be served up at {base_path}/ui/ where base_path is the base path of the API.

You can disable the Swagger UI at the application level:

app = connexion.App(__name__, specification_dir='openapi/',
                    options={"swagger_ui": False})
app.add_api('my_api.yaml')

You can also disable it at the API level:

app = connexion.App(__name__, specification_dir='openapi/')
app.add_api('my_api.yaml', options={"swagger_ui": False})

If necessary, you can explicitly specify the path to the directory with swagger-ui to not use the connexion[swagger-ui] distro. In order to do this, you should specify the following option:

options = {'swagger_path': '/path/to/swagger_ui/'}
app = connexion.App(__name__, specification_dir='openapi/', options=options)

If you wish to provide your own swagger-ui distro, note that connexion expects a jinja2 file called swagger_ui/index.j2 in order to load the correct swagger.json by default. Your index.j2 file can use the openapi_spec_url jinja variable for this purpose:

const ui = SwaggerUIBundle({ url: "{{ openapi_spec_url }}"})

Additionally, if you wish to use swagger-ui-3.x.x, it is also provided by installing connexion[swagger-ui], and can be enabled like this:

from swagger_ui_bundle import swagger_ui_3_path
options = {'swagger_path': swagger_ui_3_path}
app = connexion.App(__name__, specification_dir='swagger/', options=options)

Server Backend

By default Connexion uses the Flask server. For asynchronous applications, you can also use Tornado as the HTTP server. To do this, set your server to tornado:

import connexion

app = connexion.App(__name__, specification_dir='swagger/')
app.run(server='tornado', port=8080)

You can use the Flask WSGI app with any WSGI container, e.g. using Flask with uWSGI (this is common):

app = connexion.App(__name__, specification_dir='swagger/')
application = app.app # expose global WSGI application object

You can use the aiohttp framework as server backend as well:

import connexion

app = connexion.AioHttpApp(__name__, specification_dir='swagger/')
app.run(port=8080)

Note

Also check aiohttp handler examples.

Set up and run the installation code:

$ sudo pip3 install uwsgi
$ uwsgi --http :8080 -w app -p 16  # use 16 worker processes

See the uWSGI documentation for more information.

Documentation

Additional information is available at Connexion's Documentation Page.

Changes

A full changelog is maintained on the GitHub releases page.

Contributing to Connexion/TODOs

We welcome your ideas, issues, and pull requests. Just follow the usual/standard GitHub practices.

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 terms and conditions of Apache License 2.0 written below, without any additional copyright information, terms or conditions.

TODOs

If you'd like to become a more consistent contributor to Connexion, we'd love your help working on these we have a list of issues where we are looking for contributions.

Thanks

We'd like to thank all of Connexion's contributors for working on this project, and to Swagger/OpenAPI for their support.

License

Copyright 2015 Zalando SE

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Comments
  • OpenAPI v3 support

    OpenAPI v3 support

    Just curious about OpenAPI 3 support plans.

    See related post about Swagger 2 and OpenAPI 3 introduction: https://blog.readme.io/an-example-filled-guide-to-swagger-3-2/

    enhancement 
    opened by tomas-fp 88
  • Fix operation ID handling

    Fix operation ID handling

    Fixes error handling when dealing with bad operation IDs. Any of the following now lead to a ResolverError, which is easier to understand in the server logs:

    • A module that fails to import cleanly (e.g fakeapi/module_with_error.py)
    • A completely missing operationId
    • An operationId that specifies an unresolvable module/function

    Mostly, the last class leads to very bad error messages about NoneType not having an rsplit function - completely true, but also devoid of any useful information.

    I'll follow up with another PR that uses this change, too.

    (Note: the change to setup.py is technically out of scope, but it's a one-liner. It ensures that when you're using virtualenv, python setup.py test doesn't fail because some library in the virtualenv path breaks the tests. If you insist, I'll make it a separate PR).

    opened by jfinkhaeuser 42
  • Added aiohttp support

    Added aiohttp support

    Hello Guys, I implemented an App and Api classes supporting aiohttp framework. It is fully tested. I had did some modifications on the base code as well. Please, take a look on it

    opened by dutradda 41
  • Run an API spec, no boilerplate needed

    Run an API spec, no boilerplate needed

    Currently creating or developing an API with Connexion means that you need to Copy&Paste® a little boilerplate (small, but still) code.

    import connexion
    
    app = connexion.App(__name__, specification_dir='swagger/')
    app.add_api('my_api.yaml')
    app.run(port=8080)
    

    Plus would be nice to configure some logging, more Copy&Paste®.

    import logging
    logging.basicConfig(level=logging.DEBUG)
    

    Then would be nice to have a command line to run the project. Let me Copy&Paste® this little CLI tool boilerplate code structure.

    import click
    @click.command()
    def run():
        ...
    

    Alternatively, we could provide this minimal set of common practices of creating apps using Connexion bundled already within the installation of Connexion itself. To create a Microservice using Connexion, developers would only need to worry about the OpenAPI specification and the actual business logic/Python code. Then run the server using:

    $ connexion run my_api.yaml
    

    or

    $ connexion run my_api.yaml -p 8080 --debug
    

    Other use case is when during the development we want to run the server with partially implemented endpoints. Just run it:

    $ connexion run my_unfinished_api.yaml --stub
    

    Endpoints not implemented yet will return an error message saying that the operation is not yet implemented.

    Those changes will make Connexion sail smoothly and providing fast satisfactory results will definitely improve the success of Connexion.

    _Important to notice_ This is not a breaking change and all other functionality continues to work the same.

    Changes proposed in this pull request:

    • Adds a the class StubResolver to provide a easy way to stub not implemented or not found operations;
    • Adds a command line tool for running specifications (connexion).

    I hope you will like it! ❤️

    opened by rafaelcaricio 38
  • Frameworks passing

    Frameworks passing

    Hello guys,

    I am doing a PR in master because I rewrite the frameworks branch. Now all testing are passing and flask are full uncouple.

    @rafaelcaricio this just a API proposal

    opened by dutradda 37
  • Finalize 2.0 Release

    Finalize 2.0 Release

    Description

    We created the dev-2.0 branch to introduce a handful of major breaking changes to connexion. https://github.com/zalando/connexion/milestone/10

    At the time, the two major changes were:

    • python-jsonschema/referencing#4 openapi 3 support
    • python-jsonschema/jsonschema#406 removing vendored swagger-ui

    Both of these changes are now in dev-2.0

    Next Steps

    What other things should be in the 2.0 release? Is it large enough as is? What's could be better? It would be great to finalize the feature set for Connexion 2.0 and get it shipped! :ship:

    Let me know what you think!

    opened by dtkav 28
  • Serve correct openapi spec basepath when path is altered by reverse-proxy

    Serve correct openapi spec basepath when path is altered by reverse-proxy

    Fixes #820 Fixes #392 Fixes #527

    Changes proposed in this pull request:

    • change swagger-ui, and openapi spec location to build the path using url_for
    • modify the openapi spec basePath or servers block to include the reversed api path
    • modify the swagger-ui page to load the reversed openapi spec using url_for
    • add a openapi3/reverseproxy example
    • add a openapi3/reverseproxy_aiohttp example

    Thanks to @Jyhess for the collaboration, tests, and review!

    ready swagger ui feature 
    opened by dtkav 25
  • Add support for JWT authentication

    Add support for JWT authentication

    Fixes #389, #607 .

    Changes proposed in this pull request:

    • For swagger 2.0 add support for x-authentication-scheme=bearer in apiKey method.
    • For OpenAPI 3.0 add support for scheme=bearer in http method
    • Use x-bearerInfoFunc in security definition or BEARERINFO_FUNC env variable to pass a reference to token validation function
    opened by krise3k 24
  • Remove Swagger UI vendor code

    Remove Swagger UI vendor code

    Today Connexion hosts a vendor of Swagger UI code. This is a highly unmaintainable code which is even customized for Connexion needs. We have to review this approach.

    We need to find an alternative way to have the support to Swagger UI in Connexion projects which must not need to have the whole vendor code inside Connexion.

    enhancement help wanted swagger ui 
    opened by rafaelcaricio 22
  • Support the flask url variable converter

    Support the flask url variable converter "path"

    The Flask variable converter "path" allows url variables to include forward slashes in their values. This PR adds support for that feature if the Swagger specification indicates that a route parameter's format is "path".

    Example:

    parameters:
      - name: name
        in: path
        required: true
        format: path
        type: string
    

    will add a route parameter <path:name>.

    Excerpt from the Swagger specification:

    the format property is an open string-valued property, and can have any value to support documentation needs. Formats such as "email", "uuid", etc., can be used even though they are not defined by this specification.

    opened by patrickw276 22
  • OAuth: When verifying token, do not pass the access_token as query param

    OAuth: When verifying token, do not pass the access_token as query param

    In decorators/security.py - verify_oauth, a session.get() call is made to the token_info_url and the access_token to be verified is passed as a query parameter. According to the OAuth 2.0 Authorization Framework: Bearer Token Usage, section 5.3 ( https://tools.ietf.org/html/rfc6750#section-5.3 ):

    Don't pass bearer tokens in page URLs: Bearer tokens SHOULD NOT be passed in page URLs (for example, as query string parameters). Instead, bearer tokens SHOULD be passed in HTTP message headers or message bodies for which confidentiality measures are taken. Browsers, web servers, and other software may not adequately secure URLs in the browser history, web server logs, and other data structures. If bearer tokens are passed in page URLs, attackers might be able to steal them from the history data, logs, or other unsecured locations.

    I propose that this code is changed to something along these lines:

    token_request = session.post(token_info_url, json={'access_token': token}, timeout=5)

    enhancement 
    opened by JoshStutts 22
  • Type inference for Flask app object wrong in VS Code

    Type inference for Flask app object wrong in VS Code

    Description

    When creating a FlaskApp with connexion, the type information for the wrapped Flask app object is inferred wrong by VS Code with Pylance. While I do understand that type support has not been added to Connexion yet, it would be extremely helpful to at least be able if the editor would be able to infer the type of the wrapped app, so that one could make use of autosuggestion features and access config values without type checkers complaining.

    I am not sure whether this is a problem with Connexion or with VS Code or Pylance, and whether it needs a fix or whether I am just doing something wrong (or there is, at least, a workaround).

    Thanks for the great work on Connexion, btw, love it!

    Expected behaviour

    The type of the wrapped app should be inferred as flask.Flask.

    Actual behaviour

    The type of the wrapped app is inferred as None. See the following screenshot:

    Screenshot from 2023-01-03 11-49-35

    Screenshot from VS Code, type infernence presumably based on Pylance extension.

    Note that the tooltip refers to the type of app.app, not app (whose type is correctly inferred as connexion.apps.FlaskApp).

    Steps to reproduce

    Install Connexion as per the instructions. Create a file with the following contents, based on the quickstart instructions.

    import connexion
    
    app = connexion.FlaskApp(__name__, specification_dir='openapi/')
    app.app
    

    Open in VS Code and hover over the second app in app.app.

    Additional info:

    Editor

    Version: 1.74.2 Commit: e8a3071ea4344d9d48ef8a4df2c097372b0c5161 Date: 2022-12-20T10:27:19.253Z Electron: 19.1.8 Chromium: 102.0.5005.167 Node.js: 16.14.2 V8: 10.2.154.15-electron.0 OS: Linux x64 5.4.0-135-generic snap Sandboxed: No

    Pylance

    Name: Pylance Id: ms-python.vscode-pylance Description: A performant, feature-rich language server for Python in VS Code Version: 2022.12.20 Publisher: Microsoft VS Marketplace Link: https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance

    Output of the commands:

    • python --version: Python 3.10.7 (tried other versions, from 3.7 to 3.10, same result)

    • pip show connexion | grep "^Version\:" Version: 2.14.1 (tried other versions, same result)

    opened by uniqueg 0
  • Enable enforcing defaults

    Enable enforcing defaults

    This PR is a proposal to enforce defaults in json bodies.

    I'm not sure which way to go here

    • I think connexion should offer the functionality to fill in the defaults, as this helps enforce the contract. If a value is not provided, the application gets the default. We should probably offer this using a simple default flag instead of the custom validator now needed.
    • I don't like that validation adapts the body. Validation is a read-only operation and it would be nice to keep it that way.
    • Splitting enforcing defaults from validation would be less efficient since we'd need to traverse the body multiple times.

    If we do want to go this way, we should probably implement a similar fix for form data, as we also use json validators there.

    opened by RobbeSneyders 0
  • How to validate method at operationId matches openapi schema

    How to validate method at operationId matches openapi schema

    Is there any way to statically check, ahead of making api calls, that a method defined as the operationId of some path actually matches the schema specified by openapi manifest?

    opened by ReallyLiri 3
  • How do I use JSON content instead of schema in GET request?

    How do I use JSON content instead of schema in GET request?

    Description

    Swagger UI says that we can wrap schema into content.media-type in GET request instead of using only schema. However, mapping the content.media-type to function arguments in Connexion doesn't seem to work. Am I doing something wrong?

    Here's a snap of the error:

    python3.8/site-packages/connexion/operations/openapi.py", line 430, in _get_val_from_param
        query_schema = query_defn["schema"]
    KeyError: 'schema'
    

    Here's a sample path config:

    /trial:
        get:
            operationId: test
            parameters:
              - name: filter
                in: query
                description: Filters on data
                required: false
                content:
                  application/json:
                    schema:
                      type: object
                      properties:
                        id:
                          type: string
                          example: hello
    

    Here's a sample function:

    def test(filter={}):
        return filter
    

    Connexion Version: 2.14.1 Python 3.8.5

    opened by mdylan2 1
  • Infinite loop on validation with recursive references and unresolved refs

    Infinite loop on validation with recursive references and unresolved refs

    Description

    Having an OpenAPI 3.0 spec with these two conditions:

    • includes a remote $ref deeply nested inside a locally resolved $ref
    • includes a schema with a circular references

    Causes infinite loop when trying to validate the request body using jsonschema.

    Expected behaviour

    The infinite loop does not happen, validation is done and response is served.

    Actual behaviour

    Code enters an infinite loop and server never responds

    Steps to reproduce

    import connexion
    
    
    def view(*data):
        return {}
    
    app = connexion.FlaskApp(__name__, specification_dir='openapi/')
    app.add_api('my_api.yaml')
    app.run(port=8080)
    

    my_api.yaml

    openapi: 3.0.0
    info:
      title: Sample API
      description: Optional
      version: '0.1'
    
    servers:
      - url: http://api.example.com
        description: Optional server description, e.g. Main (production) server
    
    paths:
      /:
        post:
          operationId: 'main.view'
          summary: S
          description: D
          responses:
            '200':
              description: A JSON array of user names
              content:
                application/json:
                  schema: 
                    type: object
          requestBody:
            content:
              application/json:
                schema:
                  type: object
                  properties:
                    foo:
                      $ref: '#/components/schemas/Foo'
                    bar:
                      $ref: '#/components/schemas/Bar'
    
    components:
      schemas:
        Foo:
          type: array
          items:
            $ref: 'file:///tmp/connextest/openapi/referred_schema.json#/components/schemas/FooElement'
        Bar:
          type: object
          properties:
            child:
              $ref: '#/components/schemas/Bar'
        FooElement:
          type: string
    

    /tmp/referred_schema.json

    {
        "components": {
            "schemas": {
                "FooElement": {
                    "type": "string"
                }
            }
        }
    }
    

    To generate infinite loop:

    $ python main.py &
    $ echo '{"foo": [1], "bar": {}}' | http POST :8080/ 'Content-Type: application/json'
    

    Additional info:

    • In the example above components.schemas.Bar.properties.child is the recursive reference.

    • components.schemas.Foo.items is the unsolved $ref.

    • components.schemas.Foo.items is unresolved due to resolve_refs implementation (missing recursive call in 'try' path if '$ref' is missing)

    • components.schemas.Bar.properties.child is resolved with a circular reference to components.schemas.Bar

    • jsonschema receives the schema with the circular reference, and crashes when trying to solve the unsolved $ref

    I see two possible roads to fix the issue:

    • fix the recursion in resolve_refs also for resolved nodes not directly including a $ref, but maybe with a nested $ref
    • avoid resolving refs altogether in components.schemas. jsonschema is perfectly able to solve the refs while validating, why connexion needs to solve everything in advance ?

    Output of the commands:

    $ python --version
    Python 3.10.7
    $ pip show connexion | grep "^Version\:"
    Version: 2.14.1
    
    opened by gaetano-guerriero 0
Releases(2.14.1)
  • 2.14.1(Aug 23, 2022)

    What's Changed

    • Don't interpret simple parameter as deepObject by @fgreinacher in https://github.com/spec-first/connexion/pull/1570

    New Contributors

    • @fgreinacher made their first contribution in https://github.com/spec-first/connexion/pull/1570

    Full Changelog: https://github.com/spec-first/connexion/compare/2.14.0...2.14.1

    Source code(tar.gz)
    Source code(zip)
  • 2.14.0(Jun 22, 2022)

    What's Changed

    • openapi: remove JSON body second validation and type casting by @p4l1ly in https://github.com/spec-first/connexion/pull/1170
      • Connexion no longer casts numbers to float
    • Fix OpenAPI parameters containing other parameters by @rickpr in https://github.com/spec-first/connexion/pull/1523
    • Only warn about the schema's x-body-name being deprecated if it's used. by @lanzkron in https://github.com/spec-first/connexion/pull/1554

    New Contributors

    • @rickpr made their first contribution in https://github.com/spec-first/connexion/pull/1523
    • @lanzkron made their first contribution in https://github.com/spec-first/connexion/pull/1554

    Full Changelog: https://github.com/spec-first/connexion/compare/2.13.1...2.14.0

    Source code(tar.gz)
    Source code(zip)
  • 2.13.1(Apr 27, 2022)

    What's Changed

    • Fix uri parsing for query parameter with empty brackets by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1501
    • Update tests for changed werkzeug behavior in 2.1 by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1506
    • Bugfix/async security check by @Ruwann in https://github.com/spec-first/connexion/pull/1512

    Full Changelog: https://github.com/spec-first/connexion/compare/2.13.0...2.13.1

    Source code(tar.gz)
    Source code(zip)
  • 2.13.0(Mar 22, 2022)

    What's Changed

    • [FIX] MethodViewResolver CamelCase Methods by @jdkent in https://github.com/spec-first/connexion/pull/1467
    • Fix and add example for enforced defaults for aiohttp by @p4l1ly in https://github.com/spec-first/connexion/pull/1163
    • lifecycle: add cookies attribute to ConnexionRequest (#1168) by @noirbee in https://github.com/spec-first/connexion/pull/1209
    • upgrade pyYAML supported versions in setup.py by @jonasboecquaert in https://github.com/spec-first/connexion/pull/1478
    • Move x-body-name to requestBody level by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1475
    • Save memory on unused schema strings by @vmarkovtsev in https://github.com/spec-first/connexion/pull/1482
    • Add link to Flask JSONEncoder documentation by @Ruwann in https://github.com/spec-first/connexion/pull/1484
    • Remove obsolete code from basicauth example by @a-a-abramov in https://github.com/spec-first/connexion/pull/1486
    • Rework required_scopes checking by @Ruwann in https://github.com/spec-first/connexion/pull/1474
    • Drop pkg_resources by @Ruwann in https://github.com/spec-first/connexion/pull/1499

    New Contributors

    • @jdkent made their first contribution in https://github.com/spec-first/connexion/pull/1467
    • @p4l1ly made their first contribution in https://github.com/spec-first/connexion/pull/1163
    • @noirbee made their first contribution in https://github.com/spec-first/connexion/pull/1209
    • @jonasboecquaert made their first contribution in https://github.com/spec-first/connexion/pull/1478
    • @vmarkovtsev made their first contribution in https://github.com/spec-first/connexion/pull/1482
    • @a-a-abramov made their first contribution in https://github.com/spec-first/connexion/pull/1486

    Full Changelog: https://github.com/spec-first/connexion/compare/2.12.0...2.13.0

    Source code(tar.gz)
    Source code(zip)
  • 2.12.0(Feb 23, 2022)

    What's Changed

    • Fix for aiohttp and multipart/form-data uploads by @ddurham2 in https://github.com/spec-first/connexion/pull/1222
    • Don't validate streamed responses by @cshorler in https://github.com/spec-first/connexion/pull/1259
    • Fix version of Flask subdependencies by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1465
    • Drop openapi-spec-validator for custom ref handler by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1455

    New Contributors

    • @cshorler made their first contribution in https://github.com/spec-first/connexion/pull/1259

    Full Changelog: https://github.com/spec-first/connexion/compare/2.11.2...2.12.0

    Source code(tar.gz)
    Source code(zip)
  • 2.11.2(Feb 18, 2022)

    What's Changed

    • Change deprecated aiohttp req.has_body to req.can_read_body by @cbosborn in https://github.com/spec-first/connexion/pull/1296
    • Take into account (x-)nullable when validating defaults by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1463

    New Contributors

    • @cbosborn made their first contribution in https://github.com/spec-first/connexion/pull/1296

    Full Changelog: https://github.com/spec-first/connexion/compare/2.11.1...2.11.2

    Source code(tar.gz)
    Source code(zip)
  • 2.11.1(Feb 9, 2022)

    What's Changed

    • Add Python 3.9 to supported versions in setup.py by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1459

    Full Changelog: https://github.com/spec-first/connexion/compare/2.11.0...2.11.1

    Source code(tar.gz)
    Source code(zip)
  • 2.11.0(Feb 8, 2022)

    What's Changed

    • Bump upperbound version for jsonschema to 5.0.0 by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1447
    • Fix sanitization of function arguments by @Ruwann in https://github.com/spec-first/connexion/pull/1442
    • Reload Flask on API file changes by @aparcar in https://github.com/spec-first/connexion/pull/1418
    • Use both class docstring and init docstring for autoapi by @Ruwann in https://github.com/spec-first/connexion/pull/1451
    • Automate release process via github actions by @RobbeSneyders in https://github.com/spec-first/connexion/pull/1441, https://github.com/spec-first/connexion/pull/1454, https://github.com/spec-first/connexion/pull/1456
    • fix-square bracket : V1 by @LeComptoirDesPharmacies in https://github.com/spec-first/connexion/pull/1408

    New Contributors

    • @aparcar made their first contribution in https://github.com/spec-first/connexion/pull/1418
    • @LeComptoirDesPharmacies made their first contribution in https://github.com/spec-first/connexion/pull/1408

    Full Changelog: https://github.com/spec-first/connexion/compare/2.10.0...2.11.0

    Source code(tar.gz)
    Source code(zip)
  • 2.10.0(Nov 14, 2021)

    Note

    ~Due to unavailability of maintainers with access to the connexion PyPi project, this version has been released under a new PyPi project connexion2 for now: https://pypi.org/project/connexion2/~

    EDIT 15/01/2022: This version is now available under the main PyPi repository: https://pypi.org/project/connexion/2.10.0/

    Changelog

    • Bump Flask & Werkzeug major versions to 2.x #1402
    • Send request exception signal in common exception handler #1326
    • Render correct UI template when serving multiple APIs #1404
    • Use jsonschema for validation instead of openapi_spec_validator #936
    • Add Relative resolver #1419
    • Add keywords to the list of pythonic words #1425
    • Improved error 415 #1185

    Full Changelog: https://github.com/zalando/connexion/compare/2.9.0...2.10.0

    Source code(tar.gz)
    Source code(zip)
  • 2.9.0(Jul 16, 2021)

    Release with new (backwards-compatible) features: https://pypi.org/project/connexion/2.9.0/

    Notable changes:

    • support required: false for headers #1293
    • support multiple security schemes #1290
    • better handling of numerical path parameters in Flask #1290

    Detailed list of changes: https://github.com/zalando/connexion/milestone/12

    Source code(tar.gz)
    Source code(zip)
  • 2.8.0(Jul 8, 2021)

    New maintenance/bugfix release https://pypi.org/project/connexion/2.8.0/

    See https://github.com/zalando/connexion/milestone/11 for list of changes

    Source code(tar.gz)
    Source code(zip)
  • 2.7.0(Apr 25, 2020)

    • Objects and Arrays recursively construct examples (#1148)
    • Added server_args parameter to AbstractApp (#1173)
    • AIOHTTP: get rid of @asyncio.coroutine (deprecated in Python 3.8) (#1186)
    • AIOHTTP: fix _framework_to_connexion_response for StreamResponse (#1217)
    Source code(tar.gz)
    Source code(zip)
  • 2.6.0(Jan 29, 2020)

    • Fix variable scoping (#1110)
    • Fix aiohttp access_log duplicated if passed as argument (#1113)
    • Fix pythonic params (#1116)
    • Fix extra formData (#1020)
    • Fix nested additionalProperties (#1138)
    • Allow empty security definition
    Source code(tar.gz)
    Source code(zip)
  • 2.5.1(Dec 19, 2019)

  • 2.5.0(Dec 16, 2019)

    • Drop Python 2.7 support, support Python 3.8
    • Convert responses to raise ProblemException (#955)
    • Add error path to schema validation
    • Do not sanitize body keys in OpenAPI 3 (#1008)
    • Date/time serialization (#851)
    • Forward options to AioHTTP app (#885)
    • Returning tuples supported in AioHTTP (#849)
    • Allow Swagger UI configuration options (#948)
    • Remove security parameter to pass query validation (#470)
    • Allow users to enable debug mode via environment variable
    Source code(tar.gz)
    Source code(zip)
  • 2.4.0(Oct 18, 2019)

    • Handle deepObject and explode: true (#971)
    • Support jsonschema > 3.0.0 (#1050)
    • Drop Python 3.4 and 3.5. Add Python 3.8 (#1056)
    • Fix deprecated import (#1044)
    • Bump Flask version (#995)
    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Jun 14, 2019)

    • AioHttpApi oauth middleware catches all OAuth problems (#830)
    • Serve YAML spec (#842)
    • Added MethodViewResolver (#847)
    • Fix swagger console backslash redirect for aiohttp (#843)
    • Fix uwsgi metric collection (#972)
    • Respond with problems by default in aiohttp (#952)
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Dec 24, 2018)

    • Fix case sensitive headers in aiohttp (#825)
    • Fix passing empty object body (#815)
    • Fix openapi3 path and query validation (#821)
    • Add path to API only for HTTP operations (#817)
    • Added OpenAPI 3 getting API Key from cookie support (#794)
    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Dec 11, 2018)

    • Proper debug logs for aiohttp's StreamResponse (#787)
    • Fix cli --stub (#800)
    • Fix handling additionalProperties in body (#789)
    • Change can_read_body to body_exists in AioHttpApi.get_request (#738)
    • Removed duplicated calls of get_response method of the Api classes (#809)
    • Fix up array style defaults (#803)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Nov 15, 2018)

    • Enforce that spec has string keys (JSON does not support integer keys) (#763)
    • Add connexion.operation dummy module for backwards compatability (#758)
    • Only pass body on PATCH/POST/PUT request (#761)
    • Add support for JWT authentication (#732)
    • Don't let openapi_spec_validator tamper raw spec (#762)
    • Simplify Operation class construction (#726)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Nov 7, 2018)

    • Pass files to handler if filename in arguments or has_kwargs (#753)
    • Handle TypeValidationError in form-data (#749)
    • Get rid of deprecation warning when using connexion run ... (#745)
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Nov 5, 2018)

    Connexion 2.0 supports version 3.0.x of the OpenAPI Specification! As 2.0 is a major version bump, you can expect some breaking changes from Connexion 1.5.3.

    • You can now use openapi 3 specifications
    • Swagger UI is now optional, and can be installed with pip install connexion[swagger-ui]
    • App and Api options must be provided through the "options" argument (old_style_options have been removed).
    • You must specify a form content-type in 'consumes' in order to consume form data.
    • The Operation interface has been formalized in the AbstractOperation class.
    • The Operation class has been renamed to Swagger2Operation.
    • Array parameter deserialization now follows the Swagger 2.0 spec more closely. In situations when a query parameter is passed multiple times, and the collectionFormat is either csv or pipes, the right-most value will be used. For example, ?q=1,2,3&q=4,5,6 will result in q = [4, 5, 6]. The old behavior is available by setting the collectionFormat to multi, or by importing decorators.uri_parsing.AlwaysMultiURIParser and passing parser_class=AlwaysMultiURIParser to your Api.
    • The spec validator library has changed from swagger-spec-validator to openapi-spec-validator.
    • Errors that previously raised SwaggerValidationError now raise the InvalidSpecification exception. All spec validation errors should be wrapped with InvalidSpecification.
    • Support for nullable/x-nullable, readOnly and writeOnly/x-writeOnly has been added to the standard json schema validator.
    • Custom validators can now be specified on api level (instead of app level).
    • Added support for basic authentication and apikey authentication
    • If unsupported security requirements are defined or x-tokenInfoFunc/x-tokenInfoUrl is missing, connexion now denies requests instead of allowing access without security-check.
    • Accessing connexion.request.user / flask.request.user is no longer supported, use connexion.context['user'] instead
    Source code(tar.gz)
    Source code(zip)
  • 1.5.3(Sep 17, 2018)

    • Fix error codes for bad Content-Types in body validator. (#629)
    • Add validator kind to error logs extra in validators (#671)
    • Improve metrics reporting (#672)
    • Improve coroutine detection (#600)
    • Add x-nullable support for body validators (#642)
    Source code(tar.gz)
    Source code(zip)
  • 1.5.2(Jul 26, 2018)

  • 1.5.1(Jul 23, 2018)

  • 1.5.0(Jul 23, 2018)

    • Update to swagger-spec-validator 2.3.1 (#611)
    • URI parsing decorator (#613)
    • Correct validator response on bad JSON (#610)
    • Add capability to pass framework's request context to handler functions
    Source code(tar.gz)
    Source code(zip)
  • 1.4.2(May 16, 2018)

  • 1.4.1(May 15, 2018)

  • 1.4(Apr 9, 2018)

  • 1.3(Jan 13, 2018)

Owner
Zalando SE
The org page for Zalando, Europe's leading online fashion platform. Visit opensource.zalando.com for project stats.
Zalando SE
Bablyon 🐍 A small ASGI web framework

A small ASGI web framework that you can make asynchronous web applications using uvicorn with using few lines of code

xArty 8 Dec 07, 2021
The lightning-fast ASGI server. ?

The lightning-fast ASGI server. Documentation: https://www.uvicorn.org Community: https://discuss.encode.io/c/uvicorn Requirements: Python 3.6+ (For P

Encode 6k Jan 03, 2023
CherryPy is a pythonic, object-oriented HTTP framework. https://docs.cherrypy.org/

Welcome to the GitHub repository of CherryPy! CherryPy is a pythonic, object-oriented HTTP framework. It allows building web applications in much the

CherryPy 1.6k Dec 29, 2022
Dazzler is a Python async UI/Web framework built with aiohttp and react.

Dazzler is a Python async UI/Web framework built with aiohttp and react. Create dazzling fast pages with a layout of Python components and bindings to update from the backend.

Philippe Duval 17 Oct 18, 2022
Mini Web Framework on MicroPython (Esp8266)

dupgee Dupgee is a mini web framework developed for micro-python(Tested on esp8266). Installation pip install dupgee Create Project dupgee create newp

ahmet kotan 38 Jul 25, 2022
Pulumi-checkly - Checkly Pulumi Provider With Python

🚨 This project is still in very early stages and is not stable, use at your own

Checkly 16 Dec 15, 2022
Appier is an object-oriented Python web framework built for super fast app development.

Joyful Python Web App development Appier is an object-oriented Python web framework built for super fast app development. It's as lightweight as possi

Hive Solutions 122 Dec 22, 2022
A microservice written in Python detecting nudity in images/videos

py-nudec py-nudec (python nude detector) is a microservice, which scans all the images and videos from the multipart/form-data request payload and sen

Michael Grigoryan 8 Jul 09, 2022
Online Boutique is a cloud-native microservices demo application

Online Boutique is a cloud-native microservices demo application. Online Boutique consists of a 10-tier microservices application. The application is

Matt Reider 1 Oct 22, 2021
The core of a service layer that integrates with the Pyramid Web Framework.

pyramid_services The core of a service layer that integrates with the Pyramid Web Framework. pyramid_services defines a pattern and helper methods for

Michael Merickel 78 Apr 15, 2022
Async Python 3.6+ web server/framework | Build fast. Run fast.

Sanic | Build fast. Run fast. Build Docs Package Support Stats Sanic is a Python 3.6+ web server and web framework that's written to go fast. It allow

Sanic Community Organization 16.7k Jan 08, 2023
Endpoints is a lightweight REST api framework written in python and used in multiple production systems that handle millions of requests daily.

Endpoints Quickest API builder in the West! Endpoints is a lightweight REST api framework written in python and used in multiple production systems th

Jay Marcyes 30 Mar 05, 2022
Sanic integration with Webargs

webargs-sanic Sanic integration with Webargs. Parsing and validating request arguments: headers, arguments, cookies, files, json, etc. IMPORTANT: From

Endurant Devs 13 Aug 31, 2022
Asynchronous HTTP client/server framework for asyncio and Python

Async http client/server framework Key Features Supports both client and server side of HTTP protocol. Supports both client and server Web-Sockets out

aio-libs 13.2k Jan 05, 2023
Cses2humio - CrowdStrike Falcon Event Stream to Humio

CrowdStrike Falcon Event Stream to Humio This project intend to provide a simple

Trifork.Security 6 Aug 02, 2022
WAZO REST API for the call management of the C4 infrastructure

wazo-router-calld wazo-router-calld provides REST API for the C4 infrastructure. Installing wazo-router-calld The server is already provided as a part

Wazo Platform 4 Dec 21, 2022
Library for building WebSocket servers and clients in Python

What is websockets? websockets is a library for building WebSocket servers and clients in Python with a focus on correctness and simplicity. Built on

Aymeric Augustin 4.3k Dec 31, 2022
🦍 The Cloud-Native API Gateway

Kong or Kong API Gateway is a cloud-native, platform-agnostic, scalable API Gateway distinguished for its high performance and extensibility via plugi

Kong 33.8k Jan 09, 2023
Web-frameworks-benchmark

Web-frameworks-benchmark

Nickolay Samedov 4 May 13, 2021
Dockerized web application on Starlite, SQLAlchemy1.4, PostgreSQL

Production-ready dockerized async REST API on Starlite with SQLAlchemy and PostgreSQL

Artur Shiriev 10 Jan 03, 2023