adding .unix
This commit is contained in:
60
README.txt
60
README.txt
@@ -1,31 +1,31 @@
|
|||||||
I was too lazy to write this in a markdown file. And lazy enough to write this in English as well.
|
I was too lazy to write this in a markdown file. And lazy enough to write this in English as well.
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
Welp. Easy RESTful API and stuff.
|
Welp. Easy RESTful API and stuff.
|
||||||
|
|
||||||
Endpoints:
|
Endpoints:
|
||||||
- GET | / | Sample root endpoint.
|
- GET | / | Sample root endpoint.
|
||||||
- GET | /docs | Swagger UI for testing the endpoints.
|
- GET | /docs | Swagger UI for testing the endpoints.
|
||||||
- GET | /users | List all users.
|
- GET | /users | List all users.
|
||||||
- GET | /users/{id} | Gets a user by its id in database.
|
- GET | /users/{id} | Gets a user by its id in database.
|
||||||
- POST | /users | Adds a new user to the database.
|
- POST | /users | Adds a new user to the database.
|
||||||
|
|
||||||
Dependencies JIC you want to make your own virtual python environment:
|
Dependencies JIC you want to make your own virtual python environment:
|
||||||
- uvicorn | To run API apps
|
- uvicorn | To run API apps
|
||||||
- fastapi | This project's API Framework
|
- fastapi | This project's API Framework
|
||||||
- pydantic | Data validation library
|
- pydantic | Data validation library
|
||||||
- sqlalchemy | Framework to operate databases with abstractions
|
- sqlalchemy | Framework to operate databases with abstractions
|
||||||
|
|
||||||
Extra implementations:
|
Extra implementations:
|
||||||
- Database | SQLite3 Database file. /src/users.db
|
- Database | SQLite3 Database file. /src/users.db
|
||||||
- Windows & UNIX| For Windows or Linux servers, this API includes both .env directories for windows and UNIX. /.env & /.env-unix
|
- Windows & UNIX| For Windows or Linux servers, this API includes both .env directories for windows and UNIX. /.env & /.env-unix
|
||||||
|
|
||||||
Tested on:
|
Tested on:
|
||||||
- Windows
|
- Windows
|
||||||
- Linux (WSL & Native) - Using Arch Linux.
|
- Linux (WSL & Native) - Using Arch Linux.
|
||||||
|
|
||||||
Not tested on:
|
Not tested on:
|
||||||
- BSD - FreeBSD and/or NetBSD.
|
- BSD - FreeBSD and/or NetBSD.
|
||||||
- Docker.
|
- Docker.
|
||||||
- Micropython - ESP32.
|
- Micropython - ESP32.
|
||||||
- Other Python compatible systems.
|
- Other Python compatible systems.
|
||||||
14
deps.json
14
deps.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"1" : "uviconrn",
|
"1" : "uviconrn",
|
||||||
"2" : "fastapi",
|
"2" : "fastapi",
|
||||||
"3" : "pydantic",
|
"3" : "pydantic",
|
||||||
"4" : "sqlalchemy"
|
"4" : "sqlalchemy"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
class UserAlreadyExists(Exception):
|
class UserAlreadyExists(Exception):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from domain.users import User
|
from domain.users import User
|
||||||
|
|
||||||
class UserRepository(ABC):
|
class UserRepository(ABC):
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def save(self, user: User):
|
def save(self, user: User):
|
||||||
...
|
...
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def viewAll(self) -> list[User]:
|
def viewAll(self) -> list[User]:
|
||||||
...
|
...
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def viewById(self, user_id:int):
|
def viewById(self, user_id:int):
|
||||||
...
|
...
|
||||||
@@ -1,33 +1,33 @@
|
|||||||
from domain.users import User
|
from domain.users import User
|
||||||
from application.ports.user_repository import UserRepository
|
from application.ports.user_repository import UserRepository
|
||||||
|
|
||||||
class CreateUser:
|
class CreateUser:
|
||||||
def __init__(self, repo: UserRepository):
|
def __init__(self, repo: UserRepository):
|
||||||
if not isinstance(repo, UserRepository):
|
if not isinstance(repo, UserRepository):
|
||||||
raise TypeError("repo must implement UserRepository")
|
raise TypeError("repo must implement UserRepository")
|
||||||
self.repo = repo
|
self.repo = repo
|
||||||
|
|
||||||
def execute(self, name:str, email:str, phone:str):
|
def execute(self, name:str, email:str, phone:str):
|
||||||
user = User(user_id=0, email=email, name=name, phone=phone)
|
user = User(user_id=0, email=email, name=name, phone=phone)
|
||||||
self.repo.save(user)
|
self.repo.save(user)
|
||||||
return user
|
return user
|
||||||
|
|
||||||
class ViewUsers:
|
class ViewUsers:
|
||||||
def __init__(self, repo: UserRepository):
|
def __init__(self, repo: UserRepository):
|
||||||
if not isinstance(repo, UserRepository):
|
if not isinstance(repo, UserRepository):
|
||||||
raise TypeError("repo must implement UserRepository")
|
raise TypeError("repo must implement UserRepository")
|
||||||
self.repo = repo
|
self.repo = repo
|
||||||
|
|
||||||
def execute(self):
|
def execute(self):
|
||||||
users = self.repo.viewAll()
|
users = self.repo.viewAll()
|
||||||
return users
|
return users
|
||||||
|
|
||||||
class ViewUserById:
|
class ViewUserById:
|
||||||
def __init__(self, repo: UserRepository):
|
def __init__(self, repo: UserRepository):
|
||||||
if not isinstance(repo, UserRepository):
|
if not isinstance(repo, UserRepository):
|
||||||
raise TypeError("repo must implement UserRepository")
|
raise TypeError("repo must implement UserRepository")
|
||||||
self.repo = repo
|
self.repo = repo
|
||||||
|
|
||||||
def execute(self, user_id: int) -> User | None:
|
def execute(self, user_id: int) -> User | None:
|
||||||
user = self.repo.viewById(user_id)
|
user = self.repo.viewById(user_id)
|
||||||
return user
|
return user
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class User:
|
class User:
|
||||||
user_id: int
|
user_id: int
|
||||||
name: str
|
name: str
|
||||||
email: str
|
email: str
|
||||||
phone: str
|
phone: str
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
from infrastructure.adapters.persistence.db import engine
|
from infrastructure.adapters.persistence.db import engine
|
||||||
from infrastructure.adapters.persistence.models import Base
|
from infrastructure.adapters.persistence.models import Base
|
||||||
|
|
||||||
Base.metadata.create_all(bind=engine)
|
Base.metadata.create_all(bind=engine)
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker, declarative_base
|
from sqlalchemy.orm import sessionmaker, declarative_base
|
||||||
|
|
||||||
DATABASE_URL = "sqlite:///./users.db"
|
DATABASE_URL = "sqlite:///./users.db"
|
||||||
|
|
||||||
engine = create_engine(
|
engine = create_engine(
|
||||||
DATABASE_URL,
|
DATABASE_URL,
|
||||||
connect_args={"check_same_thread": False}
|
connect_args={"check_same_thread": False}
|
||||||
)
|
)
|
||||||
|
|
||||||
SessionLocal = sessionmaker(
|
SessionLocal = sessionmaker(
|
||||||
bind=engine,
|
bind=engine,
|
||||||
autocommit=False,
|
autocommit=False,
|
||||||
autoflush=False
|
autoflush=False
|
||||||
)
|
)
|
||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from sqlalchemy import Column, Integer, String
|
from sqlalchemy import Column, Integer, String
|
||||||
from infrastructure.adapters.persistence.db import Base
|
from infrastructure.adapters.persistence.db import Base
|
||||||
|
|
||||||
class UserModel(Base):
|
class UserModel(Base):
|
||||||
__tablename__ = "users"
|
__tablename__ = "users"
|
||||||
|
|
||||||
user_id = Column(Integer, primary_key=True, index=True)
|
user_id = Column(Integer, primary_key=True, index=True)
|
||||||
name = Column(String, unique=False, index=True)
|
name = Column(String, unique=False, index=True)
|
||||||
email = Column(String, unique=True, index=True)
|
email = Column(String, unique=True, index=True)
|
||||||
phone = Column(String, unique=True, index=True)
|
phone = Column(String, unique=True, index=True)
|
||||||
@@ -1,61 +1,61 @@
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from domain.users import User
|
from domain.users import User
|
||||||
from application.ports.user_repository import UserRepository
|
from application.ports.user_repository import UserRepository
|
||||||
from infrastructure.adapters.persistence.db import SessionLocal
|
from infrastructure.adapters.persistence.db import SessionLocal
|
||||||
from infrastructure.adapters.persistence.models import UserModel
|
from infrastructure.adapters.persistence.models import UserModel
|
||||||
from application.exceptions import UserAlreadyExists
|
from application.exceptions import UserAlreadyExists
|
||||||
|
|
||||||
class SqlUserRepository(UserRepository):
|
class SqlUserRepository(UserRepository):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.db: Session = SessionLocal()
|
self.db: Session = SessionLocal()
|
||||||
|
|
||||||
def save(self, user: User):
|
def save(self, user: User):
|
||||||
model = UserModel(
|
model = UserModel(
|
||||||
name= user.name,
|
name= user.name,
|
||||||
email=user.email,
|
email=user.email,
|
||||||
phone=user.phone
|
phone=user.phone
|
||||||
)
|
)
|
||||||
|
|
||||||
self.db.add(model)
|
self.db.add(model)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.db.commit()
|
self.db.commit()
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
self.db.rollback()
|
self.db.rollback()
|
||||||
raise UserAlreadyExists("A user with the same phone number or name does already exist.")
|
raise UserAlreadyExists("A user with the same phone number or name does already exist.")
|
||||||
|
|
||||||
|
|
||||||
self.db.refresh(model)
|
self.db.refresh(model)
|
||||||
|
|
||||||
return User(
|
return User(
|
||||||
user_id = model.user_id,
|
user_id = model.user_id,
|
||||||
name = model.name,
|
name = model.name,
|
||||||
email = model.email,
|
email = model.email,
|
||||||
phone = model.phone
|
phone = model.phone
|
||||||
)
|
)
|
||||||
|
|
||||||
def viewAll(self) -> list[User]:
|
def viewAll(self) -> list[User]:
|
||||||
models = self.db.query(UserModel).all()
|
models = self.db.query(UserModel).all()
|
||||||
|
|
||||||
return [
|
return [
|
||||||
User(
|
User(
|
||||||
user_id=model.user_id,
|
user_id=model.user_id,
|
||||||
name = model.name,
|
name = model.name,
|
||||||
email = model.email,
|
email = model.email,
|
||||||
phone = model.phone
|
phone = model.phone
|
||||||
) for model in models
|
) for model in models
|
||||||
]
|
]
|
||||||
|
|
||||||
def viewById(self, user_id: int) -> User | None:
|
def viewById(self, user_id: int) -> User | None:
|
||||||
model = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
|
model = self.db.query(UserModel).filter(UserModel.user_id == user_id).first()
|
||||||
|
|
||||||
if not model:
|
if not model:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return User(
|
return User(
|
||||||
user_id=model.user_id,
|
user_id=model.user_id,
|
||||||
name = model.name,
|
name = model.name,
|
||||||
email = model.email,
|
email = model.email,
|
||||||
phone = model.phone
|
phone = model.phone
|
||||||
)
|
)
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from infrastructure.api.users.router import router
|
from infrastructure.api.users.router import router
|
||||||
|
|
||||||
def create_app() -> FastAPI:
|
def create_app() -> FastAPI:
|
||||||
app = FastAPI(title="Users service")
|
app = FastAPI(title="Users service")
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
return app
|
return app
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("/")
|
||||||
def root():
|
def root():
|
||||||
return {
|
return {
|
||||||
"Status": "Running",
|
"Status": "Running",
|
||||||
"Docs": "/docs"
|
"Docs": "/docs"
|
||||||
}
|
}
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from infrastructure.api.users.users import router as users_router
|
from infrastructure.api.users.users import router as users_router
|
||||||
from infrastructure.api.users.root import router as root_router
|
from infrastructure.api.users.root import router as root_router
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
router.include_router(
|
router.include_router(
|
||||||
users_router,
|
users_router,
|
||||||
prefix="/users",
|
prefix="/users",
|
||||||
tags=["users"]
|
tags=["users"]
|
||||||
)
|
)
|
||||||
|
|
||||||
router.include_router(
|
router.include_router(
|
||||||
root_router,
|
root_router,
|
||||||
prefix='',
|
prefix='',
|
||||||
tags=["root"]
|
tags=["root"]
|
||||||
)
|
)
|
||||||
@@ -1,44 +1,44 @@
|
|||||||
from fastapi import APIRouter, HTTPException
|
from fastapi import APIRouter, HTTPException
|
||||||
from application.services.user_services import CreateUser, ViewUsers, ViewUserById
|
from application.services.user_services import CreateUser, ViewUsers, ViewUserById
|
||||||
from infrastructure.adapters.persistence.user_repository_sql import SqlUserRepository
|
from infrastructure.adapters.persistence.user_repository_sql import SqlUserRepository
|
||||||
from application.exceptions import UserAlreadyExists
|
from application.exceptions import UserAlreadyExists
|
||||||
|
|
||||||
router = APIRouter()
|
router = APIRouter()
|
||||||
|
|
||||||
@router.post("/")
|
@router.post("/")
|
||||||
def create_user(name:str, email:str, phone:str):
|
def create_user(name:str, email:str, phone:str):
|
||||||
service = CreateUser(SqlUserRepository())
|
service = CreateUser(SqlUserRepository())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return service.execute(name,email,phone)
|
return service.execute(name,email,phone)
|
||||||
except UserAlreadyExists as e:
|
except UserAlreadyExists as e:
|
||||||
raise HTTPException (
|
raise HTTPException (
|
||||||
status_code=409,
|
status_code=409,
|
||||||
detail=str(e)
|
detail=str(e)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.get("/")
|
@router.get("/")
|
||||||
def view_all_users():
|
def view_all_users():
|
||||||
|
|
||||||
service = ViewUsers(SqlUserRepository())
|
service = ViewUsers(SqlUserRepository())
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return service.execute()
|
return service.execute()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
detail=e)
|
detail=e)
|
||||||
|
|
||||||
@router.get("/{id}")
|
@router.get("/{id}")
|
||||||
def view_user_by_id(user_id: int):
|
def view_user_by_id(user_id: int):
|
||||||
service = ViewUserById(SqlUserRepository())
|
service = ViewUserById(SqlUserRepository())
|
||||||
|
|
||||||
result = service.execute(user_id)
|
result = service.execute(user_id)
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=404,
|
status_code=404,
|
||||||
detail="User not found")
|
detail="User not found")
|
||||||
|
|
||||||
return result
|
return result
|
||||||
32
src/main.py
32
src/main.py
@@ -1,16 +1,16 @@
|
|||||||
from infrastructure.api.users.app import create_app
|
from infrastructure.api.users.app import create_app
|
||||||
|
|
||||||
app = create_app()
|
app = create_app()
|
||||||
|
|
||||||
def run():
|
def run():
|
||||||
import uvicorn
|
import uvicorn
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"main:app",
|
"main:app",
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
port=8000,
|
port=8000,
|
||||||
reload=True,
|
reload=True,
|
||||||
log_level="info",
|
log_level="info",
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run()
|
run()
|
||||||
|
|||||||
Reference in New Issue
Block a user