Objective: Build a web service that implements the specified API for processing receipts.
This API was built to fulfill a code challenge for Fetch Rewards. For detailed instructions and rules, refer to the fetch-rewards/receipt-processor-challenge repository.
API Overview:
Swagger UI is available at http://localhost:3000/docs with detailed API information.
- Endpoint:
/receipts/process
(POST)- Payload: JSON receipt (retailer, purchaseDate, purchaseTime, items, total)
- Response: JSON with a generated receipt ID.
- Endpoint:
/receipts/{id}/points
(GET)- Response: JSON with the number of points awarded for the receipt.
- Endpoint:
/openapi.json
(GET)- Response: JSON that represents the openapi spec used to populate the swagger ui.
- Endpoint:
/
(GET)- Response: JSON with a string to indicate the app is running and healthy.
Technology Used:
- TypeScript: Although the challenge preferred Go, I chose TypeScript for familiarity and confidence in delivering the solution. I plan to build this in Go later. (11/30/2024 edit: done)
- Fastify: I wanted a lightweight, performant framework to use, since I am aware Go is generally more performant than Node.js. Although I have never used it before, I found it intuitive and easy to get something up and running quickly.
- Docker: One of the requirements of this challenge was to use docker, so the app is available in a docker container via
npm run docker:run
. - Jest: I used jest for unit tests.
- Swagger: I used Swagger to generate documentation UI based on an openAPI spec generated by
@fastify/swagger
. - AutoCannon: Used for benchmarking performance
- In-memory Storage: There is no database, data is stored in a Map and will be lost if the server is restarted.
Follow these steps to set up, build, and run this application:
Make sure the following are installed on your system:
- Node.js (v18 or higher)
- npm (comes with Node.js)
- Docker (if you intend to run the application in a container)
git clone [email protected]:derekvmcintire/receipt-processor.git
cd receipt-processor
Run the following command to install all necessary dependencies:
npm install
You have two options to run the application: development mode or production mode.
Run the application in development mode with TypeScript support:
npm run dev
- The server will start at http://localhost:3000.
- Swagger documentation will be available at http://localhost:3000/docs.
- Changes to the source code will automatically reload the server.
- Build the application:
This will compile the TypeScript code into JavaScript files in the
npx tsc
dist
folder. - Start the application:
npm start
- The server will start at http://localhost:3000.
- Swagger documentation will be available at http://localhost:3000/docs.
You must have Docker installed to run this API in a Docker container. If you are unfamiliar with, or need to install it, you can reference this Documentation
npm run docker:build
npm run docker:run
- The server will be accessible at http://localhost:3000.
- Swagger documentation will be available at http://localhost:3000/docs.
- This Docker Cheatsheet may be useful if you are not familiar with docker.
To run all tests using Jest:
npm test
npm run pretty:check
npm run pretty
npm run lint
- Health Check: Access http://localhost:3000/ to verify the application is running.
- API Documentation: Swagger UI is available at http://localhost:3000/docs with detailed API information.
- OpenAPI Spec: Retrieve the OpenAPI JSON spec at http://localhost:3000/openapi.json.
- If you encounter errors during development, check the logs output in the terminal.
- Ensure the required ports (e.g.,
3000
) are not in use by other applications. - If Docker fails to run, verify your Docker installation and ensure it is running.
- Run
docker ps
to see containers that are running anddocker stop <id>
to stop a container thendocker rm <id>
to remove it. - If it seems like things aren't quite right, try re-building docker with --no-cache, sometimes the image can get stale.
npm run docker:build:no-cache
Command | Description |
---|---|
npm run dev |
Runs the application in development mode with live reloading. |
npm start |
Runs the application in production mode. |
npm test |
Runs all Jest tests. |
npm run pretty |
Formats code using Prettier. |
npm run lint |
Lints the code using ESLint. |
npm run docker:build |
Builds a Docker image for the application. |
npm run docker:build:no-cache |
Builds a Docker image without cache |
npm run docker:run |
Runs the application inside a Docker container on port 3000 . |
npm run autocannon |
Performs a load test. Requires a URL to be provided. |
npm run autocannon:process |
Performs a load test on receipt/process endpoint. |
This project follows several architectural and technical decisions aimed at ensuring performance, maintainability, and scalability. Some of the key decisions include:
- Language: TypeScript (chosen for familiarity and static typing)
- API Framework: Fastify (chosen for performance, TypeScript support, and built-in schema validation)
- Architecture: Clean Architecture (enforces separation of concerns, keeping the application layers loosely coupled and easily testable.)
For a detailed breakdown of all technical decisions, see the TECHNICAL_DECISIONS.md file.
Performance benchmarks were set by using AutoCannon
and show high throughput and low latency, which is not surprising considering the lack of a real database.
- API Performance:
receipts/points
endpoint: 15,744 requests/secondreceipts/process
endpoint: 13,964 requests/second
For more details, see PERFORMANCE.md.
The test suite utilizes Jest for unit tests, with near-complete coverage of core business logic:
PointsCalculator
classReceiptEntity
classReceiptService
class
But also includes interface and infrastructure classes:
- controllers
InMemoryReceiptRepository
class
Test Suites: 6
Total Tests: 26
Code Coverage:
- Overall statement coverage: 98.31%
- Branch coverage: 92.1%
- Function coverage: 96.66%
- Line coverage: 98.3%
Test coverage is categorized into key directories, showing how well each area of the code is tested. High coverage in Entities, Services, and Utilities demonstrates that the core logic and data access layers are thoroughly tested.
Directory | % Stmts | % Branch | % Funcs | % Lines |
---|---|---|---|---|
All files | 98.31% | 92.1% | 96.66% | 98.3% |
Entities | 100% | 100% | 100% | 100% |
Services | 100% | 100% | 100% | 100% |
Utils | 91.66% | 70% | 88.88% | 91.66% |
Repositories | 100% | 100% | 100% | 100% |
Controllers | 100% | 100% | 100% | 100% |
-
Logging & Monitoring: Integrate logging (
pino
Fastify's built-in logger is one option) and set up centralized logging. Implement performance monitoring. -
CI/CD Workflow: Set up a GitHub Actions workflow for automated testing, linting, building Docker images, and deploying to staging/production environments.
-
Security Enhancements:
- CORS: Fastify offers
@fastify/cors
to restrict API access to trusted domains. - HTTP Headers: Fastify offers
@fastify/helmet
to protect http headers. - Rate Limiting: Fastify offers
@fastify/rate-limit
to prevent abuse and DoS attacks. - JWT Authentication: Fastify offers
@fastify/jwt
for user authentication.
- CORS: Fastify offers