File upload endpoint
Introduction#
POST /upload accepts CSV, TXT, or Excel, extracts contacts, then deletes the temp file. Used when the desktop app hands a file to the Flask backend.
Project structure#
The /upload endpoint is implemented in the Python backend service. The relevant files are:
- python-backend/app.py: Flask application with the /upload route and supporting functions
- python-backend/README.md: API documentation including endpoint overview
- python-backend/requirements.txt: Python dependencies including Flask and pandas
graph TB subgraph "Python Backend" A["Flask App<br/>python-backend/app.py"] B["Requirements<br/>python-backend/requirements.txt"] C["Docs<br/>python-backend/README.md"] end A --> B A -. references .-> C
Core components#
- Endpoint: POST /upload
- Request format: multipart/form-data
- Supported file types: txt, csv, xlsx, xls
- File size limit: 16 MB
- Security measures:
- Filename sanitization using secure_filename
- Allowed file extension validation
- Temporary file storage in uploads directory
- Cleanup of uploaded files after processing or failure
- Response schema:
- success: boolean
- contacts: array of contact objects
- count: integer
- message: string
Architecture overview#
The /upload endpoint receives a multipart/form-data request, validates the file, saves it temporarily, extracts contacts based on file type, removes the temporary file, and returns a structured response.
sequenceDiagram
participant Client as "Client"
participant Flask as "Flask App (/upload)"
participant FS as "Filesystem"
participant Parser as "Extractor Functions"
Client->>Flask : "POST /upload"<br/>multipart/form-data
Flask->>Flask : "Validate presence of 'file'"
Flask->>Flask : "Validate filename and extension"
Flask->>FS : "Save file to uploads/"
Flask->>Parser : "Detect type and parse"
Parser-->>Flask : "contacts[]"
Flask->>FS : "Remove temp file"
Flask-->>Client : "{success, contacts, count, message}"Detailed component analysis#
Endpoint definition and behavior#
- Route: POST /upload
- Purpose: Accept a file and return extracted contacts
- Request body: multipart/form-data with a field named file
- Response: JSON object with success flag, contacts array, count, and message
Validation and processing steps:
- Check for presence of file field
- Check that filename is not empty
- Validate allowed extensions
- Sanitize filename and save to uploads directory
- Detect file type and dispatch to appropriate extractor
- Remove uploaded file
- Return success response with extracted contacts
Error handling:
- Missing file field: 400 with error message
- Empty filename: 400 with error message
- Unsupported file type: 400 with error message
- Processing exceptions: 500 with error message; temporary file removed
Cleanup:
- Uploaded file is deleted after processing or upon error
Supported file types and parsing logic#
Supported formats:
- CSV (.csv)
- Text (.txt)
- Excel (.xlsx, .xls)
Parsing behavior:
- CSV: Attempts pandas read_csv; falls back to manual CSV reader if needed
- TXT: Parses lines and attempts to detect phone numbers and optional names
- Excel: Uses pandas read_excel and column header detection for phone/name columns
Phone number cleaning:
- Removes non-digit characters except plus sign
- Strips separators and spaces
- Normalizes leading zeros and adds plus for international format when applicable
- Validates digit length (between 7 and 15 digits)
Request and response specifications#
- HTTP Method: POST
- Path: /upload
- Content-Type: multipart/form-data
- Form Field Name: file
- Example curl command:
- curl -X POST -F “file=@/path/to/contacts.csv” http://localhost:5000/upload
- Example Python requests:
- requests.post(“http://localhost:5000/upload”, files={“file”: open(“contacts.xlsx”, “rb”)})
Response schema:
- success: boolean
- contacts: array of objects with keys number and optional name
- count: integer
- message: string
Example successful response:
- { “success”: true, “contacts”: [{“number”: “+1234567890”, “name”: “John Doe”}, …], “count”: 42, “message”: “Successfully extracted 42 contacts” }
Error responses:
- { “error”: “No file provided” }
- { “error”: “No file selected” }
- { “error”: “Invalid file type. Allowed types: txt, csv, xlsx, xls” }
- { “error”: "Failed to process file: " }
Security measures#
- Filename sanitization: secure_filename is applied to prevent directory traversal
- Extension whitelist: only txt, csv, xlsx, xls are accepted
- File size limit: MAX_CONTENT_LENGTH set to 16 MB
- Temporary file handling: uploaded file is removed after processing or error
Data flow diagram for contact extraction#
flowchart TD
Start(["Upload Request"]) --> CheckFile["Check 'file' field present"]
CheckFile --> FilePresent{"File present?"}
FilePresent --> |No| ErrMissing["400: No file provided"]
FilePresent --> |Yes| CheckName["Check filename not empty"]
CheckName --> NameEmpty{"Filename empty?"}
NameEmpty --> |Yes| ErrEmpty["400: No file selected"]
NameEmpty --> |No| CheckExt["Check allowed extension"]
CheckExt --> ExtAllowed{"Allowed type?"}
ExtAllowed --> |No| ErrType["400: Invalid file type"]
ExtAllowed --> |Yes| Sanitize["Sanitize filename"]
Sanitize --> Save["Save to uploads/<filename>"]
Save --> Parse["Parse based on extension"]
Parse --> Cleanup["Delete temp file"]
Cleanup --> Success["Return success response"]
ErrMissing --> End(["End"])
ErrEmpty --> End
ErrType --> End
Success --> EndDependency analysis#
The /upload endpoint depends on:
- Flask for routing and request handling
- pandas and openpyxl/xlrd for Excel/CSV parsing
- werkzeug.secure_filename for filename sanitization
graph TB Flask["Flask App<br/>python-backend/app.py"] Pandas["pandas"] Openpyxl["openpyxl"] Xlrd["xlrd"] Werkzeug["werkzeug.secure_filename"] Flask --> Pandas Flask --> Openpyxl Flask --> Xlrd Flask --> Werkzeug
Performance considerations#
- File size limit of 16 MB helps control memory usage and processing time
- CSV parsing uses pandas for speed; falls back to manual parsing for robustness
- Excel parsing uses pandas and openpyxl/xlrd
- Contact extraction avoids heavy operations by focusing on phone number normalization and column detection
Troubleshooting guide#
Common issues and resolutions:
- Invalid file type error: Ensure the file has extension txt, csv, xlsx, or xls
- Empty filename error: Select a file before uploading
- Processing failures: Check file encoding and structure; ensure phone numbers are readable
- Cleanup failures: Temporary files are removed automatically; if not, verify filesystem permissions
Conclusion#
Always check success in the JSON. Temp files are removed after processing, so failed uploads will not leave orphans unless the process dies mid-write.
Appendices#
Practical examples#
Using curl to upload a CSV file:
curl -X POST -F “file=@/path/to/contacts.csv” http://localhost:5000/upload
Using Python requests to upload an Excel file:
import requests
files = {“file”: open(“contacts.xlsx”, “rb”)}
response = requests.post(“http://localhost:5000/upload”, files=files)
print(response.json())
Using Python requests to upload a text file:
import requests
files = {“file”: open(“contacts.txt”, “rb”)}
response = requests.post(“http://localhost:5000/upload”, files=files)
print(response.json())