Skip to content

Commit

Permalink
Merge pull request #16 from 0b01001001/dev
Browse files Browse the repository at this point in the history
Dev: add docs, upgrade to v0.2
  • Loading branch information
kemingy authored Jan 6, 2020
2 parents 2fb9f32 + c4652f8 commit 8a64bf9
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 12 deletions.
66 changes: 57 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[![downloads](https://img.shields.io/pypi/dm/spectree.svg)](https://pypistats.org/packages/spectree)
[![versions](https://img.shields.io/pypi/pyversions/spectree.svg)](https://github.com/0b01001001/spectree)
[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/0b01001001/spectree.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/0b01001001/spectree/context:python)
[![Documentation Status](https://readthedocs.org/projects/spectree/badge/?version=latest)](https://spectree.readthedocs.io/en/latest/?badge=latest)

Yet another library to generate OpenAPI document and validate request & response with Python annotations.

Expand All @@ -23,29 +24,76 @@ Yet another library to generate OpenAPI document and validate request & response

install with pip: `pip install spectree`

### Demo
### Examples

```py
```
Check the [examples](/examples) folder.

### Step by Step

1. Define your data structure with `pydantic.BaseModel`
2. create `spectree.SpecTree` instance with the web framework name you are using `api = SpecTree('flask')`
3. `validate` the route
1. Define your data structure used in (query, json, headers, cookies, resp) with `pydantic.BaseModel`
2. create `spectree.SpecTree` instance with the web framework name you are using, like `api = SpecTree('flask')`
3. `api.validate` decorate the route with
* `query`
* `json`
* `headers`
* `cookies`
* `resp`
* `tags`
4. access these data with `context(query, json, headers, cookies)`
4. access these data with `context(query, json, headers, cookies)` (of course, you can access these from the original place where the framework offered)
* flask: `request.context`
* falcon: `req.context`
* starlette: `request.context`
5. register to the web application `api.register(app)`
6. check the document at URL location `/apidoc/redoc` or `/apidoc/swagger`

### Examples
## Demo

Check the [examples](/examples) folder.
### Flask

```py
from flask import Flask, request, jsonify
from pydantic import BaseModel, Field, constr
from spectree import SpecTree, Response


class Profile(BaseModel):
name: constr(min_length=2, max_length=40) # Constrained Str
age: int = Field(
...,
gt=0,
lt=150,
description='user age(Human)'
)


class Message(BaseModel):
text: str


app = Flask(__name__)
api = SpecTree('flask')


@app.route('/api/user', methods=['POST'])
@api.validate(json=Profile, resp=Response('HTTP_404', HTTP_200=Message), tags=['api'])
def user_profile():
"""
verify user profile (summary of this endpoint)
user's name, user'age, ... (long description)
"""
print(request.context.json) # or `request.json`
return jsonify(text='it works')


if __name__ == "__main__":
api.register(app) # if you don't register in api init step
app.run()

```

## FAQ

> ValidationError: missing field for headers
The HTTP headers' keys in Flask are capitalized, in Falcon are upper cases, in Starlette are lower cases.
5 changes: 4 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,7 @@
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
html_static_path = ['_static']

# read the doc
master_doc = 'index'
84 changes: 84 additions & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,97 @@
Welcome to spectree's documentation!
====================================

|GitHub Actions| |pypi| |downloads| |versions| |Language grade: Python|
|Documentation Status|

Yet another library to generate OpenAPI document and validate request &
response with Python annotations.

Features
--------

- Less boilerplate code, annotations are really easy-to-use
- Generate API document with `Redoc UI`_ or `Swagger UI`_
- Validate query, JSON data, response data with `pydantic`_
- Current support:

- Flask
- Falcon
- Starlette

Quick Start
-----------

install with pip: ``pip install spectree``

Examples
~~~~~~~~

Check the `examples`_ folder.

Step by Step
~~~~~~~~~~~~

1. Define your data structure used in (query, json, headers, cookies,
resp) with ``pydantic.BaseModel``
2. create ``spectree.SpecTree`` instance with the web framework name you
are using, like ``api = SpecTree('flask')``
3. ``api.validate`` decorate the route with

- ``query``
- ``json``
- ``headers``
- ``cookies``
- ``resp``
- ``tags``

4. access these data with ``context(query, json, headers, cookies)`` (of
course, you can access these from the original place where the
framework offered)

- flask: ``request.context``
- falcon: ``req.context``
- starlette: ``request.context``

5. register to the web application ``api.register(app)``
6. check the document at URL location ``/apidoc/redoc`` or
``/apidoc/swagger``

FAQ
---

ValidationError: missing field for headers

The HTTP headers’ keys in Flask are capitalized, in Falcon are upper
cases, in Starlette are lower cases.

.. _Redoc UI: https://github.com/Redocly/redoc
.. _Swagger UI: https://github.com/swagger-api/swagger-ui
.. _pydantic: https://github.com/samuelcolvin/pydantic/
.. _examples: https://github.com/0b01001001/spectree/blob/master/examples

.. |GitHub Actions| image:: https://github.com/0b01001001/spectree/workflows/Python%20package/badge.svg
:target: https://github.com/0b01001001/spectree/actions
.. |pypi| image:: https://img.shields.io/pypi/v/spectree.svg
:target: https://pypi.python.org/pypi/spectree
.. |downloads| image:: https://img.shields.io/pypi/dm/spectree.svg
:target: https://pypistats.org/packages/spectree
.. |versions| image:: https://img.shields.io/pypi/pyversions/spectree.svg
:target: https://github.com/0b01001001/spectree
.. |Language grade: Python| image:: https://img.shields.io/lgtm/grade/python/g/0b01001001/spectree.svg?logo=lgtm&logoWidth=18
:target: https://lgtm.com/projects/g/0b01001001/spectree/context:python
.. |Documentation Status| image:: https://readthedocs.org/projects/spectree/badge/?version=latest
:target: https://spectree.readthedocs.io/en/latest/?badge=latest


.. toctree::
:maxdepth: 2
:caption: Contents:

spectree
config
response
plugins
utils


Expand Down
14 changes: 14 additions & 0 deletions docs/source/plugins.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Plugins
====================

.. automodule:: spectree.plugins.base
:members:

.. automodule:: spectree.plugins.flask_plugin
:members:

.. automodule:: spectree.plugins.falcon_plugin
:members:

.. automodule:: spectree.plugins.starlette_plugin
:members:
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

setup(
name='spectree',
version='0.1.0',
version='0.2.0',
author='Keming Yang',
author_email='kemingy94@gmail.com',
description=('generate OpenAPI document and validate request&response '
Expand All @@ -38,7 +38,7 @@
extras_require={
'flask': ['flask'],
'falcon': ['falcon'],
'starlette': ['starlette'],
'starlette': ['starlette', 'requests'],
},
zip_safe=False,
entry_points={
Expand Down
29 changes: 29 additions & 0 deletions spectree/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,55 @@
class BasePlugin:
"""
Base plugin for SpecTree plugin classes.
:param spectree: :class:`spectree.SpecTree` instance
"""

def __init__(self, spectree):
self.spectree = spectree
self.config = spectree.config

def register_route(self, app):
"""
:param app: backend framework application
register document API routes to application
"""
raise NotImplementedError

def validate(self, query, json, headers, resp):
"""
validate the request and response
"""
raise NotImplementedError

def find_routes(self):
"""
find the routes from application
"""
raise NotImplementedError

def bypass(self, func, method):
"""
:param func: route function (endpoint)
:param method: HTTP method for this route function
bypass some routes that shouldn't be shown in document
"""
raise NotImplementedError

def parse_path(self, route):
"""
:param route: API routes
parse URI path to get the variables in path
"""
raise NotImplementedError

def parse_func(self, route):
"""
:param route: API routes
get the endpoint function from routes
"""
raise NotImplementedError
4 changes: 4 additions & 0 deletions spectree/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
class SpecTree:
"""
Interface
:param str backend: choose from ('flask', 'falcon', 'starlette')
:param app: backend framework application instance (you can also register to it later)
:param kwargs: update default :class:`spectree.config.Config`
"""

def __init__(self, backend='base', app=None, **kwargs):
Expand Down
4 changes: 4 additions & 0 deletions spectree/utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import re
import inspect

# parse HTTP status code to get the code
HTTP_CODE = re.compile(r'^HTTP_(?P<code>\d{3})$')


Expand Down Expand Up @@ -38,6 +39,9 @@ def parse_request(func):


def parse_params(func, params):
"""
get spec for (query, headers, cookies)
"""
if hasattr(func, 'query'):
params.append({
'name': func.query,
Expand Down

0 comments on commit 8a64bf9

Please sign in to comment.