Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature/andrew #64

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sqlite
create_tables.py
5 changes: 5 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM python:3.13-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY ./app .
94 changes: 70 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,37 +1,83 @@
![WATTIO](http://wattio.com.br/web/image/1204-212f47c3/Logo%20Wattio.png)
# Desafio Wattio

#### Descrição
Implementação da atividade sugerida para a vaga de estágio back-end na Wattio.

O desafio consiste em implementar um CRUD de filmes, utilizando [python](https://www.python.org/ "python") integrando com uma API REST e uma possível persistência de dados.
## Pré-requisitos

Rotas da API:
O daemon do Docker precisa estar executando em segundo plano.

- `/filmes` - [GET] deve retornar todos os filmes cadastrados.
- `/filmes` - [POST] deve cadastrar um novo filme.
- `/filmes/{id}` - [GET] deve retornar o filme com ID especificado.
## Como executar essa aplicação

O Objetivo é te desafiar e reconhecer seu esforço para aprender e se adaptar. Qualquer código enviado, ficaremos muito felizes e avaliaremos com toda atenção!
1. Clone o repositório e acesse a pasta da aplicação

#### Sugestão de Ferramentas
Não é obrigatório utilizar todas as as tecnologias sugeridas, mas será um diferencial =]
```
git clone --branch feature/andrew git@github.com:andrewunifei/backend.git
cd backend
```

- Orientação a objetos (utilizar objetos, classes para manipular os filmes)
- [FastAPI](https://fastapi.tiangolo.com/) (API com documentação auto gerada)
- [Docker](https://www.docker.com/) / [Docker-compose](https://docs.docker.com/compose/install/) (Aplicação deverá ficar em um container docker, e o start deverá seer com o comando ``` docker-compose up ```
- Integração com banco de dados (persistir as informações em json (iniciante) /[SqLite](https://www.sqlite.org/index.html) / [SQLAlchemy](https://fastapi.tiangolo.com/tutorial/sql-databases/#sql-relational-databases) / outros DB)
2. Execute o arquivo do docker compose

```
docker compose up --build
```

#### Como começar?
## Utilizando a aplicação

- Fork do repositório
- Criar branch com seu nome ``` git checkout -b feature/ana ```
- Faça os commits de suas alterações ``` git commit -m "[ADD] Funcionalidade" ```
- Envie a branch para seu repositório ``` git push origin feature/ana ```
- Navegue até o [Github](https://github.com/), crie seu Pull Request apontando para a branch **```main```**
- Atualize o README.md descrevendo como subir sua aplicação
O docker compose irá iniciar o contâiner com o sqlite e criará um banco de dados e uma tabela de filmes caso ela não exista. O docker compose também irá iniciar um segundo contâiner com o server rodando ouvindo as requisições.

#### Dúvidas?
O banco de dados vem apenas com a tabela filmes e ela está vazia. É necessário adicionar filmes.

Qualquer dúvida / sugestão / melhoria / orientação adicional só enviar email para hendrix@wattio.com.br
### Endpoints da API

Salve!
Exemplos:

#### ```GET /filmes```

Corpo da resposta:

```JSON
[
{
"id": 1,
"nome": "Pulp Fiction",
"ano": 1995,
"diretor": "Quentin Tarantino"
}
]
```

#### ```GET /filmes/{id}```

Corpo da resposta:

```JSON
{
"id": 1,
"nome": "Pulp Fiction",
"ano": 1995,
"diretor": "Quentin Tarantino"
}
```

#### ```POST /filmes```

Corpo da requisição:

```JSON
{
"nome": "Pulp Fiction",
"ano": 1995,
"diretor": "Quentin Tarantino"
}
```

Corpo da resposta:

```JSON
{
"id": 1,
"nome": "Pulp Fiction",
"ano": 1995,
"diretor": "Quentin Tarantino"
}
```
12 changes: 12 additions & 0 deletions app/database/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base

Base = declarative_base()

class Movie(Base):
__tablename__ = "filmes"

id = Column(Integer, primary_key=True, index=True, autoincrement=True)
nome = Column(String)
ano = Column(Integer)
diretor = Column(String)
7 changes: 7 additions & 0 deletions app/database/session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import os
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

SQLITE_URL = os.getenv('SQLITE_URL')
engine = create_engine(SQLITE_URL)
Session = sessionmaker(autocommit=False, autoflush=False, bind=engine)
12 changes: 12 additions & 0 deletions app/database/type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from pydantic import BaseModel

class MovieIn(BaseModel):
nome: str
ano: int
diretor: str

class MovieOut(BaseModel):
id: int
nome: str
ano: int
diretor: str
26 changes: 26 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from fastapi import FastAPI
from database.type import MovieOut, MovieIn
from typing import List
from database.session import Session, engine
from database import models

app = FastAPI()
db = Session()

@app.get("/filmes", response_model=List[MovieOut])
async def get_all_movies():
movies = db.query(models.Movie).all()
return movies

@app.get("/filmes/{id}", response_model=MovieOut)
async def get_movie(id: int):
movie = db.query(models.Movie).filter(models.Movie.id == id).first()
return movie

@app.post("/filmes", response_model=MovieOut)
async def create_movie(movie: MovieIn):
new_movie = models.Movie(**movie.dict())
db.add(new_movie)
db.commit()
db.refresh(new_movie)
return new_movie
23 changes: 23 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
services:
sqlite:
build:
context: ./sqlite_service
dockerfile: Dockerfile
ports:
- "8191:8191"
volumes:
- ./sqlite:/db
command: [sqlite3, "database_filmes.db", ".read ../init.sql"]
server:
build:
context: .
dockerfile: Dockerfile
depends_on:
- sqlite
ports:
- "8080:8080"
volumes:
- ./sqlite:/data/sqlite_db
environment:
SQLITE_URL: sqlite:////data/sqlite_db/database_filmes.db
command: [sh, -cx, "uvicorn main:app --host 0.0.0.0 --port 8080"]
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
fastapi[standard]
uvicorn
sqlalchemy
4 changes: 4 additions & 0 deletions sqlite_service/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
FROM alpine:latest
RUN apk update && apk add sqlite
COPY init.sql .
WORKDIR /db
6 changes: 6 additions & 0 deletions sqlite_service/init.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
CREATE TABLE IF NOT EXISTS filmes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
nome TEXT NOT NULL,
ano INTEGER NOT NULL,
diretor TEXT NOT NULL
);