A simple REST service for validating bank card numbers.
- Go 1.25, standard library
net/http - Docker / docker-compose
cp .env.example .env
make runStop the service:
make stopRun tests:
make test| Variable | Description | Required |
|---|---|---|
SERVER_PORT |
Port the HTTP server listens on | yes, no default |
Health-check endpoint for Docker/orchestration.
Response 200
OK
Request body
{
"card_number": "4111111111111111",
"exp_month": 12,
"exp_year": 2028
}Response 200 — card is valid
{
"valid": true
}Response 422 — card is invalid
{
"valid": false,
"error": {
"code": "004",
"message": "Card number is invalid"
}
}Response 400 — malformed request body
{
"error": "Invalid request format"
}Returned when the request body fails to parse or exp_month/exp_year are not numbers.
| Code | Message | Description |
|---|---|---|
| 001 | Card number is empty | card number was not provided |
| 002 | Length of card number is invalid | number length is outside the 13–19 range |
| 003 | Card must contain only numbers | number contains non-digit characters |
| 004 | Card number is invalid | number failed the Luhn checksum |
| 005 | Month number must be between 1 and 12 | invalid month |
| 006 | Year of expiration is not valid | year is outside the allowed range |
| 007 | The card has expired | the card's expiration date has passed |
A standard set of checks for bank card numbers was implemented:
- Format — the number must contain only digits, with a length between 13 and 19 characters (covers the major card networks).
- Luhn algorithm — checksum validation of the card number.
- Expiration — month must be 1–12, year must fall within a reasonable range (2000 to current year + 30), and the card must not already be expired.
The service logs structured events via log/slog:
- every card validation attempt — with a masked card number (
****...1234) and the result (valid: true/false, pluserror_codewhen the card is invalid); - malformed request bodies;
- system events (server start/shutdown, response serialization failures).
The full card number is never written to the logs.
cmd/validator — entry point, server startup and graceful shutdown
internal/config — configuration loading from environment variables
internal/transport — HTTP server, routing
internal/handlers — HTTP layer: request parsing, service invocation, response building
internal/service — card validation business logic
Layers are separated by responsibility: handlers depends on service through the CardService interface, which allows the handler to be tested in isolation via a mock, without spinning up the real business logic.