diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..24d7de7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Amit Vikram Raj + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 12dee8f..97eac57 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,29 @@ # Files API -This project is a more polished version of the [cloud-engineering-project](https://github.com/avr2002/cloud-engineering-project) that we built during the [MLOps Club](https://mlops-club.org/) cohort of Taking Python to Production on AWS by [me](https://www.linkedin.com/in/avr27/) and [Eric Riddoch](https://www.linkedin.com/in/eric-riddoch/). +

+ + + + + + +

+ +This project is a more polished version of the [cloud-engineering-project](https://github.com/avr2002/cloud-engineering-project) that we built during the [MLOps Club](https://mlops-club.org/) cohort of Taking Python to Production on AWS by [Eric Riddoch](https://www.linkedin.com/in/eric-riddoch/) and [me](https://www.linkedin.com/in/avr27/).

files-api

-In this project, we built -- +***In this project, we built ––*** * A [RESTful API](https://aws.amazon.com/what-is/restful-api/) using FastAPI to do CRUD operations against an S3 bucket. * Implemented principles of [12-factor app](https://12factor.net/) and [RESTful API design](https://restfulapi.net/). * Dockerized the application for easy local development and deployment. * Rigorously tested it using pytest with mocks for AWS S3 and OpenAI services. * Setup load testing with Locust +* We wrote API Contract using OpenAPI spec, auto-generated from FastAPI code, with pre-commit hooks using `oasdiff` to catch breaking changes and OpenAPI Generator to create a Python client SDK for the API. * Serverless Deployment: Deployed the app using AWS CDK with Docker on AWS Lambda and exposed it via API Gateway. * CI/CD Pipeline: Automated testing and deployment using GitHub Actions. * Observability & Monitoring: @@ -24,7 +34,18 @@ In this project, we built -- ## Setup -Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/) and node.js before running. +Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/), [aws-cli v2](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) and [node.js](https://nodejs.org/en/download) before running. + + +- Clone the repo + ```bash + git clone https://github.com/avr2002/files-api.git + ``` + +- Install dependencies + ```bash + uv sync --all-groups + ``` - If you are using AWS SSO, you can activate your profile by running the following command: @@ -73,6 +94,7 @@ Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/) and node ```bash ./run run-locust ``` + ^^^ If you want to load test against deployed API, modify the [docker-compose.locust.yaml](./docker-compose.locust.yaml) file with the deployed API Gateway URL - Generate OpenAPI spec ```bash @@ -156,3 +178,11 @@ Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/) and node Similary, you can view other metrics like Lambda Invocations, Duration, Errors, Throttles etc. and for S3 as well. + +## Contributing + +Contributions are welcome! +- Complete the setup process above +- Make your changes +- Run tests and linting, and +- Submit a pull request. diff --git a/docker-compose.locust.yaml b/docker-compose.locust.yaml index 918dc98..0300586 100644 --- a/docker-compose.locust.yaml +++ b/docker-compose.locust.yaml @@ -13,10 +13,9 @@ services: locust: image: locustio/locust:latest command: > - --locustfile /locustfile.py --host=https://k4cspk2km1.execute-api.us-west-2.amazonaws.com/prod --users 100 --spawn-rate 5 --autostart - # --locustfile /locustfile.py --host=http://fastapi:8000 --users 1 --spawn-rate 1 --autostart - # --locustfile /locustfile.py --host=https://3rbeuvjyd3.execute-api.us-west-2.amazonaws.com/prod --users 1 --spawn-rate 1 --autostart - # --locustfile /locustfile.py --host=https://j0o3bozns6.execute-api.ap-south-1.amazonaws.com/prod/ --users 1 --spawn-rate 1 --autostart + --locustfile /locustfile.py --host=http://fastapi:8000 --users 1 --spawn-rate 1 --autostart + # --locustfile /locustfile.py --host=https://k4cspk2km1.execute-api.us-west-2.amazonaws.com/prod --users 100 --spawn-rate 5 --autostart + ports: - "8089:8089" volumes: diff --git a/docs/images/mlops-club.png b/docs/images/mlops-club.png new file mode 100644 index 0000000..4890c62 Binary files /dev/null and b/docs/images/mlops-club.png differ diff --git a/pyproject.toml b/pyproject.toml index d24dbc9..a9e3399 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,11 +1,12 @@ [project] name = "files-api" -version = "0.1.0" +version = "0.1.1" description = "Files API to upload and download files from S3 using FastAPI." readme = "README.md" authors = [ { name = "avr2002", email = "avr13405@gmail.com" } ] +license = { text="MIT" } requires-python = ">=3.12" dependencies = [ "aws-embedded-metrics>=3.3.1", diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..3562265 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,73 @@ +# Scripts + +Utility scripts for OpenAPI schema generation, load testing, and SDK usage examples. + +## OpenAPI Schema Generation + +- **`generate-openapi.py`**: + Feature-rich script to generate and validate OpenAPI schemas from the FastAPI application. + + **Commands:** + + - **Generate** - Create OpenAPI schema from FastAPI app: + ```shell + uv run ./scripts/generate-openapi.py generate --output-spec=openapi.json + ``` + + - **Generate and Diff** - Generate schema and compare with existing spec: + ```shell + uv run ./scripts/generate-openapi.py generate-and-diff \ + --existing-spec ./openapi.json \ + --output-spec ./openapi.json \ + --fail-on-diff + ``` + + Used in pre-commit hooks to ensure the OpenAPI schema stays synchronized with code changes. + +- **`generate-openapi-simple.py`** + + Simplified version demonstrating the core OpenAPI generation logic. Generates schema and compares it with the existing `openapi.json` file, exiting with an error if they differ. Useful for understanding the basics before working with the full-featured `generate-openapi.py`. + + **Usage:** + ```shell + uv run ./scripts/generate-openapi-simple.py + ``` + +## Load Testing + +**`locustfile.py`** + +Locust configuration for load testing the Files API. Simulates realistic user flows including file uploads, downloads, deletions, and AI file generation. + +**Tasks:** +- `file_operations_flow`: Tests basic CRUD operations (list, upload, describe, download, delete) +- `generate_ai_files_flow`: Tests AI-powered file generation (text, image, audio) + +**Usage:** +```shell +# Start with docker-compose +./run run-locust + +# Or run Locust directly +uv run locust -f scripts/locustfile.py --host=http://localhost:8000 +``` + +Access the Locust web UI at http://localhost:8089 to configure and monitor load tests. + +## SDK Testing + +**`try_client.py`** + +Example script demonstrating usage of the auto-generated Python SDK (`files-api-sdk`). Shows how to upload files using the client library. + +**Usage:** +```shell +# First, generate and install the SDK +./run generate-client-library +./run install-generated-sdk + +# Then run the example +uv run ./scripts/try_client.py +``` + +Make sure the API is running locally before executing this script. diff --git a/uv.lock b/uv.lock index 6c43bc9..dc23f24 100644 --- a/uv.lock +++ b/uv.lock @@ -930,7 +930,7 @@ wheels = [ [[package]] name = "files-api" -version = "0.1.0" +version = "0.1.1" source = { editable = "." } dependencies = [ { name = "aws-embedded-metrics" },