Skip to content

Commit

Permalink
docs: extend documentation (#68)
Browse files Browse the repository at this point in the history
Co-authored-by: Alex Kanitz <alexander.kanitz@unibas.ch>
  • Loading branch information
kushagra189 and uniqueg committed Feb 18, 2021
1 parent f2014bf commit 342cbdc
Show file tree
Hide file tree
Showing 11 changed files with 822 additions and 89 deletions.
4 changes: 0 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ services:
# this ensures that the pipeline is triggered for internal pushes,
# PRs from forks and pushes to existing PRs from forks
if: (type == push) OR (type == pull_request AND fork == true)
branches:
only:
- master
- dev

script:
- flake8
Expand Down
183 changes: 147 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,133 @@
# FOCA - Flask-OpenAPI-Connexion Archetype
# FOCA

[![License][badge-license]][badge-url-license]
[![Build_status][badge-build-status]][badge-url-build-status]
[![Docs][badge-docs]][badge-url-docs]
[![Coverage][badge-coverage]][badge-url-coverage]
[![GitHub_tag][badge-github-tag]][badge-url-github-tag]
[![PyPI_release][badge-pypi]][badge-url-pypi]

## Synopsis

Opinionated set of tools/utils for quickly developing
[OpenAPI][res-open-api]-based microservices with [Flask][res-flask] and
[Connexion][res-connexion].
_Quickly develop Flask microservices!_

## Description

FOCA is a [Python package][res-foca] that enables fast development of
OpenAPI-based HTTP API microservices in [Flask][res-flask]. It includes modules
for:
**FOCA** (**F**lask-**O**penAPI-**C**onnexion-**A**rchetype) is an opinionated
archetype that enables fast development of [OpenAPI][res-openapi]-based HTTP
API microservices in [Flask][res-flask], leveraging the excellent
[Connexion][res-connexion] framework.

FOCA reduces the required boilerplate code to fire up your app to a bare
minimum and allows you to _**focus on your application logic**_. It also avoids
unnecessary code repetition and introduces cross-service consistency when
developing multiple applications. Simply write a configuration file, pass
it to FOCA and you're good to go!

Currently supported features:

* configuration management
* error handling
* database interaction (currently [MongoDB][res-mongo-db])
* [JWT][res-jwt] validation
* Manage app configuration
* Handle exceptions
* Register OpenAPI 2.x/3.x specifications
* Protect endpoints via [JWT][res-jwt] validation
* Register [MongoDB][res-mongo-db] collections
* Run asynchronous tasks via [RabbitMQ][res-rabbitmq] & [Celery][res-celery]
* [CORS][res-cors] support

Check the [API docs][badge-url-docs] for further details.

## Usage

Install with `pip`:
(1) Install the [FOCA package][badge-url-pypi] with `pip`:

```bash
pip install foca
```

(2) Create a [configuration file](#configuration-file).

(3) Import the FOCA main function `foca()` and pass your config:

```python
from foca import foca

```bash
pip install foca
app = foca("path/to/my/app/config.yaml") # returns a Connexion app instance
```

Import in your code! For example:
(4) Start your [Flask][res-flask] app as usual.

![Hint][img-hint] _**Check out the [Petstore example application][example]
shipped with this repository to see FOCA in action!**_

## Configuration file

In order to use FOCA functionalities, you must create a [YAML][res-yaml]
configuration file that includes keyword sections reserved by FOCA.

![Hint][img-hint] _**In order to get you started writing your own app
configuration, you can copy the [**annotated template**][config-template]
shipped with this repository and modify it.**_

For further information on the writing FOCA configuration files, read on.

### Editing your configuration file

```bash
from foca.config.config_parser import YAMLConfigParser
For example, if you want to register a [MongoDB][res-mongo-db] database
collection, your configuration file must include the top-level `database`
keyword section, e.g.:

```yaml
db:
host: mongodb
port: 27017
dbs:
myDb:
collections:
myCollection:
indexes:
- keys:
id: 1
options:
'unique': True
```

Check the [API docs][docs-api] to see what's in FOCA.
> This config would create a MongoDB database `myDb` with collection
> `myCollection` in your database server. The collection would be indexed by
> key `id`, which is required to be unique. To register another collection,
> simply add another named `CollectionConfig` object as a child to
> `collections`, e.g., `yourCollection`, with its own `indexes` etc.
If you do _not_ want to register a database collection, you can simply omit
that section, but note that once a section is included, it _MUST_ adhere
to the corresponding model described in the [API
documentation][docs-models].

Keywords reserved by FOCA include the following (exhaustive; follow links to
corresponding models):

* [`api`][docs-models-api]
* [`db`][docs-models-db]
* [`exceptions`][docs-models-exceptions]
* [`jobs`][docs-models-jobs]
* [`log`][docs-models-log]
* [`security`][docs-models-security]
* [`server`][docs-models-server]

Any values passed to reserved keywords are automatically validated and a
corresponding informative exception will be raised whenever a value does not
adhere to the corresponding model.

Any top-level sections that are _not_ listed above will simply be passed to the
app instance returned by the `foca()` function. All configuration parameters,
reserved by FOCA _and_ any custom ones, will be available in the [application
context][res-flask-app-context] as attributes of `current_app.config['FOCA']`.

### More examples

Apart from the [annotated template][config-template], you can also check
out the [configuration file][config-petstore] of the [Petstore app][example]
for another example.

![Hint][img-hint] _**Or why not explore [apps that already use
FOCA][res-using-foca]?**_

## Contributing

Expand All @@ -50,9 +140,8 @@ with the community.

## Versioning

The project adopts the [semantic versioning][res-semver] scheme for versioning.
Currently the service is in beta stage, so the API may change without further
notice.
The project adopts [semantic versioning][res-semver]. Currently the service
is in beta stage, so the API may change without further notice.

## License

Expand All @@ -66,26 +155,48 @@ AAI][org-elixir-cloud]. Follow the link to get in touch with us via chat or
email. Please mention the name of this service for any inquiry, proposal,
question etc.

[badge-build-status]:<https://travis-ci.com/elixir-cloud-aai/foca.svg?branch=dev>
[badge-coverage]:<https://img.shields.io/coveralls/github/elixir-cloud-aai/foca>
[badge-github-tag]:<https://img.shields.io/github/v/tag/elixir-cloud-aai/foca?color=C39BD3>
[badge-license]:<https://img.shields.io/badge/license-Apache%202.0-blue.svg>
[badge-pypi]:<https://img.shields.io/pypi/v/foca.svg?style=flat&color=C39BD3>
[badge-url-build-status]:<https://travis-ci.com/elixir-cloud-aai/foca>
[badge-url-coverage]:<https://coveralls.io/github/elixir-cloud-aai/foca>
[badge-url-github-tag]:<https://github.com/elixir-cloud-aai/foca/releases>
[badge-url-license]:<http://www.apache.org/licenses/LICENSE-2.0>
[badge-url-pypi]:<https://pypi.python.org/pypi/foca>
[docs-api]: <https://foca.readthedocs.io/en/latest/>
![Logo_banner][img-logo-banner]

[badge-build-status]: <https://travis-ci.com/elixir-cloud-aai/foca.svg?branch=dev>
[badge-coverage]: <https://img.shields.io/coveralls/github/elixir-cloud-aai/foca>
[badge-docs]: <https://readthedocs.org/projects/foca/badge/>
[badge-github-tag]: <https://img.shields.io/github/v/tag/elixir-cloud-aai/foca?color=C39BD3>
[badge-license]: <https://img.shields.io/badge/license-Apache%202.0-blue.svg>
[badge-pypi]: <https://img.shields.io/pypi/v/foca.svg?style=flat&color=C39BD3>
[badge-url-build-status]: <https://travis-ci.com/elixir-cloud-aai/foca>
[badge-url-coverage]: <https://coveralls.io/github/elixir-cloud-aai/foca>
[badge-url-docs]: <https://foca.readthedocs.io/en/latest/>
[badge-url-github-tag]: <https://github.com/elixir-cloud-aai/foca/releases>
[badge-url-license]: <http://www.apache.org/licenses/LICENSE-2.0>
[badge-url-pypi]: <https://pypi.python.org/pypi/foca>
[config-template]: templates/config.yaml
[config-petstore]: examples/petstore/config.yaml
[docs-models]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html>
[docs-models-api]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.APIConfig>
[docs-models-db]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.DBConfig>
[docs-models-exceptions]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.ExceptionConfig>
[docs-models-jobs]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.JobsConfig>
[docs-models-log]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.LogConfig>
[docs-models-security]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.SecurityConfig>
[docs-models-server]: <https://foca.readthedocs.io/en/latest/modules/foca.models.html#foca.models.config.ServerConfig>
[example]: examples/petstore/README.md
[img-hint]: images/hint.svg
[img-logo-banner]: images/logo-banner.svg
[license]: LICENSE
[license-apache]: <https://www.apache.org/licenses/LICENSE-2.0>
[org-elixir-cloud]: <https://github.com/elixir-cloud-aai/elixir-cloud-aai>
[res-celery]: <http://docs.celeryproject.org/>
[res-connexion]: <https://github.com/zalando/connexion>
[res-cors]: <https://flask-cors.readthedocs.io/en/latest/>
[res-elixir-cloud-coc]: <https://github.com/elixir-cloud-aai/elixir-cloud-aai/blob/dev/CODE_OF_CONDUCT.md>
[res-elixir-cloud-contributing]: <https://github.com/elixir-cloud-aai/elixir-cloud-aai/blob/dev/CONTRIBUTING.md>
[res-connexion]: <https://github.com/zalando/connexion>
[res-flask]: <http://flask.pocoo.org/>
[res-flask-app-context]: <https://flask.palletsprojects.com/en/1.1.x/appcontext/>
[res-foca]: <https://pypi.org/project/foca/>
[res-jwt]: <https://jwt.io>
[res-mongo-db]: <https://www.mongodb.com/>
[res-open-api]: <https://www.openapis.org/>
[res-openapi]: <https://www.openapis.org/>
[res-rabbitmq]: <https://www.rabbitmq.com/>
[res-semver]: <https://semver.org/>
[res-using-foca]: <https://github.com/elixir-cloud-aai/foca/network/dependents>
[res-yaml]: <https://yaml.org/>
159 changes: 159 additions & 0 deletions examples/petstore/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# FOCA-Petstore

Dockerized [Petstore][res-petstore] example application implemented using
[FOCA][res-foca].

## Description

The example demonstrates how FOCA sets up a fully configured [Flask][res-flask]
app when passed an appropriately formatted [configuration
file][docs-config-file].

FOCA makes sure that

* the returned app instance contains all [configuration parameters][app-config]
* FOCA configuration parameters are validated
* requests and responses sent to/from the API endpoints configured in the
[Petstore][app-specs] [OpenAPI][res-openapi] specification are validated
* a [MongoDB][res-mongo-db] collection to store pets in is registered with The
app
* [CORS][res-cors] is enabled
* handles exceptions (here only returns `500 / Internal Server Error` for all
problems)

Apart from writing the configuration file, all that was left for us to do to
set up this example app was to write a _very_ simple app [entry point
module][app-entry-point], implement the [endpoint controller
logic][app-controllers] and prepare the [`Dockerfile`][app-dockerfile] and
[Docker Compose][res-docker-compose] [configuration][app-docker-compose] for
easy shipping/installation!

![Hint][img-hint] _**Check the [FOCA documentation][docs] for further
details.**_

## Installation

### Requirements

Ensure you have the following software installed:

* Docker (19.03.4, build 9013bf583a)
* docker-compose (1.25.5)
* Git (2.17.1)

> Indicated versions were used for developing/testing. Other versions may or
> may not work. Please let us know if you encounter any issues with versions
> _newer_ than the listed ones.
### Deploy app

Clone repository:

```bash
git clone https://github.com/elixir-cloud-aai/foca.git
```

Traverse to example app directory:

```bash
cd foca/examples/petstore
```

Build and run services in detached/daemonized mode:

```bash
docker-compose up -d --build
```

> In case Docker complains about port conflicts or if any of the used ports are
> blocked by a firewall, you will need to re-map the conflicting port(s) in the
> [Docker Compose config][app-docker-compose]. In particular, for each of the
> services that failed to start because of a port conflict, you will need to
> change the **first** of the two numbers listed below the corresponding
> `ports` keyword to some unused/open port. Note that if you change the mapped
> port for the `app` service you will need to manually append it to `localhost`
> when you access the API (or the Swagger UI) in subsequent steps, like, e.g.,
> so: `http://localhost:8080/`.
That's it, you can now visit the application's [Swagger UI][res-swagger-ui] in
your browser, e.g.,:

```bash
firefox http://localhost/ui # or use your browser of choice
```

> Mac users may need to replace `localhost` with `0.0.0.0`.
## Explore app

In the [Swagger UI][res-swagger-ui], you may use the `GET`/`POST` endpoints by
providing the required/desired values based on the indicated descriptions, then
hit the `Try it out!` button!

Alternatively, you can access the API endpoints programmatically, e.g., via
[`curl`][res-curl]:

* To **register a new pet**:

```console
curl -X POST \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
-d '{"name":"You","tag":"cat"}' \
'http://localhost/pets'
```

* To **retrieve all registered pets**:

```console
curl -X GET \
--header 'Accept: application/json' \
'http://localhost/pets'
```

* To **retrieve information on a specific pet**:

```console
curl -X GET \
--header 'Accept: application/json' \
'http://localhost/pets/0'
```

* To **delete a pet**: :-(

```console
curl -X DELETE \
--header 'Accept: application/json' \
'http://localhost/pets/0'
```

## Modify app

You can make use of this example to create your own app. Just modify any or all
of the following:

* [FOCA configuration file][app-config]
* [API specification][app-specs]
* [Endpoint controller module][app-controllers]
* [Main application module][app-entrypoint]
* [Dockerfile][app-dockerfile]
* [Docker Compose configuration][app-docker-compose]

[app-config]: config.yaml
[app-controllers]: controllers.py
[app-dockerfile]: Dockerfile
[app-docker-compose]: docker-compose.yaml
[app-entrypoint]: app.py
[app-specs]: petstore.yaml
[docs]: <https://foca.readthedocs.io/en/latest/>
[docs-config-file]: ../../README.md#configuration-file
[img-hint]: ../../images/hint.svg
[res-cors]: <https://flask-cors.readthedocs.io/en/latest/>
[res-curl]: <https://curl.se/>
[res-docker-compose]: <https://docs.docker.com/compose/>
[res-flask]: <http://flask.pocoo.org/>
[res-foca]: <https://pypi.org/project/foca/>
[res-mongo-db]: <https://www.mongodb.com/>
[res-openapi]: <https://www.openapis.org/>
[res-petstore]: <https://petstore.swagger.io/>
[res-swagger-ui]: <https://swagger.io/tools/swagger-ui/>

0 comments on commit 342cbdc

Please sign in to comment.