Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Set up the Fastapi project #2

Merged
merged 45 commits into from
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
ac23c84
feat: Added server config
frgfm Oct 4, 2020
b04fab5
feat: Defined SQLAlchemy tables
frgfm Oct 4, 2020
6da82ca
feat: Added user route
frgfm Oct 4, 2020
3c68a41
feat: Added sites route
frgfm Oct 4, 2020
250c33a
feat: Added events route
frgfm Oct 4, 2020
430934c
feat: Added devices route
frgfm Oct 4, 2020
d8c9e72
feat: Added media route
frgfm Oct 4, 2020
03b02bb
feat: Added installations route
frgfm Oct 4, 2020
b0e22df
feat: Added alerts route
frgfm Oct 4, 2020
c6e973f
feat: Added ping route
frgfm Oct 4, 2020
fde1b67
feat: Added main app script
frgfm Oct 4, 2020
bfcf0d2
chore: Added requirements and Dockerfile
frgfm Oct 4, 2020
e579193
chore: Added docker-compose
frgfm Oct 4, 2020
0a1dc0f
docs: Updated README and CONTRIBUTING
frgfm Oct 4, 2020
55cc143
style: Added flake8 config
frgfm Oct 4, 2020
86f5916
chore: Added CI job for lint checking, installation and testing
frgfm Oct 4, 2020
10f481e
style: Updated CI job name
frgfm Oct 4, 2020
ce46b2a
fix: Fixed CI tests
frgfm Oct 4, 2020
d387907
test: Added unittest for ping
frgfm Oct 4, 2020
1a33fc4
test: Added unittests for users route
frgfm Oct 4, 2020
fa55dd6
style: Fixed lint
frgfm Oct 4, 2020
858edac
fix: Fixed CI test job
frgfm Oct 4, 2020
c2b5f8b
chore: Fixed requirements for unittests
frgfm Oct 4, 2020
445b68e
refactor: Removed unused import
frgfm Oct 4, 2020
cc9e8fc
chore: Added coverage handling
frgfm Oct 4, 2020
5e67856
chore: Added coverage upload
frgfm Oct 4, 2020
f077c08
style: Added back EOF
frgfm Oct 4, 2020
127557f
feat: Added default CRUD
frgfm Oct 4, 2020
3216c73
refactor: Refactored CRUD
frgfm Oct 4, 2020
a2ecd06
test: Updated tests for new CRUD compatibility
frgfm Oct 4, 2020
bf284c2
refactor: Refactored all routes to reduce codebase
frgfm Oct 4, 2020
9649447
test: Updated unittest
frgfm Oct 4, 2020
eb87613
feat: Updated main to reflect route refactoring
frgfm Oct 4, 2020
bcf38ab
style: Fixed lint
frgfm Oct 4, 2020
3a3b206
chore: Added coverage config
frgfm Oct 5, 2020
77b0491
test: Fixed typo
frgfm Oct 5, 2020
28bc139
test: Added unittests for sites
frgfm Oct 5, 2020
74c2b22
test: Added unittests for events
frgfm Oct 5, 2020
3b62d61
test: Refactored unittests
frgfm Oct 5, 2020
f8c281f
test: Added unittests for media
frgfm Oct 5, 2020
91a544b
test: Added unittests for devices
frgfm Oct 5, 2020
8768c8c
test: Added unittest for installations
frgfm Oct 5, 2020
f0b0ed1
test: Added unittests for alerts
frgfm Oct 5, 2020
be2a89b
docs: Fixed installation instructions in README
frgfm Oct 6, 2020
780b703
docs: Updated project description in CONTRIBUTING
frgfm Oct 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[flake8]
max-line-length = 120
ignore = F401, E402, E265, F403, W503, W504, F821, W605
exclude = .git, venv*, docs, build
64 changes: 64 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: fastapi-project

on: push

jobs:
install-deps:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
architecture: x64
- name: Cache python modules
uses: actions/[email protected]
env:
cache-name: cache-pkg-requirements
with:
path: ~/.cache/pip
key: ${{ runner.os }}-install-${{ env.cache-name }}-${{ hashFiles('requirements.txt') }}
restore-keys: |
${{ runner.os }}-install-${{ env.cache-name }}-
${{ runner.os }}-install-
${{ runner.os }}-
- name: Install package
run: |
python -m pip install --upgrade pip
pip install -r src/requirements.txt

flake8-py3:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python 3.7
uses: actions/setup-python@v1
with:
python-version: 3.7
architecture: x64
- name: Run flake8
run: |
pip install flake8
flake8 --version
flake8 ./

docker-ready:
runs-on: ubuntu-latest
needs: install-deps
steps:
- uses: actions/checkout@v2
- name: Build & run docker
run: PORT=8002 docker-compose up -d --build
- name: Run docker test
run: |
PORT=8002 docker-compose exec -T web coverage run -m pytest .
PORT=8002 docker-compose exec -T web coverage xml
docker cp pyronear-api_web_1:/usr/src/app/coverage.xml .

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
with:
file: ./coverage.xml
flags: unittests
fail_ci_if_error: true
39 changes: 39 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Contributing to pyronear-api

Everything you need to know to contribute efficiently to the project.



## Codebase structure

- [src](https://github.com/pyronear/pyronear-api/blob/master/src) - The actual [FastAPI](https://fastapi.tiangolo.com/) project
- [src/app](https://github.com/pyronear/pyronear-api/blob/master/src/app) - The source code of the API
- [src/tests](https://github.com/pyronear/pyronear-api/blob/master/src/tests) - The unittests for the app



## Continuous Integration

This project uses the following integrations to ensure proper codebase maintenance:

- [Github Worklow](https://help.github.com/en/actions/configuring-and-managing-workflows/configuring-a-workflow) - run jobs for package build and coverage
- [Codacy](https://www.codacy.com/) - analyzes commits for code quality
- [Codecov](https://codecov.io/) - reports back coverage results

As a contributor, you will only have to ensure coverage of your code by adding appropriate unit testing of your code.



## Issues

Use Github [issues](https://github.com/pyronear/pyronear-api/issues) for feature requests, or bug reporting. When doing so, use issue templates whenever possible and provide enough information for other contributors to jump in.



## Developing pyronear-api


### Commits

- **Code**: ensure to provide docstrings to your Python code. In doing so, please follow [Google-style](https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html) so it can ease the process of documentation later.
- **Commit message**: please follow [Udacity guide](http://udacity.github.io/git-styleguide/)
67 changes: 65 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,65 @@
# pyronear-api
API for wildfire prevention, detection & monitoring
# Pyronear API

[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/3bea1a63e4aa44258cfd08831d713478)](https://www.codacy.com/gh/pyronear/pyronear-api/dashboard?utm_source=github.com&utm_medium=referral&utm_content=pyronear/pyronear-api&utm_campaign=Badge_Grade)![Build Status](https://github.com/pyronear/pyronear-api/workflows/fastapi-project/badge.svg) [![codecov](https://codecov.io/gh/pyronear/pyronear-api/branch/master/graph/badge.svg)](https://codecov.io/gh/frgfm/Holocron) [![Docs](https://img.shields.io/badge/docs-available-blue.svg)](https://pyronear.github.io/pyronear-api)

The building blocks of our wildfire detection & monitoring API.



## Table of Contents

- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Usage](#usage)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)



## Getting started

### Prerequisites

- Python 3.6 (or more recent)
- [pip](https://pip.pypa.io/en/stable/)

### Installation

You can clone and install the project dependencies as follows:

```bash
git clone https://github.com/pyronear/pyronear-api.git
pip install -r pyronear-api/src/requirements.txt
```



## Usage

If you wish to deploy this project on a server hosted remotely, you might want to be using [Docker](https://www.docker.com/) containers. You can perform the same using this command:

```bash
PORT=8002 docker-compose up -d --build
```

Once completed, you will notice that you have a docker container running on the port you selected, which can process requests just like any django server.



## Documentation

The full project documentation is available [here](https://pyronear.github.io/pyronear-api/) for detailed specifications. The documentation was built with [ReDoc](https://redocly.github.io/redoc/).



## Contributing

Please refer to `CONTRIBUTING` if you wish to contribute to this project.



## License

Distributed under the GPLv3 License. See `LICENSE` for more information.
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: '3.7'

services:
web:
build: ./src
command: uvicorn app.main:app --reload --workers 1 --host 0.0.0.0 --port 8000
volumes:
- ./src/:/usr/src/app/
ports:
- ${PORT}:8000
environment:
- DATABASE_URL=postgresql://pyronear_api:pyronear_api@db/pyronear_api_dev
db:
image: postgres:12.1-alpine
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_USER=pyronear_api
- POSTGRES_PASSWORD=pyronear_api
- POSTGRES_DB=pyronear_api_dev

volumes:
postgres_data:
2 changes: 2 additions & 0 deletions src/.coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
source = app
23 changes: 23 additions & 0 deletions src/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
FROM python:3.8.1-alpine

# set work directory
WORKDIR /usr/src/app

# set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# copy requirements file
COPY ./requirements.txt /usr/src/app/requirements.txt

# install dependencies
RUN set -eux \
&& apk add --no-cache --virtual .build-deps build-base \
libressl-dev libffi-dev gcc musl-dev python3-dev \
postgresql-dev \
&& pip install --upgrade pip setuptools wheel \
&& pip install -r /usr/src/app/requirements.txt \
&& rm -rf /root/.cache/pip

# copy project
COPY . /usr/src/app/
34 changes: 34 additions & 0 deletions src/app/api/crud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from app.db import database
from sqlalchemy import Table
from pydantic import BaseModel


async def post(payload: BaseModel, table: Table):
query = table.insert().values(**payload.dict())
return await database.execute(query=query)


async def get(id: int, table: Table):
query = table.select().where(id == table.c.id)
return await database.fetch_one(query=query)


async def fetch_all(table: Table):
query = table.select()
return await database.fetch_all(query=query)


async def put(id: int, payload: BaseModel, table: Table):
query = (
table
.update()
.where(id == table.c.id)
.values(**payload.dict())
.returning(table.c.id)
)
return await database.execute(query=query)


async def delete(id: int, table: Table):
query = table.delete().where(id == table.c.id)
return await database.execute(query=query)
33 changes: 33 additions & 0 deletions src/app/api/routes/alerts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import List
from fastapi import APIRouter, Path
from app.api import routing
from app.db import alerts
from app.api.schemas import AlertOut, AlertIn


router = APIRouter()


@router.post("/", response_model=AlertOut, status_code=201)
async def create_alert(payload: AlertIn):
return await routing.create_entry(alerts, payload)


@router.get("/{id}/", response_model=AlertOut)
async def get_alert(id: int = Path(..., gt=0)):
return await routing.get_entry(alerts, id)


@router.get("/", response_model=List[AlertOut])
async def fetch_alerts():
return await routing.fetch_entries(alerts)


@router.put("/{id}/", response_model=AlertOut)
async def update_alert(payload: AlertIn, id: int = Path(..., gt=0)):
return await routing.update_entry(alerts, payload, id)


@router.delete("/{id}/", response_model=AlertOut)
async def delete_alert(id: int = Path(..., gt=0)):
return await routing.delete_entry(alerts, id)
33 changes: 33 additions & 0 deletions src/app/api/routes/devices.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import List
from fastapi import APIRouter, Path
from app.api import routing
from app.db import devices
from app.api.schemas import DeviceOut, DeviceIn


router = APIRouter()


@router.post("/", response_model=DeviceOut, status_code=201)
async def create_device(payload: DeviceIn):
return await routing.create_entry(devices, payload)


@router.get("/{id}/", response_model=DeviceOut)
async def get_device(id: int = Path(..., gt=0)):
return await routing.get_entry(devices, id)


@router.get("/", response_model=List[DeviceOut])
async def fetch_devices():
return await routing.fetch_entries(devices)


@router.put("/{id}/", response_model=DeviceOut)
async def update_device(payload: DeviceIn, id: int = Path(..., gt=0)):
return await routing.update_entry(devices, payload, id)


@router.delete("/{id}/", response_model=DeviceOut)
async def delete_device(id: int = Path(..., gt=0)):
return await routing.delete_entry(devices, id)
33 changes: 33 additions & 0 deletions src/app/api/routes/events.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from typing import List
from fastapi import APIRouter, Path
from app.api import routing
from app.db import events
from app.api.schemas import EventOut, EventIn


router = APIRouter()


@router.post("/", response_model=EventOut, status_code=201)
async def create_event(payload: EventIn):
return await routing.create_entry(events, payload)


@router.get("/{id}/", response_model=EventOut)
async def get_event(id: int = Path(..., gt=0)):
return await routing.get_entry(events, id)


@router.get("/", response_model=List[EventOut])
async def fetch_events():
return await routing.fetch_entries(events)


@router.put("/{id}/", response_model=EventOut)
async def update_event(payload: EventIn, id: int = Path(..., gt=0)):
return await routing.update_entry(events, payload, id)


@router.delete("/{id}/", response_model=EventOut)
async def delete_event(id: int = Path(..., gt=0)):
return await routing.delete_entry(events, id)
Loading