USER
ok want to use this backend api to vercel how i can ? :
MONGODB_URI="mongodb+srv://123:123@firstserv.i5myl.mongodb.net/?retryWrites=true&w=majority&appName=FIRSTSERv"
SECRET_KEY="d09aee7b1159d2519918aefe2e0b4084c14d405f73f0640ce22a48efa0056964"
ALGORITHM="HS256"
ACCESS_TOKEN_EXPIRE_MINUTES=30
# authentication.py
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from database import users_collection
from models import UserInDB
from config import SECRET_KEY, ALGORITHM, ACCESS_TOKEN_EXPIRE_MINUTES
import bcrypt
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
# Fonction pour vérifier l'utilisateur
def verify_password(plain_password, hashed_password):
return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))
# Fonction pour récupérer l'utilisateur
def get_user(db, username: str):
user = db.find_one({"name": username})
if user:
return UserInDB(name=user["name"], hashed_password=user["password"])
return None
# Fonction pour authentifier l'utilisateur
def authenticate_user(db, username: str, password: str):
user = get_user(db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
# Fonction pour créer un token d'accès
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta if expires_delta else timedelta(minutes=15))
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
# Fonction pour obtenir l'utilisateur actuel
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=401,
detail="Impossible de valider les informations d'identification",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
user = get_user(users_collection, username)
if user is None:
raise credentials_exception
return user
except JWTError:
raise credentials_exception
# config.py
import os
from dotenv import load_dotenv
from pathlib import Path
env_path = Path(__file__).resolve().parent / '.env'
load_dotenv(dotenv_path=env_path)
#hello
MONGODB_URI = os.getenv("MONGODB_URI")
SECRET_KEY = os.getenv("SECRET_KEY")
ALGORITHM = os.getenv("ALGORITHM")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES"))
# database.py
from pymongo import MongoClient
from config import MONGODB_URI
client = MongoClient(MONGODB_URI)
db = client["FIRSTSERv"]
users_collection = db["users"]
conversations_collection = db["conversations"]
# main.py
from fastapi import FastAPI, Depends, HTTPException, status
from typing import List
from fastapi.middleware.cors import CORSMiddleware
from models import UserCreate, User, UserBase, UserInDB, Message, Conversation
from datetime import timedelta
from authentication import authenticate_user, create_access_token, get_current_user
from config import ACCESS_TOKEN_EXPIRE_MINUTES
from database import users_collection, conversations_collection
from bson.objectid import ObjectId
import bcrypt
app = FastAPI()
# Configuration CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # En production, spécifiez l'origine exacte
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# ---- Gestion des utilisateurs ----
@app.get("/")
def read_root():
return {"message": "Hello, world!"}
@app.post("/signup", response_model=User)
def signup(user: UserCreate):
# Vérifier si l'utilisateur existe déjà
if users_collection.find_one({"name": user.name}):
raise HTTPException(status_code=400, detail="Un utilisateur avec ce nom existe déjà.")
# asher le mot de passe
hashed_password = bcrypt.hashpw(user.password.encode('utf-8'), bcrypt.gensalt())
# Créer l'utilisateur
user_doc = {
"name": user.name,
"password": hashed_password.decode('utf-8')
}
result = users_collection.insert_one(user_doc)
return User(id=str(result.inserted_id), name=user.name)
@app.post("/login")
def login(form_data: UserCreate):
user = authenticate_user(users_collection, form_data.name, form_data.password)
if not user:
raise HTTPException(status_code=400, detail="Nom d'utilisateur ou mot de passe incorrect")
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.name}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
# ---- Gestion des conversations ----
@app.post("/conversations", response_model=Conversation)
def create_conversation(participants: List[str], current_user: UserInDB = Depends(get_current_user)):
# Ajouter l'utilisateur courant aux participants s'il n'est pas déjà présent
if current_user.name not in participants:
participants.append(current_user.name)
# Vérifier que les utilisateurs existent
for name in participants:
if not users_collection.find_one({"name": name}):
raise HTTPException(status_code=404, detail=f"Utilisateur {name} introuvable")
# Vérifier si la conversation existe déjà
conversation = conversations_collection.find_one({"participants": {"$all": participants}})
if conversation:
raise HTTPException(status_code=400, detail="La conversation existe déjà")
# Créer la conversation
conversation_doc = {
"participants": participants,
"messages": []
}
result = conversations_collection.insert_one(conversation_doc)
return Conversation(id=str(result.inserted_id), participants=participants)
@app.get("/conversations", response_model=List[Conversation])
def get_user_conversations(current_user: UserInDB = Depends(get_current_user)):
conversations = conversations_collection.find({"participants": current_user.name})
convo_list = []
for convo in conversations:
convo_list.append(Conversation(
id=str(convo['_id']),
participants=convo["participants"]
))
return convo_list
@app.get("/conversations/{conversation_id}", response_model=Conversation)
def get_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
if not conversation:
raise HTTPException(status_code=404, detail="Conversation non trouvée")
if current_user.name not in conversation["participants"]:
raise HTTPException(status_code=403, detail="Accès refusé")
messages = [Message(**msg) for msg in conversation.get("messages", [])]
return Conversation(
id=str(conversation['_id']),
participants=conversation["participants"],
messages=messages
)
@app.post("/conversations/{conversation_id}/messages", response_model=Message)
def send_message(conversation_id: str, message: Message, current_user: UserInDB = Depends(get_current_user)):
conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
if not conversation:
raise HTTPException(status_code=404, detail="Conversation non trouvée")
if current_user.name not in conversation["participants"]:
raise HTTPException(status_code=403, detail="Accès refusé")
message_doc = message.dict()
message_doc["timestamp"] = message.timestamp
conversations_collection.update_one(
{"_id": ObjectId(conversation_id)},
{"$push": {"messages": message_doc}}
)
return message
@app.delete("/conversations/{conversation_id}")
def delete_conversation(conversation_id: str, current_user: UserInDB = Depends(get_current_user)):
conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
if not conversation:
raise HTTPException(status_code=404, detail="Conversation non trouvée")
if current_user.name not in conversation["participants"]:
raise HTTPException(status_code=403, detail="Accès refusé")
conversations_collection.delete_one({"_id": ObjectId(conversation_id)})
return {"detail": "Conversation supprimée"}
# ---- Gestion des utilisateurs connectés ----
@app.get("/users/me", response_model=UserBase)
def read_current_user(current_user: UserInDB = Depends(get_current_user)):
return UserBase(name=current_user.name)
@app.get("/users", response_model=List[UserBase])
def get_all_users(current_user: UserInDB = Depends(get_current_user)):
users = users_collection.find({})
return [UserBase(name=user["name"]) for user in users]
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
# models.py
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import datetime
# Modèles pour l'utilisateur
class UserBase(BaseModel):
name: str
class UserCreate(UserBase):
password: str
class UserInDB(UserBase):
hashed_password: str
class User(UserBase):
id: str
# Modèles pour les messages
class Message(BaseModel):
sender: str
message: str
timestamp: datetime = Field(default_factory=datetime.utcnow)
# Modèles pour les conversations
class Conversation(BaseModel):
id: str
participants: List[str]
messages: List[Message] = []
warning each import is a new different file ASSISTANT
Deploying a FastAPI backend with multiple files and dependencies (like your project) to Vercel can be a bit challenging due to the way Vercel handles Python serverless functions. However, it is possible with some adjustments to your project structure.
Here’s a step-by-step guide to help you deploy your FastAPI backend API to Vercel:
---
### **1. Project Structure**
First, restructure your project to fit Vercel's expected layout. Your project should look like this:
```
your_project/
├── api/
│ ├── __init__.py
│ ├── main.py
│ ├── authentication.py
│ ├── config.py
│ ├── database.py
│ ├── models.py
│ ├── requirements.txt
│ └── .env
└── vercel.json
```
**Explanation:**
- **`api/` Directory**: Vercel treats the `api/` directory specially. Any Python files in this directory can be deployed as serverless functions.
- **`vercel.json`**: This configuration file tells Vercel how to build and route your application.
---
### **2. Adjust Your Code**
**a. Entry Point (`main.py`):**
- Move your `main.py` into the `api/` directory.
- Ensure that your FastAPI application instance is named `app`, which is required by Vercel.
```python
# api/main.py
from fastapi import FastAPI
# Import other modules as needed
from authentication import *
from config import *
from database import *
from models import *
app = FastAPI()
# Your routes and logic here
# Remove the __main__ block
# if __name__ == "__main__":
# import uvicorn
# uvicorn.run(app, host="0.0.0.0", port=8000)
```
**b. Imports:**
- Ensure all your imports are relative and point to the correct modules within the `api/` directory.
**c. Environment Variables:**
- Remove any direct use of `.env` files in your code since Vercel doesn't support loading `.env` files by default.
- Instead, use `os.getenv()` to access environment variables.
For example:
```python
# config.py
import os
MONGODB_URI = os.getenv("MONGODB_URI")
SECRET_KEY = os.getenv("SECRET_KEY")
ALGORITHM = os.getenv("ALGORITHM")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", 30))
```
---
### **3. Environment Variables on Vercel**
Set your environment variables in Vercel:
- Log in to your Vercel dashboard.
- Navigate to your project.
- Go to **Settings** > **Environment Variables**.
- Add all the necessary environment variables (`MONGODB_URI`, `SECRET_KEY`, `ALGORITHM`, `ACCESS_TOKEN_EXPIRE_MINUTES`, etc.).
---
### **4. `requirements.txt` File**
Create a `requirements.txt` file inside your `api/` directory with all your dependencies:
```plaintext
fastapi
pymongo
bcrypt
python-dotenv
python-jose[cryptography]
```
Note: Include any other packages your project depends on.
---
### **5. `vercel.json` Configuration**
Create a `vercel.json` file in the root of your project:
```json
{
"builds": [
{
"src": "api/main.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "api/main.py"
}
]
}
```
**Explanation:**
- **`builds`**: Defines how to build your application using Vercel’s Python runtime.
- **`routes`**: Routes all incoming traffic to your `main.py` serverless function.
---
### **6. Deployment**
**a. Install Vercel CLI:**
If you haven't installed the Vercel CLI, install it using npm:
```bash
npm i -g vercel
```
**b. Deploying the Application:**
From your project's root directory, run:
```bash
vercel
```
Follow the prompts to:
- Link or create a new Vercel project.
- Select the deployment scope (personal or team).
- Choose the appropriate settings when prompted.
**c. Set Up Environment Variables via CLI (Optional):**
You can also set environment variables via the Vercel CLI:
```bash
vercel env add MONGODB_URI production
vercel env add SECRET_KEY production
# Add others as needed
```
---
### **7. Testing Your Deployment**
After deployment, Vercel will provide you with a URL where your API is accessible. Test your API endpoints to ensure everything is working as expected.
---
### **Important Considerations**
**a. Cold Starts and Connection Handling:**
Vercel's serverless functions are stateless and might lead to performance issues due to cold starts and database connection overhead.
- Each serverless function invocation might create a new database connection, which isn't efficient for MongoDB.
- Implement connection pooling or use a managed database service that handles connections efficiently with serverless environments.
**b. Execution Time Limits:**
Vercel's serverless functions have execution time limits:
- **Free Plan**: 10 seconds maximum execution time.
- **Pro Plan**: Increases the limit but still has constraints.
Ensure that your API endpoints execute quickly and efficiently within these limits.
**c. Suitable Use Cases:**
Vercel is optimized for frontend applications and stateless backend functions. For a full-fledged backend API with persistent connections and longer execution times, consider other hosting options like:
- **Heroku**
- **DigitalOcean Apps**
- **AWS Elastic Beanstalk**
- **Google Cloud Run**
- **Render**
---
### **Alternative Recommendation**
Given the nature of your backend API (stateful connections, authentication, database interactions), you might experience limitations on Vercel.
**I recommend deploying your FastAPI application to a hosting service that's more suited for backend applications**, such as:
- **Heroku**: Offers a free tier, easy deployment, and is beginner-friendly.
- **DigitalOcean Apps**: Managed service with easy scaling.
- **Render**: Simple deployments with free tiers for web services.
- **AWS Elastic Beanstalk**: For scalable applications with more control over resources.
These platforms allow for persistent server processes and are better suited for applications that require steady database connections and longer execution times.
---
### **Conclusion**
While it's possible to deploy your FastAPI backend to Vercel with some adjustments, you may run into limitations that affect performance and scalability. Consider your application's needs and choose a hosting platform that aligns with those requirements.
---
**Note:** If you still prefer to proceed with Vercel, ensure your database connections are efficiently managed, perhaps by using connection pooling libraries designed for serverless environments (like `motor` for async MongoDB connections in FastAPI). Additionally, test your application thoroughly to ensure it works within Vercel's constraints.