Repository: hjacobs/connexion-example Branch: master Commit: 024c38850eb9 Files: 9 Total size: 9.1 KB Directory structure: gitextract_0ae__7fn/ ├── .gitignore ├── Dockerfile ├── LICENSE ├── MAINTAINERS ├── Pipfile ├── README.rst ├── app.py ├── swagger.yaml └── test.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ __pycache__ ================================================ FILE: Dockerfile ================================================ FROM registry.opensource.zalan.do/stups/python:3.6.5-22 COPY Pipfile / COPY Pipfile.lock / RUN pipenv install --system --deploy --ignore-pipfile COPY app.py / COPY swagger.yaml / WORKDIR /data CMD /app.py ================================================ FILE: LICENSE ================================================ Copyright 2015 Henning Jacobs 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. ================================================ FILE: MAINTAINERS ================================================ Henning Jacobs ================================================ FILE: Pipfile ================================================ [[source]] url = "https://pypi.org/simple" verify_ssl = true name = "pypi" [packages] connexion = "*" gevent = "*" greenlet = {version = "*", platform_python_implementation="=='CPython'"} [dev-packages] [requires] python_version = "3.6" ================================================ FILE: README.rst ================================================ ============================== Connexion Example REST Service ============================== This example application implements a very basic "pet shop" REST service using the `Connexion`_ Python library. Connexion is a framework on top of Flask_ to automagically handle your REST API requests based on `Swagger 2.0 Specification`_ files in YAML. 👉 Please also have a look at the `Connexion Example with Redis database and Kubernetes deployment manifests`_. Features ======== This example application shows various features supported by the Connexion library: * mapping of REST operations to Python functions (using the ``operationId`` in ``swagger.yaml``) * maps path, query and body parameters to keyword arguments * bundled Swagger UI (served on `/ui/`_ path) * automatic JSON serialization for ``application/json`` content type * schema validation for the HTTP request body and query parameters: * required object properties * primitive JSON types (string, integers, etc) * date/time values * string lengths * minimum/maximum values * regular expression patterns * gevent WSGI server * OAuth2 protection Files ===== The example application only needs very few files: * ``swagger.yaml``: the pet shop REST API Swagger definition * ``app.py``: implementation of the pet shop operations with in-memory storage * ``Pipfile``: list of required Python libraries (used by Pipenv) * ``Dockerfile``: to build the example as a runnable Docker image * ``test.sh``: shell script to execute example HTTP requests against the pet shop API Running Locally =============== You can run the Python application directly on your local operating system (this requires Python 3 and `Pipenv `_): .. code-block:: bash $ pipenv install --dev && pipenv shell $ ./app.py # start the HTTP server $ xdg-open http://localhost:8080/ui/ $ ./test.sh # do some test HTTP requests Running with Docker =================== You can build the example application as a Docker image and run it: .. code-block:: bash $ docker build -t connexion-example . $ docker run -d -p 8080:8080 connexion-example $ ./test.sh # do some test HTTP requests Using OAuth2 Security ===================== To enable OAuth2 security (token verification), you need to pass the URL to the "tokeninfo" endpoint: .. code-block:: bash $ docker run -d -p 8080:8080 -e HTTP_TOKENINFO_URL=https://auth.example.org/tokeninfo connexion-example Using Connexion with a WSGI container ===================================== You can use the Flask WSGI app with any WSGI container, e.g. `using Flask with uWSGI`_: .. code-block:: bash $ sudo pip3 install uwsgi $ uwsgi --http :8080 -w app You can run uwsgi with a large number of worker processes to get high concurrency. This obviously makes no sense for the in-memory pet store example (every worker would have its own pet store dictionary): .. code-block:: bash $ uwsgi --http :8080 -w app -p 16 # use 16 worker processes See the `uWSGI documentation`_ for more information. .. _Connexion: https://pypi.python.org/pypi/connexion .. _Flask: http://flask.pocoo.org/ .. _Swagger 2.0 Specification: https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md .. _/ui/: http://localhost:8080/ui/ .. _using Flask with uWSGI: http://flask.pocoo.org/docs/latest/deploying/uwsgi/ .. _uWSGI documentation: https://uwsgi-docs.readthedocs.org/ .. _Connexion Example with Redis database and Kubernetes deployment manifests: https://github.com/hjacobs/connexion-example-redis-kubernetes ================================================ FILE: app.py ================================================ #!/usr/bin/env python3 import connexion import datetime import logging from connexion import NoContent # our memory-only pet storage PETS = {} def get_pets(limit, animal_type=None): return {"pets": [pet for pet in PETS.values() if not animal_type or pet['animal_type'] == animal_type][:limit]} def get_pet(pet_id): pet = PETS.get(pet_id) return pet or ('Not found', 404) def put_pet(pet_id, pet): exists = pet_id in PETS pet['id'] = pet_id if exists: logging.info('Updating pet %s..', pet_id) PETS[pet_id].update(pet) else: logging.info('Creating pet %s..', pet_id) pet['created'] = datetime.datetime.utcnow() PETS[pet_id] = pet return NoContent, (200 if exists else 201) def delete_pet(pet_id): if pet_id in PETS: logging.info('Deleting pet %s..', pet_id) del PETS[pet_id] return NoContent, 204 else: return NoContent, 404 logging.basicConfig(level=logging.INFO) app = connexion.App(__name__) app.add_api('swagger.yaml') # set the WSGI application callable to allow using uWSGI: # uwsgi --http :8080 -w app application = app.app if __name__ == '__main__': # run our standalone gevent server app.run(port=8080, server='gevent') ================================================ FILE: swagger.yaml ================================================ swagger: '2.0' info: title: Pet Shop Example API version: "0.1" description: Simple example API to store and retrieve pets consumes: - application/json produces: - application/json security: # enable OAuth protection for all REST endpoints # (only active if the TOKENINFO_URL environment variable is set) - oauth2: [uid] paths: /pets: get: tags: [Pets] operationId: app.get_pets summary: Get all pets parameters: - name: animal_type in: query type: string pattern: "^[a-zA-Z0-9]*$" - name: limit in: query type: integer format: int32 minimum: 0 default: 100 responses: 200: description: Return pets schema: type: object properties: pets: type: array items: $ref: '#/definitions/Pet' /pets/{pet_id}: get: tags: [Pets] operationId: app.get_pet summary: Get a single pet parameters: - $ref: '#/parameters/pet_id' responses: 200: description: Return pet schema: $ref: '#/definitions/Pet' 404: description: Pet does not exist put: tags: [Pets] operationId: app.put_pet summary: Create or update a pet parameters: - $ref: '#/parameters/pet_id' - name: pet in: body schema: $ref: '#/definitions/Pet' responses: 200: description: Pet updated 201: description: New pet created delete: tags: [Pets] operationId: app.delete_pet summary: Remove a pet parameters: - $ref: '#/parameters/pet_id' responses: 204: description: Pet was deleted 404: description: Pet does not exist parameters: pet_id: name: pet_id description: Pet's Unique identifier in: path type: string required: true pattern: "^[a-zA-Z0-9-]+$" definitions: Pet: type: object required: - name - animal_type properties: id: type: string description: Unique identifier example: "123" readOnly: true name: type: string description: Pet's name example: "Susie" minLength: 1 maxLength: 100 animal_type: type: string description: Kind of animal example: "cat" minLength: 1 tags: type: object description: Custom tags created: type: string format: date-time description: Creation time example: "2015-07-07T15:49:51.230+02:00" readOnly: true securityDefinitions: oauth2: type: oauth2 flow: implicit authorizationUrl: https://example.com/oauth2/dialog scopes: uid: Unique identifier of the user accessing the service. ================================================ FILE: test.sh ================================================ #!/bin/bash HTTP=$(which http) if [ ! -x "$HTTP" ]; then echo 'You need HTTPie to run this script!' echo 'sudo pip3 install httpie' exit 1 fi URL=:8080 set -x http PUT $URL/pets/1 name=foo animal_type=test http $URL/pets/1 http PUT $URL/pets/1 name=foo animal_type=test tags:='{"color": "brown"}' http $URL/pets/1 http $URL/pets animal_type==test http DELETE $URL/pets/1