A NestJS backend service for managing car data, processing high-volume car data ingestion, and providing statistics endpoints.
- Framework: NestJS
- Language: TypeScript
- Database: PostgreSQL with TypeORM
- Authentication: JWT (Passport)
- Validation: class-validator, class-transformer
- Documentation: Swagger/OpenAPI
- Testing: Jest
- Node.js (v18 or higher)
- PostgreSQL (v12 or higher)
- Redis
- pnpm (or npm/yarn/bun.js)
pnpm installInstall and setup PostgreSQL and Redis. Create a PostgreSQL database and a user.
Create a .env file in the root directory.
You can check .env.example file for more details.
For default values you can check ./src/config folder.
# Database Configuration
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_NAME=car_statistics
# JWT Configuration
JWT_SECRET=your-secret-key-change-in-production
JWT_EXPIRES_IN=1d
# Redis Configuration
REDIS_HOST=your-redis-host
REDIS_PORT=your-redis-port
# Application Configuration
PORT=3000
NODE_ENV=development
# External API Configuration
EXTERNAL_APIARY_URL=<your-external-apiary-url>
INGESTION_API_KEY=<your-ingestion-api-key>
# Application port
PORT=<your application port>The application uses TypeORM's synchronize option in development mode, which automatically creates/updates database tables.
You can create a user using the seed script:
# Create a user with default credentials (admin/admin123)
pnpm run seed:user
# Or specify custom username and password
pnpm run seed:user myusername mypasswordAlternatively, you can create a user directly in the database (password must be hashed using bcrypt).
# watch mode (recommended for development)
pnpm run start:dev
# standard start
pnpm run startThe application will be available at http://localhost:3000
Swagger documentation will be available at http://localhost:3000/api/docs
POST /auth/login- Login with username and password, returns JWT token
POST /cars- Create a single carPOST /cars/bulk- Bulk create cars (requires x-api-key header)GET /cars- List all carsGET /cars/:id- Get car by IDPATCH /cars/:id- Update carDELETE /cars/:id- Delete car
GET /cars/stats/average-price-per-model- Average price per model (grouped by make + model)GET /cars/stats/make-percentage- Percentage distribution per makeGET /cars/stats/model-percentage- Percentage distribution per model
API testing You can use Postman collection in the root folder for testing the API.
All /cars routes are protected with JWT authentication (except for /create/bulk). To access them:
- Login using
POST /auth/loginwith username and password - Copy the
access_tokenfrom the response - Include it in subsequent requests as:
Authorization: Bearer <token>
Example using curl:
# Login
curl -X POST http://localhost:3000/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"yourusername","password":"yourpassword"}'
# Use the token
curl -X GET http://localhost:3000/cars \
-H "Authorization: Bearer YOUR_TOKEN_HERE"The application provides a bulk ingestion endpoint at POST /cars/bulk that accepts an array of car objects. This endpoint is designed to handle high-volume data.
Example request:
curl -X POST http://localhost:3000/cars/bulk \
-H "Content-Type: application/json" \
-H "x-api-key: your-api-key" \
-d '[
{
"normalizedMake": "toyota",
"normalizedModel": "corolla",
"year": 2020,
"price": 25000,
"location": "New York, NY"
},
{
"normalizedMake": "bmw",
"normalizedModel": "3-series",
"year": 2021,
"price": 35000,
"location": "Los Angeles, CA"
}
]'To integrate with the AMA-task-data-seeder project:
- Fork/clone the data-seeder repository
- Configure it to send POST requests to
http://localhost:3000/cars/bulk - Include the INGESTION_API_KEY in the "x-api-key" header
- Send car data in batches for optimal performance
# run unit tests
pnpm run test- Absolute Imports: All imports use the
@/prefix (e.g.,@/modules/auth/auth.service) - Type Imports: Type-only imports use
import typeand are placed at the end of import statements - Module Organization: Features are organized in the
modules/directory - Guards & Strategies: Authentication guards and strategies are in separate folders
Once the application is running, visit http://localhost:3000/api/docs to access the interactive Swagger documentation. You can:
- View all available endpoints
- See request/response schemas
- Test endpoints directly from the browser
- Authenticate using the "Authorize" button
All incoming data is validated using class-validator and class-transformer. Invalid requests will return detailed error messages indicating what validation failed.
Example validation errors:
{
"statusCode": 400,
"message": [
"normalizedMake should not be empty",
"year must be an integer number",
"price must be a positive number"
],
"error": "Bad Request"
}- The bulk ingestion endpoint uses batch inserts for optimal performance
- Database indexes are created on
(normalizedMake, normalizedModel)for faster statistics queries
- Verify PostgreSQL is running:
pg_isready - Check database credentials in
.env - Ensure the database exists:
psql -l | grep car_statistics
- Verify JWT_SECRET is set in
.env - Check token expiration time
- Ensure user exists in the database
- Change
PORTin.envfile - Or kill the process using the port:
lsof -ti:3000 | xargs kill