This project implements a production-grade backend API and a clean web UI for validating credit card numbers using the Luhn algorithm. Built with Node.js, TypeScript, and NestJS.
- Full-Stack: Built-in interactive demo UI.
- Luhn Algorithm: Robust checksum validation.
- Intelligent Response: Detects card types (Visa, Mastercard) and provide human-friendly messages.
- Production Ready: Fully Dockerized and works on Vercel, Railway, or Render.
- Framework: NestJS (Node.js)
- Frontend: Vanilla HTML/CSS/JS (served via
@nestjs/serve-static) - Validation:
class-validator - Testing: Jest (Unit & E2E)
-
Install dependencies:
npm install
-
Run the application locally:
npm run start:dev
- Web UI: http://localhost:3001
- API Base: http://localhost:3001/hello
-
Run tests:
npm test
Validates a given credit card number.
Request Body:
{
"cardNumber": "4111 1111 1111 1111"
}Response:
{
"isValid": true,
"cardType": "Visa",
"message": "This looks like a valid Visa card."
}The project includes a multi-stage Dockerfile optimized for production.
docker build -t card-validator .
docker run -p 3001:3001 card-validatorConfiguration is provided via vercel.json. Simply run vercel --prod.
Example Request (using curl):
curl -X POST http://localhost:3000/validate-card \
-H "Content-Type: application/json" \
-d Example Valid Response:
{
"valid": true,
"type": "Visa"
}Example Invalid Response (Luhn algorithm fails):
{
"valid": false,
"type": "Unknown"
}Example Error Response (Invalid input):
{
"statusCode": 400,
"message": [
"Card number must be between 12 and 19 characters"
],
"error": "Bad Request"
}The Luhn algorithm (also known as the Mod 10 algorithm) is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers, and Canadian Social Insurance Numbers. It is not intended to be a cryptographically secure hash function; it was designed to protect against accidental errors, not malicious attacks.
The algorithm works as follows:
- Starting from the rightmost digit, and moving left, double the value of every second digit.
- If the result of this doubling is greater than 9 (e.g., 7 doubled is 14), subtract 9 from the result (e.g., 14 becomes 14 - 9 = 5).
- Sum all the digits (including those that were not doubled and those that had 9 subtracted).
- If the total sum is a multiple of 10 (i.e.,
sum % 10 === 0), then the number is considered valid.
- NestJS Framework: Chosen for its robust, modular structure, and excellent TypeScript support, which aligns with the requirement for a production-grade backend.
- Clean Modular Structure: The project adheres to the standard NestJS architecture, separating concerns into
Controller(HTTP layer),Service(business logic), andDTO(data transfer objects for validation). This promotes maintainability and scalability. class-validatorfor DTO Validation: Provides a declarative and powerful way to validate incoming request bodies, ensuring that input adheres to specified constraints (string, digits only, length between 12-19 characters). This is integrated globally using NestJS'sValidationPipe.- Global Validation Pipe: Configured in
main.tsto automatically validate all incoming requests against their respective DTOs.whitelist: trueandforbidNonWhitelisted: trueare used to prevent unexpected fields in the request body, enhancing security and data integrity. - Luhn Algorithm Implementation: Encapsulated within the
AppServiceto keep business logic separate from the HTTP layer. The implementation is straightforward, following the algorithm's steps precisely. - Card Type Detection: An optional feature implemented cleanly within the
AppServiceto identify Visa and Mastercard based on their starting digits. This adds value without overengineering. - Error Handling: Invalid input is handled gracefully by the global
ValidationPipe, returning a400 Bad Requestwith clear error messages. Internal errors would be handled by NestJS's default exception filters or custom ones if needed for more complex scenarios. - Unit Testing with Jest: Comprehensive unit tests are provided for both the
AppService(Luhn algorithm and card type detection) andAppController(endpoint integration), ensuring the core logic functions as expected. tsconfig.jsonstrict: true: Enforced to leverage TypeScript's full type-checking capabilities, leading to more robust and error-free code.
This project follows a conventional commit structure, simulating the following:
feat: initial project setupfeat: implement validation endpointfeat: add Luhn algorithm logictest: add unit testsdocs: add README