feat: enhance Docker setup and API functionality; add integration tests and update README
All checks were successful
Build and Push to Private Registry101 / build (push) Successful in 9s

This commit is contained in:
stephen schuresko
2025-02-18 08:51:48 -05:00
10 changed files with 252 additions and 21 deletions

View File

@@ -28,10 +28,4 @@ jobs:
name: Build Docker image
- run: docker push kube-reg.fairfaxmedia.net/papi/svc1:${{ steps.extract_branch.outputs.branch }} # Push the Docker image
name: Push Docker image
#- env:
#KUBEB64: '${{ secrets.KUBEB64 }}'
#run: mkdir -p $HOME/.kube &&echo "$KUBEB64" | base64 -d > $HOME/.kube/config &&
#curl https://fairfaxmedia.net/helm -o /usr/local/bin/helm && chmod +xxx /usr/local/bin/helm &&
#/usr/local/bin/helm upgrade --install papi papi-helm/ --set image.tag=${{ steps.extract_branch.outputs.branch }} # Deploy the Helm chart

4
.gitignore vendored
View File

@@ -1,5 +1,5 @@
__pycache__
test.db
test*.db
.coverage
report.xml
coverage.xml
coverage.xml

View File

@@ -1,3 +1,5 @@
#
#
FROM python:3.12
@@ -11,6 +13,6 @@ COPY ./requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./papi.py /code/
COPY ./*.py /code/
CMD ["python3", "papi.py", "--port", "8912"]
CMD ["uvicorn", "papi:app","--port", "8912","--host","0.0.0.0"]

View File

@@ -1,20 +1,35 @@
ENV=dev
VER=2
VER=0.0.6
TAG=${ENV}-${VER}
REGISTRY=kube-reg.fairfaxmedia.net
SVC=papi/svc1
DOCK_IMG=${REGISTRY}/${SVC}:${TAG}
LIVE_HOST:="http://localhost:8912"
clean:
rm -rf .pytest_cache
rm -rf .coverage
rm -rf report.xml
rm -rf test.db
rm -rf htmlcov
coverage: clean
install:
pip3 install -r requirements.txt
coverage: clean install
pytest --cov=papi --cov=posts --cov=users test_papi.py test_posts.py test_users.py --junitxml=report.xml --cov-report=html --cov-report=xml --cov-report=term --cov-fail-under 90
docker-img: coverage
docker build -t ${DOCK_IMG} .
docker-push: docker-img
docker push ${DOCK_IMG}
deploy: docker-push
helm upgrade papi ./papi-helm/ -f ./papi-helm/v.${ENV}.yaml --set image.tag=${TAG}
helm upgrade papi ./papi-helm/ -f ./papi-helm/v.${ENV}.yaml --set image.tag=${TAG} --set env.VERSION=${VER}
integration: install
pyresttest ${LIVE_HOST} integration.pyrest.yaml
run: install
uvicorn papi:app --reload --port 8912 --host 0.0.0.0
all: deploy

119
README.md
View File

@@ -0,0 +1,119 @@
# Posts API
This is the Posts API project, a simple API for managing blog posts.
## Table of Contents
- [Installation](#installation)
- [Usage](#usage)
- [Endpoints](#endpoints)
- [Contributing](#contributing)
- [License](#license)
## Installation
1. Clone the repository:
```bash
git clone https://git.fairfaxmedia.net/posts-api/papi-py.git
```
2. Navigate to the project directory:
```bash
cd papi-py
```
3. Install the dependencies:
```bash
pip install -r requirements.txt
```
## Usage
To start the server, run:
```bash
python3 papi.py
```
To start with an alternative database location(postgresql)
Use the following
```bash
DATABASE_URL='postgresql+psycopg2://user:password@hostname/database_name' python3 papi.py
```
## Endpoints
### GET /posts
Retrieve a list of all posts.
### POST /posts
Create a new post.
### GET /posts/{id}
Retrieve a specific post by ID.
### PUT /posts/{id}
Update a specific post by ID.
### DELETE /posts/{id}
Delete a specific post by ID.
### Unit Tests
```bash
make coverage
```
This runs coverage tests and stores the html coverage report along with functions tested in htmlcov
## deploy...
Please log into the connected container registry on Makefile:4 WHERE it says REGISTRY=
using the `docker login` command
feel free to edit the VER= tag
ensure you are logged into kubernetes so that commands kubectl and helm both work
then run
```bash
make deploy
```
### Integration testing instructions
to test live on papi.kube-dev.fairfaxmedia.net
run the following:
```bash
make integration -e LIVE_HOST=http://papi.kube-dev.fairfaxmedia.net
```
to integration-test on localhost on the default port run
```bash
make integration
```
## openapi spec:
[openapi.json](https://papi.kube-dev.fairfaxmedia.net/openapi.json)
[swagger-ui](https://papi.kube-dev.fairfaxmedia.net/docs)
### helm deployment
```bash
helm upgrade papi ./papi-helm/ -f ./papi-helm/v.${ENV}.yaml --set image.tag=${TAG} --set env.VERSION=${VER}
```
or alternatively
```bash
make deploy
```
### postman-like hopscotch collection:
hopscotch_collection.json can be imported into the following tool
[hopscotch-ui](https://hopscotch.kube.fairfaxmedia.net/)
## kubernetes dashboard plane:
[kubernetes](https://kube.fairfaxmedia.net)
[git-ci server](https://git.fairfaxmedia.net)

7
db.py
View File

@@ -1,14 +1,17 @@
from sqlalchemy import create_engine, Column, Integer,String, ForeignKey
from sqlalchemy.engine import URL
from sqlalchemy.orm import sessionmaker, Session, declarative_base
import os
# Database setup
DATABASE_URL = "sqlite:///./test.db"
if os.getenv("DATABASE_URL"):
DATABASE_URL = os.getenv("DATABASE_URL")
engine = create_engine(DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
Base = declarative_base()
version = os.environ.get("VERSION", "0.0.0")

85
integration.pyrest.yaml Normal file
View File

@@ -0,0 +1,85 @@
# Test using included Django test app
# First install python-django
# Then launch the app in another terminal by doing
# cd testapp
# python manage.py testserver test_data.json
# Once launched, tests can be executed via:
# python resttest.py http://localhost:8000 miniapp-test.yaml
---
- config:
- testset: "Tests using test app"
- variable_binds:
- 'uid': 1
- 'post_id': 1
- test: # create entity
- name: "Basic get"
- url: "/"
- test: # create entity
- name: "Get version"
- url: "/version"
- test: # create person by POST
- name: "Create person"
- url: "/users"
- method: "POST"
- body: '{"name": "Willim","email": "theadmiral@gmail.com"}'
- headers: {Content-Type: application/json}
- extract_binds:
- 'uid' : {'jsonpath_mini': "user.id"}
- test: # get single person
- name: "Get single person"
- url: {'template':'/users/$uid'} # use binded value
- method: 'GET'
- test: # update person by PUT
- name: "update person by PUT"
- url: {'template':'/users/$uid'}
- method: "PUT"
- body: '{"name": "Gaius"}'
- headers: {'Content-Type': 'application/json'}
- test: # create post by POST
- name: "Create post"
- url: "/posts"
- method: "POST"
- body: '{"title": "Willims post","content": "william made a post","author_id": 1}'
- headers: {Content-Type: application/json}
- extract_binds:
- 'post_id' : {'jsonpath_mini': "post.id"}
- test: # get single post
- name: "Get single post"
- url: {'template':'/posts/$post_id'}
- method: 'GET'
- test: # update post by PUT
- name: "update post by PUT"
- url: {'template':'/posts/$post_id'}
- method: "PUT"
- body: '{"title": "Gaius made a post"}'
- headers: {'Content-Type': 'application/json'}
- test: # delete post
- name: "Delete post"
- url: {'template':'/posts/$post_id'}
- method: "DELETE"
- test: # delete person
- name: "Delete person"
- url: {'template':'/users/$uid'}
- method: "DELETE"

17
papi.py
View File

@@ -1,4 +1,11 @@
#!/bin/env python3
#
# author: Stephen Schuresko
# date: 2025-02-18
# file: papi.py
# description: A simple FastAPI app (papi) with a few routes and models for users and posts
#
from fastapi import FastAPI, Depends
import uvicorn
from sqlalchemy import create_engine, Column, Integer,String, ForeignKey
@@ -7,6 +14,7 @@ from sqlalchemy.orm import sessionmaker, Session, declarative_base
import db
import users
import posts
import os
@@ -19,9 +27,6 @@ app.include_router(posts.router)
async def root():
return {"message": "Hello World"}
if __name__ == "__main__":
uvicorn.run("papi:app", host="0.0.0.0", port=8912, reload=True, log_level="debug",
workers=5, limit_concurrency=10, limit_max_requests=100)
@app.get("/version")
async def ver():
return {"version":db.version}

View File

@@ -1,3 +1,4 @@
fastapi
sqlalchemy
uvicorn
pyresttest

View File

@@ -12,3 +12,10 @@ def test_read_main():
assert response.json() == {"message": "Hello World"}
def test_read_version():
response = client.get("/version")
assert response.status_code == 200