From bc344c024c5882646e2f52cb95fa58b05a547dad Mon Sep 17 00:00:00 2001
From: "Hebert F. Barros"
Date: Thu, 28 Dec 2023 17:30:33 +0000
Subject: [PATCH 1/4] Initial commit
---
.dockerignore | 4 ++
.github/script/test.ps1 | 27 ++++++++
.github/script/test.sh | 22 +++++++
.github/workflows/docker-image.yml | 18 ++++++
.github/workflows/python-app.yml | 29 +++++++++
.gitignore | 4 ++
.gitpod.yml | 4 ++
Dockerfile | 12 ++++
README.md | 98 ++++++++++++++++++++++++++++++
api/index.py | 1 +
docker-compose.yml | 0
main.py | 1 +
requirements.txt | 5 ++
src/__main__.py | 0
src/dtos/ISayHelloDto.py | 4 ++
src/index.py | 20 ++++++
test_index.http | 20 ++++++
test_index.py | 23 +++++++
vercel.json | 15 +++++
19 files changed, 307 insertions(+)
create mode 100644 .dockerignore
create mode 100644 .github/script/test.ps1
create mode 100644 .github/script/test.sh
create mode 100644 .github/workflows/docker-image.yml
create mode 100644 .github/workflows/python-app.yml
create mode 100644 .gitignore
create mode 100644 .gitpod.yml
create mode 100644 Dockerfile
create mode 100644 README.md
create mode 100644 api/index.py
create mode 100644 docker-compose.yml
create mode 100644 main.py
create mode 100644 requirements.txt
create mode 100644 src/__main__.py
create mode 100644 src/dtos/ISayHelloDto.py
create mode 100644 src/index.py
create mode 100644 test_index.http
create mode 100644 test_index.py
create mode 100644 vercel.json
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..f5f4229
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,4 @@
+.vercel
+venv
+.idea
+__pycache__
diff --git a/.github/script/test.ps1 b/.github/script/test.ps1
new file mode 100644
index 0000000..fcd0167
--- /dev/null
+++ b/.github/script/test.ps1
@@ -0,0 +1,27 @@
+#!/bin/pwsh
+
+if (Get-Command pip -ErrorAction SilentlyContinue) {
+ Write-Host "Installing Python dependencies..."
+ pip install -r requirements.txt
+}
+else {
+ Write-Host "pip is not installed"
+ Write-Host "Installing pip"
+ Invoke-WebRequest -Uri https://bootstrap.pypa.io/get-pip.py -OutFile get-pip.py
+ python get-pip.py
+ Write-Host "Installing Python dependencies..."
+ pip install -r requirements.txt
+}
+
+if (Get-Command pytest -ErrorAction SilentlyContinue) {
+ Write-Host "Running tests..."
+ pytest --version
+ pytest
+}
+else {
+ Write-Host "pytest is not installed"
+ Write-Host "installing pytest"
+ pip install pytest
+ pytest --version
+ pytest
+}
\ No newline at end of file
diff --git a/.github/script/test.sh b/.github/script/test.sh
new file mode 100644
index 0000000..12f3022
--- /dev/null
+++ b/.github/script/test.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+if ! [ -x "$(command -v pip)" ]; then
+ echo 'Error: pip is not installed.' >&2
+ echo 'Installing pip...'
+ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
+ python get-pip.py
+ rm get-pip.py
+ echo 'pip installed.'
+fi
+
+pip install -r requirements.txt
+
+if ! [ -x "$(command -v pytest)" ]; then
+ echo 'Error: pytest is not installed.' >&2
+ echo 'Installing pytest'
+ pip install pytest
+ echo 'pytest installed.'
+fi
+
+
+pytest
\ No newline at end of file
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
new file mode 100644
index 0000000..d657a63
--- /dev/null
+++ b/.github/workflows/docker-image.yml
@@ -0,0 +1,18 @@
+name: Docker Image CI
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+
+ build:
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v3
+ - name: Build the Docker image
+ run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)
diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml
new file mode 100644
index 0000000..b528a9e
--- /dev/null
+++ b/.github/workflows/python-app.yml
@@ -0,0 +1,29 @@
+name: Python testing
+
+on:
+ push:
+ branches: ["main"]
+ pull_request:
+ branches: ["main"]
+
+permissions:
+ contents: read
+
+jobs:
+ run_tests_on_ubuntu:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Run Bash script file
+ run: |
+ chmod +x ./.github/script/test.sh
+ ./.github/script/test.sh
+ shell: bash
+ run_tests_on_windows:
+ runs-on: windows-latest
+ steps:
+ - uses: actions/checkout@v2
+ - name: Run PowerShell script file
+ run: |
+ .\.github/script/test.ps1
+ shell: pwsh
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1e6eda4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.vercel
+venv
+.idea
+__pycache__
\ No newline at end of file
diff --git a/.gitpod.yml b/.gitpod.yml
new file mode 100644
index 0000000..3c0c831
--- /dev/null
+++ b/.gitpod.yml
@@ -0,0 +1,4 @@
+tasks:
+ - init: pip install -r requirements.txt
+
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..1373048
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,12 @@
+FROM python:3.9
+
+WORKDIR /app
+
+COPY requirements.txt .
+
+RUN pip install --upgrade pip && \
+ pip install --no-cache-dir -r requirements.txt
+
+COPY . .
+
+CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7c6b468
--- /dev/null
+++ b/README.md
@@ -0,0 +1,98 @@
+
+
+
:package: deploy-python-fastapi-in-vercel
+ This example shows how to use FastApi on Vercel with Serverless Functions using the Python Runtime.
+
+
+
+
+
+
+
+
+
+
+ Report Bug
+ Request Feature
+
+ Systems on which it has been tested.
+
+
+
+
+
+
+
+
+Did you like the project? Please, considerate a donation to help improve!
+
+✨
+
+# Getting started
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fhebertcisco%2Fdeploy-python-fastapi-in-vercel%2Ftree%2Fmain%2Fpython%2FFastApi&demo-title=FastApi%20%2B%20Vercel&demo-description=Use%20FastApi%202%20on%20Vercel%20with%20Serverless%20Functions%20using%20the%20Python%20Runtime.&demo-url=https%3A%2F%2FFastApi-python-template.vercel.app%2F&demo-image=https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png)
+
+# FastApi + Vercel
+
+This example shows how to use FastApi 0.88.0 on Vercel with Serverless Functions using the [Python Runtime](https://vercel.com/docs/concepts/functions/serverless-functions/runtimes/python).
+
+[![Python testing](https://github.com/hebertcisco/deploy-python-fastapi-in-vercel/actions/workflows/python-app.yml/badge.svg?branch=main)](https://github.com/hebertcisco/deploy-python-fastapi-in-vercel/actions/workflows/python-app.yml)
+[![Docker Image CI](https://github.com/hebertcisco/deploy-python-fastapi-in-vercel/actions/workflows/docker-image.yml/badge.svg)](https://github.com/hebertcisco/deploy-python-fastapi-in-vercel/actions/workflows/docker-image.yml)
+
+## Demo
+
+[deploy-python-fastapi-in-vercel.vercel.app](https://deploy-python-fastapi-in-vercel.vercel.app)
+
+## How it Works
+
+This example uses the Web Server Gateway Interface (WSGI) with FastApi to enable handling requests on Vercel with Serverless Functions.
+
+## Running Locally
+
+### With Docker
+```bash
+# Build the Docker image
+docker build -t deploy-python-fastapi-in-vercel .
+
+# Run the Docker container
+docker run -p 8000:8000 deploy-python-fastapi-in-vercel
+
+```
+
+### With uvicorn
+
+#### Install dependencies
+
+```bash
+pip install -r requirements.txt
+```
+```bash
+uvicorn main:app --host 0.0.0.0 --port 8000
+```
+
+Your FastApi application is now available at `http://localhost:8000`.
+
+## One-Click Deploy
+
+Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=vercel-examples):
+
+[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fhebertcisco%2Fdeploy-python-fastapi-in-vercel%2Ftree%2Fmain%2Fpython%2FFastApi&demo-title=FastApi%20%2B%20Vercel&demo-description=Use%20FastApi%202%20on%20Vercel%20with%20Serverless%20Functions%20using%20the%20Python%20Runtime.&demo-url=https%3A%2F%2FFastApi-python-template.vercel.app%2F&demo-image=https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png)
+
+## 🤝 Contributing
+
+Contributions, issues and feature requests are welcome!
Feel free to check [issues page](issues).
+
+## Show your support
+
+Give a ⭐️ if this project helped you!
+
+Or buy me a coffee 🙌🏾
+
+
+
+
+
+## 📝 License
+
+Copyright © 2023 [Hebert F Barros](https://github.com/hebertcisco).
+This project is [MIT](LICENSE) licensed.
diff --git a/api/index.py b/api/index.py
new file mode 100644
index 0000000..227406a
--- /dev/null
+++ b/api/index.py
@@ -0,0 +1 @@
+from src.index import app
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..e69de29
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..f850a29
--- /dev/null
+++ b/main.py
@@ -0,0 +1 @@
+from api.index import app
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..34fc9cb
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,5 @@
+fastapi==0.88.0
+pytest==7.1.3
+pytest-asyncio==0.20.3
+uvicorn==0.20.0
+pydantic~=1.10.4
diff --git a/src/__main__.py b/src/__main__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/dtos/ISayHelloDto.py b/src/dtos/ISayHelloDto.py
new file mode 100644
index 0000000..f81f0aa
--- /dev/null
+++ b/src/dtos/ISayHelloDto.py
@@ -0,0 +1,4 @@
+from pydantic import BaseModel
+
+class ISayHelloDto(BaseModel):
+ message: str
\ No newline at end of file
diff --git a/src/index.py b/src/index.py
new file mode 100644
index 0000000..246f9fb
--- /dev/null
+++ b/src/index.py
@@ -0,0 +1,20 @@
+from fastapi import FastAPI
+
+from src.dtos.ISayHelloDto import ISayHelloDto
+
+app = FastAPI()
+
+
+@app.get("/")
+async def root():
+ return {"message": "Hello World"}
+
+
+@app.get("/hello/{name}")
+async def say_hello(name: str):
+ return {"message": f"Hello {name}"}
+
+
+@app.post("/hello")
+async def hello_message(dto: ISayHelloDto):
+ return {"message": f"Hello {dto.message}"}
diff --git a/test_index.http b/test_index.http
new file mode 100644
index 0000000..9053072
--- /dev/null
+++ b/test_index.http
@@ -0,0 +1,20 @@
+# Test your FastAPI endpoints
+
+GET http://127.0.0.1:8000/
+Accept: application/json
+
+###
+
+GET http://127.0.0.1:8000/hello/User
+Accept: application/json
+
+###
+
+POST /hello HTTP/1.1
+Host: 127.0.0.1:8000
+Content-Type: application/json
+Content-Length: 28
+
+{
+ "message": "Fulano!"
+}
\ No newline at end of file
diff --git a/test_index.py b/test_index.py
new file mode 100644
index 0000000..99258ad
--- /dev/null
+++ b/test_index.py
@@ -0,0 +1,23 @@
+import pytest
+
+from src.dtos.ISayHelloDto import ISayHelloDto
+from src.index import root, say_hello, hello_message
+
+
+@pytest.mark.asyncio
+async def test_root():
+ result = await root()
+ assert result == {'message': 'Hello World'}
+
+
+@pytest.mark.asyncio
+async def test_say_hello():
+ result = await say_hello("John")
+ assert result == {'message': 'Hello John'}
+
+
+@pytest.mark.asyncio
+async def test_hello_message():
+ dto = ISayHelloDto(message="Alice")
+ result = await hello_message(dto)
+ assert result == {'message': 'Hello Alice'}
diff --git a/vercel.json b/vercel.json
new file mode 100644
index 0000000..6172529
--- /dev/null
+++ b/vercel.json
@@ -0,0 +1,15 @@
+{
+ "devCommand": "uvicorn main:app --host 0.0.0.0 --port 3000",
+ "builds": [
+ {
+ "src": "api/index.py",
+ "use": "@vercel/python"
+ }
+ ],
+ "routes": [
+ {
+ "src": "/(.*)",
+ "dest": "api/index.py"
+ }
+ ]
+}
\ No newline at end of file
From 0a98111da23bb6decf7d7790080229941b23bc4f Mon Sep 17 00:00:00 2001
From: "Hebert F. Barros"
Date: Thu, 28 Dec 2023 17:36:24 +0000
Subject: [PATCH 2/4] Add Docker setup for web service
Introduced a docker-compose configuration to build and run the web
service, mapping its internal port 8000 to the same port on the host,
facilitating containerization and local development workflow.
---
docker-compose.yml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/docker-compose.yml b/docker-compose.yml
index e69de29..677df3b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -0,0 +1,5 @@
+services:
+ web:
+ build: .
+ ports:
+ - "8000:8000"
\ No newline at end of file
From 0e6c4a03f11ddad4077791f088a22d6313357ed4 Mon Sep 17 00:00:00 2001
From: hebertcisco
Date: Thu, 28 Dec 2023 17:59:23 +0000
Subject: [PATCH 3/4] Refactor initialization task in .gitpod.yml
Replace pip install with docker-compose for improved environment setup.
---
.gitpod.yml | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/.gitpod.yml b/.gitpod.yml
index 3c0c831..57df11a 100644
--- a/.gitpod.yml
+++ b/.gitpod.yml
@@ -1,4 +1,2 @@
tasks:
- - init: pip install -r requirements.txt
-
-
+ - init: docker-compose up
From ddbf40d8593b448702dc3abdc134a95e18b77a55 Mon Sep 17 00:00:00 2001
From: hebertcisco
Date: Thu, 28 Dec 2023 17:59:30 +0000
Subject: [PATCH 4/4] Refactor README for Docker instructions
Consolidated Docker setup instructions in README for clarity and ease of
use. Now users can easily choose between Docker Compose and traditional
Docker methods when running the application locally. This streamlining
improves the user experience. Issue #123
---
README.md | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/README.md b/README.md
index 7c6b468..9b013e5 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,14 @@ This example uses the Web Server Gateway Interface (WSGI) with FastApi to enable
## Running Locally
+### With Docker Compose
+
+```bash
+docker-compose up
+```
+
### With Docker
+
```bash
# Build the Docker image
docker build -t deploy-python-fastapi-in-vercel .
@@ -66,6 +73,7 @@ docker run -p 8000:8000 deploy-python-fastapi-in-vercel
```bash
pip install -r requirements.txt
```
+
```bash
uvicorn main:app --host 0.0.0.0 --port 8000
```