---
tags: React, FastAPI, MongoDB
---
# React & FastAPI & MongoDB
## pre-requirement
- MongoDB
- NPM
- Python 10
## Environment
### MongoDB
[MongoDB]([MongoDB](https://www.mongodb.com/))
`mongod --version`
`mongodsh` : mongodb shell (for commands)
`show dbs` : checkout all dbs
### React
`npx create-react-app [app-name]`
`npm start`: start server at localhost:3000
`npm install axios bootstrap`
### FastAPI
A fast(both performance and develop) tool for building APIs with built-in swagger doc.
*install in virtual env*
`fastapi`: FastAPI
`uvicorn`: ASGI web server for python
`motor`: coroutine-based API for non-blocking access to MongoDB from Tornado or asyncio.
## Build
### Backend
#### CORSMiddleware
`CORS`: Cross Origin Resourse Sharing
Request should be in same domain for safety reason. An application should open accessibility for certain domains that are different from itself.
```python
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=origin_list,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*']
)
```
#### A simple get
```python
@app.get("/")
def read_root():
return {"Ping":"Pong"}
```
#### A simple CRUD of todos
```python
@app.get("/api/todo")
def get_todos():
return [todos]
@app.get("/api/todo/{id}")
async def get_todo_by_id(id):
return [todo]
# create
@app.post("/api/todo")
async def post_todo(todo):
return [todo]
@app.put("/api/todo/{id}")
async def put_todo(todo):
return [todo]
@app.delete("/api/todo/{id}")
async def delete_todo(todo):
return [todo]
```
#### Build todo model
`pydantic`: A tool to validate and setup data types through type annotations. It enforces type hints at runtime and provides user friendly errors when data is invalid.
[pydantic docs](https://pydantic-docs.helpmanual.io/)
```python
from pydantic import BaseModel
class Todo(BaseModel):
title: str
description: str
```
#### Database connection
[motor docs](https://pydantic-docs.helpmanual.io/)
```python
from motor import motor.motor_asyncio
client = motor.motor_asyncio.AsyncIOMotorClient("mongodb://localhost:27017")
database = client.TodoList
collection = database.todo
```
#### Database query
query format follows [mongodb operations](https://www.mongodb.com/docs/manual/crud/)
```python
# database.py
async def fetch_one_todo(title):
document = await.collection.find_one({"title": title})
return document
async def update_todo(title, desc):
await.collection.update_one({"title": title}, {
"$set": {"description": desc}
})
document = await.collection.find_one({"title": title})
return document
```
```python
# main.py
from database import update_todo
@app.post("/api/todo/{title}", response_model=Todo)
async def put_todo(todo: Todo):
response = await update_todo(todo.dict())
if response:
return response
raise HTTPException(400, "Something went wrong/ bad request")
```
### Frontend
#### JSX
- Javascript XML.
- Allows us to write HTML in React.
- Makes it easier to write and add HTML in React.
#### Root component
Only one root component
```jsx
function App() {
return (
<div className="container">
<div
className="App"
style={{
"width": "400px"
}}
>
<h1>Task Manager</h1>
</div>
</div>
)
}
export default App;
```
#### TodoList Component
- Depart the **todo list** and make it as a component.
`useState`: Tracks state in a function component.
The first value is current state,
the second value is the function which used to update the state.
```jsx
import React, {useState, useEffect} from 'react';
function App() {
const [todoList, setTodoList] = useState([{}])
//todoList's initial = [{}]
...
<TodoListView todoList={todoList} />
}
```
- Inside the TodoList View
- Depart every **todo item** and make it as a component as well.
`props` stands for properties.
```jsx
function TodoListView(props) {
return (
<div>
<ul>
{props.todoList.map(
todo => <TodoItem todo={todo} />)}
</ul>
</div>
)
}
export default TodoListView
```
#### useEffect + axios to get todos
`useEffect`: `useEffect(<function>, <dependency>:optional)`
Allows component performs side effects such as fetching data, timers, updating the DOM directly.
```jsx
useEffect(() =>
axios.get('http://localhost:8000/api/todo')
.then(res => {
setTodoList(res.data)
})
);
```
## Run
- frontend
`npm start`
- backend
`pipenv shell`
`uvicorn app:main --reload`