--- license: apache-2.0 title: Assignment sdk: docker emoji: 🐨 colorFrom: purple colorTo: indigo --- # Place Review REST API A production-ready REST API for a mobile app that allows users to review places (shops, doctors, restaurants, etc.), built with Django and Django REST Framework. ## Features - **User Registration**: Phone-based user registration (one user per phone number) - **Authentication**: Token-based authentication for all endpoints - **Reviews**: Users can add reviews with 1-5 ratings for any place - **Smart Search**: Search places by name (exact match prioritized) and/or minimum rating - **Place Details**: View place information with all reviews, current user's review shown first - **Automatic Place Creation**: Places are automatically created when adding a review if they don't exist ## Technology Stack - **Framework**: Django 5.0 with Django REST Framework - **Database**: SQLite (can be easily switched to PostgreSQL or MySQL) - **Authentication**: Token-based authentication - **Data Generation**: Faker for realistic sample data ## Installation ### Prerequisites - Python 3.8 or higher - pip (Python package manager) ### Setup Steps 1. **Clone or extract the project** ```bash cd "d:\SDE intern Assignment" ``` 2. **Create a virtual environment (recommended)** ```bash python -m venv venv # On Windows venv\Scripts\activate # On macOS/Linux source venv/bin/activate ``` 3. **Install dependencies** ```bash pip install -r requirements.txt ``` 4. **Run database migrations** ```bash python manage.py makemigrations python manage.py migrate ``` 5. **Populate the database with sample data** ```bash python manage.py populate_data ``` This will create: - 50 users with realistic names and phone numbers - 100 places (restaurants, cafes, shops, doctors, gyms, salons) - 300+ reviews with varied ratings **Note**: The command will display sample user credentials that you can use for testing. 6. **Create a superuser (optional, for admin access)** ```bash python manage.py createsuperuser ``` 7. **Run the development server** ```bash python manage.py runserver ``` The API will be available at `http://127.0.0.1:8000/` ## API Endpoints All endpoints (except registration and login) require authentication via token header: ``` Authorization: Token YOUR_AUTH_TOKEN ``` ### 1. User Registration **Endpoint**: `POST /api/register/` **Description**: Register a new user with name and phone number. **Request Body**: ```json { "name": "John Doe", "phone": "1234567890" } ``` **Response** (201 Created): ```json { "user": { "id": 1, "name": "John Doe", "phone": "1234567890" }, "token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" } ``` **Error** (400 Bad Request): ```json { "phone": ["user with this phone already exists."] } ``` ### 2. User Login **Endpoint**: `POST /api/login/` **Description**: Login with phone number to receive authentication token. **Request Body**: ```json { "phone": "1234567890" } ``` **Response** (200 OK): ```json { "user": { "id": 1, "name": "John Doe", "phone": "1234567890" }, "token": "9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" } ``` **Error** (404 Not Found): ```json { "error": "User with this phone number does not exist" } ``` ### 3. Add Review **Endpoint**: `POST /api/reviews/add/` **Description**: Add a review for a place. If the place doesn't exist, it will be created automatically. **Headers**: ``` Authorization: Token YOUR_TOKEN ``` **Request Body**: ```json { "place_name": "Joe's Pizza", "place_address": "123 Main St, New York, NY", "rating": 5, "review_text": "Best pizza in town! The crust is perfect." } ``` **Response** (201 Created): ```json { "message": "Review added successfully", "review": { "id": 1, "user_name": "John Doe", "rating": 5, "text": "Best pizza in town! The crust is perfect.", "created_at": "2024-01-01T12:00:00Z" } } ``` **Notes**: - If a place with the exact name and address exists, the review will be added to it - If the place doesn't exist, it will be created automatically - If the user has already reviewed this place, the review will be updated ### 4. Search Places **Endpoint**: `GET /api/places/search/` **Description**: Search for places by name and/or minimum rating. **Headers**: ``` Authorization: Token YOUR_TOKEN ``` **Query Parameters**: - `name` (optional): Search by place name (case-insensitive, exact matches shown first) - `min_rating` (optional): Filter by minimum average rating **Examples**: Search by name only: ``` GET /api/places/search/?name=pizza ``` Search by minimum rating only: ``` GET /api/places/search/?min_rating=4 ``` Search by both: ``` GET /api/places/search/?name=pizza&min_rating=4 ``` **Response** (200 OK): ```json [ { "id": 1, "name": "Joe's Pizza", "address": "123 Main St, New York, NY", "average_rating": 4.5 }, { "id": 2, "name": "Pizza Paradise", "address": "456 Oak Ave, Brooklyn, NY", "average_rating": 4.2 } ] ``` **Search Logic**: - Exact matches are shown first, followed by partial matches - Case-insensitive search - Results are filtered by minimum rating if specified ### 5. Place Details **Endpoint**: `GET /api/places/{place_id}/` **Description**: Get detailed information about a place, including all reviews. The current user's review appears first, followed by all other reviews sorted by newest first. **Headers**: ``` Authorization: Token YOUR_TOKEN ``` **Example**: ``` GET /api/places/1/ ``` **Response** (200 OK): ```json { "id": 1, "name": "Joe's Pizza", "address": "123 Main St, New York, NY", "average_rating": 4.5, "reviews": [ { "id": 5, "user_name": "John Doe", "rating": 5, "text": "Best pizza in town!", "created_at": "2024-01-01T12:00:00Z" }, { "id": 3, "user_name": "Jane Smith", "rating": 4, "text": "Great pizza, slightly pricey", "created_at": "2024-01-02T14:00:00Z" }, { "id": 1, "user_name": "Bob Johnson", "rating": 5, "text": "Amazing crust!", "created_at": "2023-12-30T10:00:00Z" } ] } ``` **Error** (404 Not Found): ```json { "error": "Place not found" } ``` ## Testing the API ### Using curl 1. **Register a user**: ```bash curl -X POST http://127.0.0.1:8000/api/register/ \ -H "Content-Type: application/json" \ -d "{\"name\": \"Test User\", \"phone\": \"9999999999\"}" ``` 2. **Login** (use a phone from the populate_data output): ```bash curl -X POST http://127.0.0.1:8000/api/login/ \ -H "Content-Type: application/json" \ -d "{\"phone\": \"1234567890\"}" ``` 3. **Add a review** (replace YOUR_TOKEN): ```bash curl -X POST http://127.0.0.1:8000/api/reviews/add/ \ -H "Content-Type: application/json" \ -H "Authorization: Token YOUR_TOKEN" \ -d "{\"place_name\": \"New Place\", \"place_address\": \"123 Test St\", \"rating\": 5, \"review_text\": \"Excellent!\"}" ``` 4. **Search places**: ```bash curl -X GET "http://127.0.0.1:8000/api/places/search/?name=pizza&min_rating=4" \ -H "Authorization: Token YOUR_TOKEN" ``` 5. **Get place details**: ```bash curl -X GET http://127.0.0.1:8000/api/places/1/ \ -H "Authorization: Token YOUR_TOKEN" ``` ### Using Postman or Similar Tools 1. Import the API endpoints 2. Set up an environment variable for the auth token 3. Test each endpoint according to the examples above ## Database Schema ### User Model - `id`: Primary key (auto-generated) - `phone`: Unique phone number (used for authentication) - `name`: User's name - `date_joined`: Timestamp of registration ### Place Model - `id`: Primary key (auto-generated) - `name`: Place name - `address`: Place address - `created_at`: Timestamp - **Unique constraint**: (name, address) ### Review Model - `id`: Primary key (auto-generated) - `user_id`: Foreign key to User - `place_id`: Foreign key to Place - `rating`: Integer (1-5) - `text`: Review text - `created_at`: Timestamp - **Unique constraint**: (user, place) - one review per user per place ## Production Deployment Notes For production deployment, you should: 1. **Change the SECRET_KEY** in `settings.py` to a secure random value 2. **Set DEBUG = False** in `settings.py` 3. **Configure ALLOWED_HOSTS** with your domain 4. **Use PostgreSQL or MySQL** instead of SQLite: ```python DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': 'your_db_name', 'USER': 'your_db_user', 'PASSWORD': 'your_db_password', 'HOST': 'localhost', 'PORT': '5432', } } ``` 5. **Set up static files** serving 6. **Use a production WSGI server** like Gunicorn or uWSGI 7. **Set up HTTPS** with SSL certificates ## Project Structure ``` SDE intern Assignment/ ├── manage.py # Django management script ├── requirements.txt # Python dependencies ├── db.sqlite3 # SQLite database (auto-generated) ├── place_review_api/ # Main project directory │ ├── __init__.py │ ├── settings.py # Django settings │ ├── urls.py # Root URL configuration │ ├── asgi.py # ASGI configuration │ └── wsgi.py # WSGI configuration └── reviews/ # Reviews app ├── __init__.py ├── admin.py # Admin interface configuration ├── apps.py # App configuration ├── models.py # Database models ├── serializers.py # DRF serializers ├── views.py # API views ├── urls.py # App URL routing ├── management/ # Management commands │ ├── __init__.py │ └── commands/ │ ├── __init__.py │ └── populate_data.py # Data population script └── migrations/ # Database migrations (auto-generated) └── __init__.py ``` ## Design Decisions and Assumptions 1. **Phone-based Authentication**: Users register and login with phone numbers. No password is required in this basic version, but it can be easily extended. 2. **SQLite Database**: Used for portability and ease of submission. The code works with any relational database (PostgreSQL, MySQL, etc.) by simply changing the database configuration. 3. **Atomic Place Creation**: When adding a review, if a place with the same name and address doesn't exist, it's created atomically using `get_or_create()`. 4. **Review Updates**: If a user reviews the same place twice, their review is updated rather than creating a duplicate. 5. **Search Priority**: Exact name matches are shown before partial matches to improve relevance. 6. **Review Sorting**: On the place details page, the current user's review always appears first (if they've reviewed it), followed by all other reviews sorted by newest first. 7. **Rating Distribution**: The sample data generator creates reviews with ratings skewed toward positive (4-5 stars) to simulate realistic rating distributions. 8. **Token Authentication**: Simple and effective for mobile apps. Tokens never expire in this version but can be configured to expire. ## Code Quality Highlights - **Type Safety**: Proper use of Django's field validators and constraints - **Database Integrity**: Unique constraints and foreign key relationships - **Atomic Operations**: Uses transactions for data population - **Error Handling**: Comprehensive error responses with appropriate HTTP status codes - **Code Documentation**: Docstrings for all views and complex methods - **DRY Principle**: Reusable serializers and efficient database queries - **Security**: Token authentication required for all sensitive endpoints - **Performance**: Database indexes on commonly queried fields ## License This project is submitted as part of a technical assessment.