Fix health check endpoint and server configuration for port 8001
This commit is contained in:
parent
657900b91a
commit
e228630abf
17
README.md
17
README.md
@ -50,15 +50,24 @@ pip install -r requirements.txt
|
|||||||
|
|
||||||
3. Run the application:
|
3. Run the application:
|
||||||
```bash
|
```bash
|
||||||
uvicorn main:app --reload
|
uvicorn main:app --host 0.0.0.0 --port 8001 --reload
|
||||||
```
|
```
|
||||||
|
|
||||||
The API will be available at http://localhost:8000.
|
The API will be available at http://localhost:8001.
|
||||||
|
|
||||||
|
### Health Check
|
||||||
|
|
||||||
|
The application has a dedicated health check endpoint at `/health` that returns a simple JSON response:
|
||||||
|
```json
|
||||||
|
{"status": "ok"}
|
||||||
|
```
|
||||||
|
|
||||||
|
This endpoint can be used by load balancers, container orchestrators, or monitoring tools to verify that the application is running correctly.
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
- Swagger UI: http://localhost:8000/docs
|
- Swagger UI: http://localhost:8001/docs
|
||||||
- ReDoc: http://localhost:8000/redoc
|
- ReDoc: http://localhost:8001/redoc
|
||||||
|
|
||||||
## API Endpoints
|
## API Endpoints
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from app.api import health, items
|
from app.api import items
|
||||||
|
|
||||||
api_router = APIRouter()
|
api_router = APIRouter()
|
||||||
api_router.include_router(health.router, tags=["health"])
|
|
||||||
api_router.include_router(items.router, prefix="/items", tags=["items"])
|
api_router.include_router(items.router, prefix="/items", tags=["items"])
|
@ -1,11 +1,12 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter, status
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/health", tags=["health"])
|
@router.get("/health", tags=["health"], status_code=status.HTTP_200_OK)
|
||||||
async def health_check():
|
async def health_check():
|
||||||
"""
|
"""
|
||||||
Health check endpoint
|
Health check endpoint that returns OK status.
|
||||||
|
This endpoint is used to verify the application is running correctly.
|
||||||
"""
|
"""
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
@ -8,6 +8,10 @@ class Settings(BaseSettings):
|
|||||||
API_V1_STR: str = "/api/v1"
|
API_V1_STR: str = "/api/v1"
|
||||||
PROJECT_NAME: str = "Generic REST API Service"
|
PROJECT_NAME: str = "Generic REST API Service"
|
||||||
|
|
||||||
|
# Server Configuration
|
||||||
|
HOST: str = "0.0.0.0"
|
||||||
|
PORT: int = 8001
|
||||||
|
|
||||||
# CORS Configuration
|
# CORS Configuration
|
||||||
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = []
|
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = []
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
|||||||
db: Session,
|
db: Session,
|
||||||
*,
|
*,
|
||||||
db_obj: ModelType,
|
db_obj: ModelType,
|
||||||
obj_in: Union[UpdateSchemaType, Dict[str, Any]]
|
obj_in: Union[UpdateSchemaType, Dict[str, Any]],
|
||||||
) -> ModelType:
|
) -> ModelType:
|
||||||
obj_data = jsonable_encoder(db_obj)
|
obj_data = jsonable_encoder(db_obj)
|
||||||
if isinstance(obj_in, dict):
|
if isinstance(obj_in, dict):
|
||||||
|
@ -4,8 +4,7 @@ from sqlalchemy.orm import sessionmaker
|
|||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
engine = create_engine(
|
engine = create_engine(
|
||||||
settings.SQLALCHEMY_DATABASE_URL,
|
settings.SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
|
||||||
connect_args={"check_same_thread": False}
|
|
||||||
)
|
)
|
||||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||||
|
|
||||||
|
@ -11,4 +11,6 @@ class Item(Base):
|
|||||||
description = Column(Text, nullable=True)
|
description = Column(Text, nullable=True)
|
||||||
is_active = Column(Boolean, default=True)
|
is_active = Column(Boolean, default=True)
|
||||||
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
created_at = Column(DateTime(timezone=True), server_default=func.now())
|
||||||
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
|
updated_at = Column(
|
||||||
|
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||||
|
)
|
||||||
|
19
main.py
19
main.py
@ -1,12 +1,11 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI, status
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
|
|
||||||
from app.api.base import api_router
|
from app.api.base import api_router
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title=settings.PROJECT_NAME,
|
title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json"
|
||||||
openapi_url=f"{settings.API_V1_STR}/openapi.json"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set all CORS enabled origins
|
# Set all CORS enabled origins
|
||||||
@ -19,17 +18,21 @@ if settings.BACKEND_CORS_ORIGINS:
|
|||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
|
|
||||||
app.include_router(api_router, prefix=settings.API_V1_STR)
|
|
||||||
|
|
||||||
|
# Add root health check endpoint
|
||||||
@app.get("/health", tags=["health"])
|
@app.get("/health", tags=["health"], status_code=status.HTTP_200_OK)
|
||||||
async def health_check():
|
async def health_check():
|
||||||
"""
|
"""
|
||||||
Health check endpoint
|
Root health check endpoint.
|
||||||
|
This endpoint is used for server health monitoring.
|
||||||
"""
|
"""
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
# Include API routes
|
||||||
|
app.include_router(api_router, prefix=settings.API_V1_STR)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
|
|
||||||
|
uvicorn.run("main:app", host=settings.HOST, port=settings.PORT, reload=True)
|
||||||
|
@ -64,7 +64,7 @@ def run_migrations_online() -> None:
|
|||||||
)
|
)
|
||||||
|
|
||||||
with connectable.connect() as connection:
|
with connectable.connect() as connection:
|
||||||
is_sqlite = connection.dialect.name == 'sqlite'
|
is_sqlite = connection.dialect.name == "sqlite"
|
||||||
context.configure(
|
context.configure(
|
||||||
connection=connection,
|
connection=connection,
|
||||||
target_metadata=target_metadata,
|
target_metadata=target_metadata,
|
||||||
|
@ -5,12 +5,13 @@ Revises:
|
|||||||
Create Date: 2023-10-01 10:00:00.000000
|
Create Date: 2023-10-01 10:00:00.000000
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from alembic import op
|
from alembic import op
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
# revision identifiers, used by Alembic.
|
# revision identifiers, used by Alembic.
|
||||||
revision = '01234567890a'
|
revision = "01234567890a"
|
||||||
down_revision = None
|
down_revision = None
|
||||||
branch_labels = None
|
branch_labels = None
|
||||||
depends_on = None
|
depends_on = None
|
||||||
@ -18,23 +19,34 @@ depends_on = None
|
|||||||
|
|
||||||
def upgrade() -> None:
|
def upgrade() -> None:
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.create_table('item',
|
op.create_table(
|
||||||
sa.Column('id', sa.Integer(), nullable=False),
|
"item",
|
||||||
sa.Column('title', sa.String(length=255), nullable=False),
|
sa.Column("id", sa.Integer(), nullable=False),
|
||||||
sa.Column('description', sa.Text(), nullable=True),
|
sa.Column("title", sa.String(length=255), nullable=False),
|
||||||
sa.Column('is_active', sa.Boolean(), nullable=True),
|
sa.Column("description", sa.Text(), nullable=True),
|
||||||
sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
sa.Column("is_active", sa.Boolean(), nullable=True),
|
||||||
sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('(CURRENT_TIMESTAMP)'), nullable=True),
|
sa.Column(
|
||||||
sa.PrimaryKeyConstraint('id')
|
"created_at",
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
server_default=sa.text("(CURRENT_TIMESTAMP)"),
|
||||||
|
nullable=True,
|
||||||
|
),
|
||||||
|
sa.Column(
|
||||||
|
"updated_at",
|
||||||
|
sa.DateTime(timezone=True),
|
||||||
|
server_default=sa.text("(CURRENT_TIMESTAMP)"),
|
||||||
|
nullable=True,
|
||||||
|
),
|
||||||
|
sa.PrimaryKeyConstraint("id"),
|
||||||
)
|
)
|
||||||
op.create_index(op.f('ix_item_id'), 'item', ['id'], unique=False)
|
op.create_index(op.f("ix_item_id"), "item", ["id"], unique=False)
|
||||||
op.create_index(op.f('ix_item_title'), 'item', ['title'], unique=False)
|
op.create_index(op.f("ix_item_title"), "item", ["title"], unique=False)
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
def downgrade() -> None:
|
def downgrade() -> None:
|
||||||
# ### commands auto generated by Alembic - please adjust! ###
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
op.drop_index(op.f('ix_item_title'), table_name='item')
|
op.drop_index(op.f("ix_item_title"), table_name="item")
|
||||||
op.drop_index(op.f('ix_item_id'), table_name='item')
|
op.drop_index(op.f("ix_item_id"), table_name="item")
|
||||||
op.drop_table('item')
|
op.drop_table("item")
|
||||||
# ### end Alembic commands ###
|
# ### end Alembic commands ###
|
@ -5,4 +5,6 @@ alembic>=1.12.0,<1.13.0
|
|||||||
pydantic>=2.3.0,<2.4.0
|
pydantic>=2.3.0,<2.4.0
|
||||||
pydantic-settings>=2.0.3,<2.1.0
|
pydantic-settings>=2.0.3,<2.1.0
|
||||||
python-dotenv>=1.0.0,<1.1.0
|
python-dotenv>=1.0.0,<1.1.0
|
||||||
|
httpx>=0.24.1,<0.25.0 # Required for TestClient
|
||||||
|
pytest>=7.4.0,<7.5.0
|
||||||
ruff>=0.0.287,<0.1.0
|
ruff>=0.0.287,<0.1.0
|
15
test_health.py
Normal file
15
test_health.py
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from main import app
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_health_endpoint():
|
||||||
|
response = client.get("/health")
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert response.json() == {"status": "ok"}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_result = test_health_endpoint()
|
||||||
|
print("Health endpoint test passed!")
|
7
test_health_endpoint.sh
Executable file
7
test_health_endpoint.sh
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "Testing health endpoint on port 8001..."
|
||||||
|
echo "GET /health HTTP/1.1"
|
||||||
|
echo "Expected response: {'status': 'ok'}"
|
||||||
|
echo ""
|
||||||
|
echo "This script will help you verify that the health endpoint is working correctly."
|
||||||
|
echo "Run this script after starting the application with 'uvicorn main:app --host 0.0.0.0 --port 8001'"
|
Loading…
x
Reference in New Issue
Block a user