Home

Awesome

pyramid_openapi3

Validate Pyramid views against OpenAPI 3.0/3.1 documents

<p align="center"> <img alt="Pyramid and OpenAPI logos" height="200" src="https://github.com/Pylons/pyramid_openapi3/blob/main/header.jpg?raw=true"> </p> <p align="center"> <a href="https://github.com/Pylons/pyramid_openapi3/actions/workflows/ci.yml"> <img alt="CI for pyramid_openapi3 (main branch)" src="https://github.com/Pylons/pyramid_openapi3/actions/workflows/ci.yml/badge.svg"> </a> <img alt="Test coverage (main branch)" src="https://img.shields.io/badge/tests_coverage-100%25-brightgreen.svg"> <img alt="Test coverage (main branch)" src="https://img.shields.io/badge/types_coverage-100%25-brightgreen.svg"> <a href="https://pypi.org/project/pyramid_openapi3/"> <img alt="latest version of pyramid_openapi3 on PyPI" src="https://img.shields.io/pypi/v/pyramid_openapi3.svg"> </a> <a href="https://pypi.org/project/pyramid_openapi3/"> <img alt="Supported Python versions" src="https://img.shields.io/pypi/pyversions/pyramid_openapi3.svg"> </a> <a href="https://github.com/Pylons/pyramid_openapi3/blob/main/LICENSE"> <img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg"> </a> <a href="https://github.com/Pylons/pyramid_openapi3/graphs/contributors"> <img alt="Built by these great folks!" src="https://img.shields.io/github/contributors/Pylons/pyramid_openapi3.svg"> </a> </p>

Peace of Mind

The reason this package exists is to give you peace of mind when providing a RESTful API. Instead of chasing down preventable bugs and saying sorry to consumers, you can focus on more important things in life.

<p align="center"> <a href="https://www.youtube.com/watch?v=P0zNxrDO0sE&amp;t=1061" title="Building Robust APIs" rel="nofollow" class="rich-diff-level-one"><img src="https://user-images.githubusercontent.com/311580/97364772-6d246a80-189c-11eb-84f2-a0ad23236003.png" alt="Building Robust APIs" style="max-width:100%;"></a> </p>

Features

Getting started

  1. Declare pyramid_openapi3 as a dependency in your Pyramid project.

  2. Include the following lines:

    config.include("pyramid_openapi3")
    config.pyramid_openapi3_spec('openapi.yaml', route='/api/v1/openapi.yaml')
    config.pyramid_openapi3_add_explorer(route='/api/v1/')
    
  3. Use the openapi view predicate to enable request/response validation:

    @view_config(route_name="foobar", openapi=True, renderer='json')
    def myview(request):
        return request.openapi_validated.parameters
    

For requests, request.openapi_validated is available with two fields: parameters and body. For responses, if the payload does not match the API document, an exception is raised.

Advanced configuration

Relative File References in Spec

A feature introduced in OpenAPI3 is the ability to use $ref links to external files (https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#reference-object).

To use this, you must ensure that you have all of your spec files in a given directory (ensure that you do not have any code in this directory as all the files in it are exposed as static files), then replace the pyramid_openapi3_spec call that you did in Getting Started with the following:

config.pyramid_openapi3_spec_directory('path/to/openapi.yaml', route='/api/v1/spec')

Some notes:

Endpoints / Request / Response Validation

Provided with pyramid_openapi3 are a few validation features:

These features are enabled as a default, but you can disable them if you need to:

config.registry.settings["pyramid_openapi3.enable_endpoint_validation"] = False
config.registry.settings["pyramid_openapi3.enable_request_validation"] = False
config.registry.settings["pyramid_openapi3.enable_response_validation"] = False

[!WARNING] Disabling request validation will result in request.openapi_validated no longer being available to use.

Register Pyramid's Routes

You can register routes in your pyramid application. First, write the x-pyramid-route-name extension in the PathItem of the OpenAPI schema.

paths:
  /foo:
    x-pyramid-route-name: foo_route
    get:
      responses:
        200:
          description: GET foo

Then put the config directive pyramid_openapi3_register_routes in the app_factory of your application.

config.pyramid_openapi3_register_routes()

This is equal to manually writing the following:

config.add_route("foo_route", pattern="/foo")

The pyramid_openapi3_register_routes() method supports setting a factory and route prefix as well. See the source for details.

Specify protocol and port for getting the OpenAPI 3 spec file

Sometimes, it is necessary to specify the protocol and port to access the openapi3 spec file. This can be configured using the proto_port optional parameter to the the pyramid_openapi3_add_explorer function:

config.pyramid_openapi3_add_explorer(proto_port=('https', 443))

Demo / Examples

There are three examples provided with this package:

All examples come with tests that exhibit pyramid_openapi's error handling and validation capabilities.

A fully built-out app, with 100% test coverage, providing a RealWorld.io API is available at niteoweb/pyramid-realworld-example-app. It is a Heroku-deployable Pyramid app that provides an API for a Medium.com-like social app. You are encouraged to use it as a scaffold for your next project.

Design defense

The authors of pyramid_openapi3 believe that the approach of validating a manually-written API document is superior to the approach of generating the API document from Python code. Here are the reasons:

  1. Both generation and validation against a document are lossy processes. The underlying libraries running the generation/validation will always have something missing. Either a feature from the latest OpenAPI specification, or an implementation bug. Having to fork the underlying library in order to generate the part of your API document that might only be needed for the frontend is unfortunate.

    Validation on the other hand allows one to skip parts of validation that are not supported yet, and not block a team from shipping the document.

  2. The validation approach does sacrifice DRY-ness, and one has to write the API document and then the (view) code in Pyramid. It feels a bit redundant at first. However, this provides a clear separation between the intent and the implementation.

  3. The generation approach has the drawback of having to write Python code even for parts of the API document that the Pyramid backend does not handle, as it might be handled by a different system, or be specific only to documentation or only to the client side of the API. This bloats your Pyramid codebase with code that does not belong there.

Running tests

You need to have poetry and Python 3.10 & 3.12 installed on your machine. All Makefile commands assume you have the Poetry environment activated, i.e. poetry shell.

Alternatively, if you use nix, run nix-shell to drop into a shell that has everything prepared for development.

Then you can run:

make tests

Related packages

These packages tackle the same problem-space:

Deprecation policy

We do our best to follow the rules below.

Use in the wild

A couple of projects that use pyramid_openapi3 in production: