Ved Gupta commited on
Commit
d67439e
Β·
1 Parent(s): 15ea62b

initial setup correct

Browse files
Pipfile CHANGED
@@ -5,7 +5,6 @@ name = "pypi"
5
 
6
  [packages]
7
  fastapi = "*"
8
- uvicorn = {extras = ["standard"], version = "*"}
9
  python-dotenv = "*"
10
  sqlalchemy = "*"
11
  psycopg2-binary = "*"
@@ -13,6 +12,7 @@ pytest = "*"
13
  pytest-cov = "*"
14
  faker = "*"
15
  requests-mock = "*"
 
16
 
17
  [dev-packages]
18
 
 
5
 
6
  [packages]
7
  fastapi = "*"
 
8
  python-dotenv = "*"
9
  sqlalchemy = "*"
10
  psycopg2-binary = "*"
 
12
  pytest-cov = "*"
13
  faker = "*"
14
  requests-mock = "*"
15
+ uvicorn = {extras = ["standard"], version = "*"}
16
 
17
  [dev-packages]
18
 
README.md CHANGED
@@ -1,11 +1,11 @@
1
- # my-fastapi-project
2
 
3
  This is a production level project structure for a Python FastAPI project.
4
 
5
  ## Project Structure
6
 
7
  ```
8
- my-fastapi-project
9
  β”œβ”€β”€ app
10
  β”‚ β”œβ”€β”€ __init__.py
11
  β”‚ β”œβ”€β”€ api
@@ -67,4 +67,11 @@ The project structure is organized as follows:
67
  - `Dockerfile`: specifies the Docker image configuration.
68
  - `requirements.txt`: specifies the Python dependencies.
69
  - `README.md`: this file.
70
- - `.vscode`: contains Visual Studio Code configuration files.
 
 
 
 
 
 
 
 
1
+ # whisper.api
2
 
3
  This is a production level project structure for a Python FastAPI project.
4
 
5
  ## Project Structure
6
 
7
  ```
8
+ whisper.api
9
  β”œβ”€β”€ app
10
  β”‚ β”œβ”€β”€ __init__.py
11
  β”‚ β”œβ”€β”€ api
 
67
  - `Dockerfile`: specifies the Docker image configuration.
68
  - `requirements.txt`: specifies the Python dependencies.
69
  - `README.md`: this file.
70
+ - `.vscode`: contains Visual Studio Code configuration files.
71
+
72
+
73
+ ## Run this Project
74
+
75
+ ```bash
76
+ uvicorn app.main:app --reload
77
+ ```
app/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
  from fastapi import FastAPI
2
 
3
- from app.api.api import api_router
4
  from app.core.config import settings
5
 
6
 
 
1
  from fastapi import FastAPI
2
 
3
+ from app.api import api_router
4
  from app.core.config import settings
5
 
6
 
app/api/__init__.py CHANGED
@@ -1,10 +1,9 @@
1
- # File: my-fastapi-project/app/api/__init__.py
2
 
3
- from fastapi import FastAPI
4
  from .endpoints import items, users
5
- from .models import item, user
6
 
7
- app = FastAPI()
8
 
9
- app.include_router(items.router)
10
- app.include_router(users.router)
 
1
+ # File: whisper.api/app/api/__init__.py
2
 
3
+ from fastapi import APIRouter
4
  from .endpoints import items, users
 
5
 
6
+ api_router = APIRouter()
7
 
8
+ api_router.include_router(items.router, prefix="/items", tags=["items"])
9
+ api_router.include_router(users.router, prefix="/users", tags=["users"])
app/api/endpoints/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # File: my-fastapi-project/app/api/endpoints/__init__.py
2
 
3
  from fastapi import APIRouter
4
 
 
1
+ # File: whisper.api/app/api/endpoints/__init__.py
2
 
3
  from fastapi import APIRouter
4
 
app/api/endpoints/users.py CHANGED
@@ -1,12 +1,14 @@
1
  from fastapi import APIRouter
2
 
3
  from app.api.models.user import UserInDB
4
- from app.api.db import database
5
 
6
- users_router = r = APIRouter()
7
 
 
8
 
9
- @r.post("/", response_model=UserInDB, status_code=201)
 
10
  async def create_user(user: UserInDB):
11
  query = UserInDB.insert().values(
12
  username=user.username,
@@ -17,14 +19,14 @@ async def create_user(user: UserInDB):
17
  return {**user.dict(), "id": user_id}
18
 
19
 
20
- @r.get("/{id}/", response_model=UserInDB)
21
  async def read_user(id: int):
22
  query = UserInDB.select().where(UserInDB.c.id == id)
23
  user = await database.fetch_one(query)
24
  return user
25
 
26
 
27
- @r.put("/{id}/", response_model=UserInDB)
28
  async def update_user(id: int, user: UserInDB):
29
  query = (
30
  UserInDB
@@ -41,7 +43,7 @@ async def update_user(id: int, user: UserInDB):
41
  return {**user.dict(), "id": user_id}
42
 
43
 
44
- @r.delete("/{id}/", response_model=int)
45
  async def delete_user(id: int):
46
  query = UserInDB.delete().where(UserInDB.c.id == id)
47
  user_id = await database.execute(query)
 
1
  from fastapi import APIRouter
2
 
3
  from app.api.models.user import UserInDB
4
+ from app.core.database import SessionLocal
5
 
6
+ database = SessionLocal()
7
 
8
+ users_router = router = APIRouter()
9
 
10
+
11
+ @router.post("/", response_model=UserInDB, status_code=201)
12
  async def create_user(user: UserInDB):
13
  query = UserInDB.insert().values(
14
  username=user.username,
 
19
  return {**user.dict(), "id": user_id}
20
 
21
 
22
+ @router.get("/{id}/", response_model=UserInDB)
23
  async def read_user(id: int):
24
  query = UserInDB.select().where(UserInDB.c.id == id)
25
  user = await database.fetch_one(query)
26
  return user
27
 
28
 
29
+ @router.put("/{id}/", response_model=UserInDB)
30
  async def update_user(id: int, user: UserInDB):
31
  query = (
32
  UserInDB
 
43
  return {**user.dict(), "id": user_id}
44
 
45
 
46
+ @router.delete("/{id}/", response_model=int)
47
  async def delete_user(id: int):
48
  query = UserInDB.delete().where(UserInDB.c.id == id)
49
  user_id = await database.execute(query)
app/api/models/item.py CHANGED
@@ -13,7 +13,4 @@ class ItemCreate(ItemBase):
13
 
14
  class Item(ItemBase):
15
  id: int
16
- owner_id: int
17
-
18
- class Config:
19
- orm_mode = True
 
13
 
14
  class Item(ItemBase):
15
  id: int
16
+ owner_id: int
 
 
 
app/api/models/user.py CHANGED
@@ -10,5 +10,5 @@ class User(UserBase):
10
  id: int
11
  is_active: bool
12
 
13
- class Config:
14
- orm_mode = True
 
10
  id: int
11
  is_active: bool
12
 
13
+ class UserInDB(User):
14
+ hashed_password: str
app/core/config.py CHANGED
@@ -1,18 +1,24 @@
1
  from typing import Any, Dict, List, Optional, Union
2
- from pydantic import AnyHttpUrl, BaseSettings, validator
3
 
 
 
 
4
 
5
  class Settings(BaseSettings):
6
  API_V1_STR: str = "/api/v1"
7
  PROJECT_NAME: str = "Whisper API"
8
- SECRET_KEY: str
9
- ACCESS_TOKEN_EXPIRE_MINUTES: int = 60
10
- SERVER_NAME: str
11
- SERVER_HOST: AnyHttpUrl
12
- POSTGRES_SERVER: str
13
- POSTGRES_USER: str
14
- POSTGRES_PASSWORD: str
15
- POSTGRES_DB: str
 
 
 
16
 
17
  @validator("SECRET_KEY", pre=True)
18
  def secret_key_must_be_set(cls, v: Optional[str], values: Dict[str, Any]) -> str:
@@ -56,5 +62,12 @@ class Settings(BaseSettings):
56
  raise ValueError("POSTGRES_DB must be set")
57
  return v
58
 
 
 
 
 
 
 
 
59
 
60
  settings = Settings()
 
1
  from typing import Any, Dict, List, Optional, Union
2
+ from pydantic import AnyHttpUrl, validator
3
 
4
+ from pydantic_settings import BaseSettings, SettingsConfigDict
5
+
6
+ from os import environ as env
7
 
8
  class Settings(BaseSettings):
9
  API_V1_STR: str = "/api/v1"
10
  PROJECT_NAME: str = "Whisper API"
11
+ PROJECT_VERSION: str = "0.1.0"
12
+ SECRET_KEY: str = env.get("SECRET_KEY")
13
+ ACCESS_TOKEN_EXPIRE_MINUTES: int = env.get("ACCESS_TOKEN_EXPIRE_MINUTES")
14
+ SERVER_NAME: str = env.get("SERVER_NAME")
15
+ SERVER_HOST: AnyHttpUrl = env.get("SERVER_HOST")
16
+ POSTGRES_SERVER: str = env.get("POSTGRES_SERVER")
17
+ POSTGRES_USER: str = env.get("POSTGRES_USER")
18
+ POSTGRES_PASSWORD: str = env.get("POSTGRES_PASSWORD")
19
+ POSTGRES_DB: str = env.get("POSTGRES_DB")
20
+ POSTGRES_DATABASE_URL: str = env.get("POSTGRES_DATABASE_URL")
21
+ BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = ['http://localhost:3000']
22
 
23
  @validator("SECRET_KEY", pre=True)
24
  def secret_key_must_be_set(cls, v: Optional[str], values: Dict[str, Any]) -> str:
 
62
  raise ValueError("POSTGRES_DB must be set")
63
  return v
64
 
65
+ @validator("POSTGRES_DATABASE_URL", pre=True)
66
+ def postgres_db_url_must_be_set(cls, v: Optional[str], values: Dict[str, Any]) -> str:
67
+ if not v:
68
+ raise ValueError("POSTGRES_DATABASE_URL must be set")
69
+ return v
70
+
71
+
72
 
73
  settings = Settings()
app/core/database.py CHANGED
@@ -4,7 +4,7 @@ from sqlalchemy.orm import sessionmaker
4
 
5
  from app.core.config import settings
6
 
7
- SQLALCHEMY_DATABASE_URL = settings.database_url
8
 
9
  engine = create_engine(SQLALCHEMY_DATABASE_URL)
10
 
 
4
 
5
  from app.core.config import settings
6
 
7
+ SQLALCHEMY_DATABASE_URL = settings.POSTGRES_DATABASE_URL
8
 
9
  engine = create_engine(SQLALCHEMY_DATABASE_URL)
10
 
app/core/errors.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Request
2
+ from fastapi.responses import JSONResponse
3
+ from fastapi.exceptions import HTTPException , RequestValidationError
4
+
5
+ async def http_exception_handler(request: Request, exc: HTTPException):
6
+ """
7
+ Exception handler for HTTP errors
8
+ """
9
+ return JSONResponse(
10
+ status_code=exc.status_code,
11
+ content={"message": exc.detail},
12
+ )
13
+
14
+ async def http_error_handler(request: Request, exc: HTTPException):
15
+ """
16
+ Exception handler for HTTP errors
17
+ """
18
+ return JSONResponse(
19
+ status_code=exc.status_code,
20
+ content={"message": exc.detail},
21
+ )
22
+
23
+
24
+ def http422_error_handler(request: Request, exc: RequestValidationError):
25
+ """
26
+ Exception handler for HTTP 422 errors
27
+ """
28
+ return JSONResponse(
29
+ status_code=422,
30
+ content={"message": "Validation error", "details": exc.errors()},
31
+ )
app/core/security.py CHANGED
@@ -4,4 +4,17 @@ pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
4
 
5
  ALGORITHM = "HS256"
6
  ACCESS_TOKEN_EXPIRE_MINUTES = 30
7
- SECRET_KEY = "mysecretkey"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  ALGORITHM = "HS256"
6
  ACCESS_TOKEN_EXPIRE_MINUTES = 30
7
+ SECRET_KEY = "mysecretkey"
8
+
9
+
10
+ def get_password_hash(password: str) -> str:
11
+ """
12
+ Hashes a password using bcrypt algorithm
13
+ """
14
+ return pwd_context.hash(password)
15
+
16
+ def verify_password(password: str, hash: str) -> bool:
17
+ """
18
+ Verifies a password against a bcrypt hash
19
+ """
20
+ return pwd_context.verify(password, hash)
app/main.py CHANGED
@@ -1,5 +1,5 @@
1
  from fastapi import FastAPI
2
- from app.api.api_v1.api import router as api_router
3
  from app.core.config import settings
4
  from app.core.errors import http_error_handler
5
  from app.core.errors import http422_error_handler
 
1
  from fastapi import FastAPI
2
+ from app.api import api_router
3
  from app.core.config import settings
4
  from app.core.errors import http_error_handler
5
  from app.core.errors import http422_error_handler
app/tests/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # File: my-fastapi-project/app/tests/__init__.py
2
 
3
  # Import necessary modules
4
  import pytest
 
1
+ # File: whisper.api/app/tests/__init__.py
2
 
3
  # Import necessary modules
4
  import pytest
app/tests/test_api/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # File: my-fastapi-project/app/tests/test_api/__init__.py
2
 
3
  from fastapi.testclient import TestClient
4
  from my_fastapi_project.app.api import app
 
1
+ # File: whisper.api/app/tests/test_api/__init__.py
2
 
3
  from fastapi.testclient import TestClient
4
  from my_fastapi_project.app.api import app
requirements.txt CHANGED
@@ -6,4 +6,5 @@ psycopg2-binary
6
  pytest
7
  pytest-cov
8
  faker
9
- requests-mock
 
 
6
  pytest
7
  pytest-cov
8
  faker
9
+ requests-mock
10
+ passlib