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
JustPy is an object-oriented, component based, high-level Python Web Framework

JustPy Docs and Tutorials Introduction JustPy is an object-oriented, component based, high-level Python Web Framework that requires no front-en

927 Jan 08, 2023
FastAPI framework, high performance, easy to learn, fast to code, ready for production

FastAPI framework, high performance, easy to learn, fast to code, ready for production Documentation: https://fastapi.tiangolo.com Source Code: https:

Sebastián Ramírez 53k Jan 02, 2023
Pretty tornado wrapper for making lightweight REST API services

CleanAPI Pretty tornado wrapper for making lightweight REST API services Installation: pip install cleanapi Example: Project folders structure: . ├──

Vladimir Kirievskiy 26 Sep 11, 2022
Djask is a web framework for python which stands on the top of Flask and will be as powerful as Django.

Djask is a web framework for python which stands on the top of Flask and will be as powerful as Django.

Andy Zhou 27 Sep 08, 2022
An alternative serializer implementation for REST framework written in cython built for speed.

drf-turbo An alternative serializer implementation for REST framework written in cython built for speed. Free software: MIT license Documentation: htt

Mng 74 Dec 30, 2022
Light, Flexible and Extensible ASGI API framework

Starlite Starlite is a light, opinionated and flexible ASGI API framework built on top of pydantic and Starlette. Check out the Starlite documentation

Na'aman Hirschfeld 1.6k Jan 09, 2023
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
A boilerplate Flask API for a Fullstack Project with some additional packages and configuration prebuilt. ⚙

Flask Boilerplate to quickly get started with production grade flask application with some additional packages and configuration prebuilt.

Yasser Tahiri 32 Dec 24, 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
Low code web framework for real world applications, in Python and Javascript

Full-stack web application framework that uses Python and MariaDB on the server side and a tightly integrated client side library.

Frappe 4.3k Dec 30, 2022
A shopping list and kitchen inventory management app.

Flask React Project This is the backend for the Flask React project. Getting started Clone this repository (only this branch) git clone https://github

11 Jun 03, 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
Free and open source full-stack enterprise framework for agile development of secure database-driven web-based applications, written and programmable in Python.

Readme web2py is a free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applic

2k Dec 31, 2022
An easy-to-use high-performance asynchronous web framework.

中文 | English 一个易用的高性能异步 web 框架。 Index.py 文档 Index.py 实现了 ASGI3 接口,并使用 Radix Tree 进行路由查找。是最快的 Python web 框架之一。一切特性都服务于快速开发高性能的 Web 服务。 大量正确的类型注释 灵活且高效的

Index.py 264 Dec 31, 2022
Bromelia-hss implements an HSS by using the Python micro framework Bromélia.

Bromélia HSS bromelia-hss is the second official implementation of a Diameter-based protocol application by using the Python micro framework Bromélia.

henriquemr 7 Nov 02, 2022
The Python micro framework for building web applications.

Flask Flask is a lightweight WSGI web application framework. It is designed to make getting started quick and easy, with the ability to scale up to co

The Pallets Projects 61.5k Jan 06, 2023
Pyramid - A Python web framework

Pyramid Pyramid is a small, fast, down-to-earth, open source Python web framework. It makes real-world web application development and deployment more

Pylons Project 3.7k Dec 30, 2022
Python AsyncIO data API to manage billions of resources

Introduction Please read the detailed docs This is the working project of the next generation Guillotina server based on asyncio. Dependencies Python

Plone Foundation 183 Nov 15, 2022
Otter is framework for creating microservices in Flask like fassion using RPC communication via message queue.

Otter Framework for microservices. Overview Otter is framework for creating microservices in Flask like fassion using RPC communication via message qu

Volodymyr Biloshytskyi 4 Mar 23, 2022
An easy-to-use high-performance asynchronous web framework.

An easy-to-use high-performance asynchronous web framework.

Aber 264 Dec 31, 2022