Skip to content

Commit 67ab7e4

Browse files
committed
Initial commit
0 parents  commit 67ab7e4

File tree

3 files changed

+149
-0
lines changed

3 files changed

+149
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__
2+
.vscode
3+
.envrc

app.py

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import os
2+
from fastapi import FastAPI, Body, HTTPException, status
3+
from fastapi.responses import JSONResponse
4+
from fastapi.encoders import jsonable_encoder
5+
from pydantic import BaseModel, Field, EmailStr
6+
from bson import ObjectId
7+
from typing import Optional, List
8+
import motor.motor_asyncio
9+
10+
app = FastAPI()
11+
client = motor.motor_asyncio.AsyncIOMotorClient(os.environ["MONGODB_URL"])
12+
db = client.college
13+
14+
15+
class PyObjectId(ObjectId):
16+
@classmethod
17+
def __get_validators__(cls):
18+
yield cls.validate
19+
20+
@classmethod
21+
def validate(cls, v):
22+
if not ObjectId.is_valid(v):
23+
raise ValueError("Invalid objectid")
24+
return ObjectId(v)
25+
26+
@classmethod
27+
def __modify_schema__(cls, field_schema):
28+
field_schema.update(type="string")
29+
30+
31+
class StudentModel(BaseModel):
32+
id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")
33+
name: str = Field(...)
34+
email: EmailStr = Field(...)
35+
course: str = Field(...)
36+
gpa: float = Field(..., le=4.0)
37+
38+
class Config:
39+
allow_population_by_field_name = True
40+
arbitrary_types_allowed = True
41+
json_encoders = {ObjectId: str}
42+
schema_extra = {
43+
"example": {
44+
"name": "Jane Doe",
45+
"email": "jdoe@example.com",
46+
"course": "Experiments, Science, and Fashion in Nanophotonics",
47+
"gpa": "3.0",
48+
}
49+
}
50+
51+
52+
class UpdateStudentModel(BaseModel):
53+
name: Optional[str]
54+
email: Optional[EmailStr]
55+
course: Optional[str]
56+
gpa: Optional[float]
57+
58+
class Config:
59+
arbitrary_types_allowed = True
60+
json_encoders = {ObjectId: str}
61+
schema_extra = {
62+
"example": {
63+
"name": "Jane Doe",
64+
"email": "jdoe@example.com",
65+
"course": "Experiments, Science, and Fashion in Nanophotonics",
66+
"gpa": "3.0",
67+
}
68+
}
69+
70+
71+
@app.post("/", response_description="Add new student", response_model=StudentModel)
72+
async def create_student(student: StudentModel = Body(...)):
73+
student = jsonable_encoder(student)
74+
new_student = await db["students"].insert_one(student)
75+
created_student = await db["students"].find_one({"_id": new_student.inserted_id})
76+
return JSONResponse(status_code=status.HTTP_201_CREATED, content=created_student)
77+
78+
79+
@app.get(
80+
"/", response_description="List all students", response_model=List[StudentModel]
81+
)
82+
async def list_students():
83+
students = await db["students"].find().to_list(1000)
84+
return students
85+
86+
87+
@app.get(
88+
"/{id}", response_description="Get a single student", response_model=StudentModel
89+
)
90+
async def show_student(id: str):
91+
if (student := await db["students"].find_one({"_id": id})) is not None:
92+
return student
93+
94+
raise HTTPException(status_code=404, detail=f"Student {id} not found")
95+
96+
97+
@app.put("/{id}", response_description="Update a student", response_model=StudentModel)
98+
async def update_student(id: str, student: UpdateStudentModel = Body(...)):
99+
student = {k: v for k, v in student.dict().items() if v is not None}
100+
101+
if len(student) >= 1:
102+
update_result = await db["students"].update_one({"_id": id}, {"$set": student})
103+
104+
if update_result.modified_count == 1:
105+
if (
106+
updated_student := await db["students"].find_one({"_id": id})
107+
) is not None:
108+
return updated_student
109+
110+
if (existing_student := await db["students"].find_one({"_id": id})) is not None:
111+
return existing_student
112+
113+
raise HTTPException(status_code=404, detail=f"Student {id} not found")
114+
115+
116+
@app.delete("/{id}", response_description="Delete a student")
117+
async def delete_student(id: str):
118+
delete_result = await db["students"].delete_one({"_id": id})
119+
120+
if delete_result.deleted_count == 1:
121+
return JSONResponse(status_code=status.HTTP_204_NO_CONTENT)
122+
123+
raise HTTPException(status_code=404, detail=f"Student {id} not found")

requirements.txt

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
appdirs==1.4.4
2+
black==20.8b1
3+
click==7.1.2
4+
dnspython==2.0.0
5+
email-validator==1.1.2
6+
fastapi==0.62.0
7+
flake8==3.8.4
8+
h11==0.11.0
9+
idna==2.10
10+
mccabe==0.6.1
11+
motor==2.3.0
12+
mypy-extensions==0.4.3
13+
pathspec==0.8.1
14+
pycodestyle==2.6.0
15+
pydantic==1.7.3
16+
pyflakes==2.2.0
17+
pymongo==3.11.1
18+
regex==2020.11.13
19+
starlette==0.13.6
20+
toml==0.10.2
21+
typed-ast==1.4.1
22+
typing-extensions==3.7.4.3
23+
uvicorn==0.12.3

0 commit comments

Comments
 (0)