REST API in Go for fetching exchange rates from Banco Central de Venezuela (BCV) for USD and EUR.
This API was born out of necessity. The Banco Central de Venezuela (BCV) does not provide an official public API for accessing exchange rates, which created a challenge for my SaaS application. To solve this problem, I developed this custom API that scrapes the BCV website to provide reliable and up-to-date exchange rate data.
The project is built with Go (Golang), chosen for its exceptional performance and efficiency. As I continue to explore and learn this powerful language, this project represents one of my initial steps into the Go ecosystem. It's a testament to my growing knowledge and understanding of Go's concurrency model, HTTP handling, and web scraping capabilities.
- π§Ή Clean and optimized code
- ποΈ Modular and scalable architecture
- π‘οΈ Robust error handling
- β‘ Concurrent rate fetching for improved performance
- π― Intelligent scraping with multiple extraction strategies
- βοΈ Environment variable configuration
- π SSL certificate handling for BCV website
- π¦ Rate limiting (60 requests per minute per IP)
- πΎ In-memory caching with TTL to reduce BCV website requests
- Go 1.21 or higher
- Internet connection
-
Clone or download the project
-
Install dependencies:
make deps
# Or manually:
go mod download
go mod tidy- Build the project:
make build
# Or manually:
go build -o bin/bcv-api ./cmd/servermake run
# Or manually:
go run ./cmd/server/main.go./bin/bcv-apiPORT=3000 make run
# Or
PORT=3000 ./bin/bcv-api# Set cache TTL to 10 minutes and rate limit to 100 requests/minute
CACHE_TTL=10m RATE_LIMIT_PER_MIN=100 ./bin/bcv-api
# Custom port, cache, and timeout
PORT=3000 CACHE_TTL=5m HTTP_TIMEOUT=45s ./bin/bcv-apiGET http://localhost:8080/api/rates/dollarResponse:
{
"success": true,
"data": {
"currency": "Dollar",
"rate": "36.50",
"date": "2024-01-15T10:30:00Z"
}
}GET http://localhost:8080/api/rates/euroResponse:
{
"success": true,
"data": {
"currency": "Euro",
"rate": "40.25",
"date": "2024-01-15T10:30:00Z"
}
}GET http://localhost:8080/api/rates/allResponse:
{
"success": true,
"data": {
"dollar": {
"currency": "Dollar",
"rate": "36.50",
"date": "2024-01-15T10:30:00Z"
},
"euro": {
"currency": "Euro",
"rate": "40.25",
"date": "2024-01-15T10:30:00Z"
}
}
}bcv-api/
βββ cmd/
β βββ server/
β βββ main.go # Application entry point
βββ internal/
β βββ cache/ # In-memory caching
β β βββ cache.go
β βββ config/ # Configuration management
β β βββ config.go
β βββ handler/ # HTTP handlers
β β βββ home_handler.go
β β βββ tasa_handler.go
β βββ middleware/ # HTTP middleware
β β βββ ratelimit.go
β βββ models/ # Data models
β β βββ tasa.go
β βββ service/ # Business logic
β βββ bcv_service.go
βββ go.mod # Dependencies
βββ go.sum # Dependency checksums
βββ Makefile # Useful commands
βββ LICENSE # MIT License
βββ README.md
make build- Build the projectmake run- Run server in development modemake clean- Clean compiled filesmake test- Run testsmake deps- Download and update dependenciesmake install- Install dependencies and build
- Go 1.21+: Programming language chosen for its speed and efficiency
- Gorilla Mux: HTTP router for flexible routing
- GoQuery: HTML parser (similar to jQuery) for web scraping
- golang.org/x/time: Rate limiting library
- net/http: Native Go HTTP client
Go was selected for this project because:
- β‘ Performance: Go's compiled nature and efficient runtime make it ideal for high-performance APIs
- π Concurrency: Built-in goroutines allow for concurrent rate fetching, improving response times
- π― Simplicity: Clean syntax and strong standard library reduce complexity
- π Learning: This project serves as a learning experience in Go's ecosystem
The project follows clean architecture principles:
- π Separation of concerns: Handlers, services, and models are clearly separated
- π Dependency injection: Services are injected into handlers
- π‘οΈ Error handling: Comprehensive error handling throughout the codebase
- β‘ Concurrent processing: Rates are fetched concurrently for optimal performance
The API implements an in-memory cache to improve performance and reduce load on the BCV website:
- Automatic caching: Exchange rates are cached automatically after the first request
- Configurable TTL: Cache duration is configurable via
CACHE_TTLenvironment variable (default: 5 minutes) - Per-currency cache: Dollar and Euro rates are cached separately
- Thread-safe: Safe for concurrent requests
- Automatic cleanup: Expired cache entries are automatically removed
Benefits:
- β‘ Faster response times for cached requests
- π Reduced load on BCV website
- π° Lower bandwidth usage
- π― Better user experience
Example:
# First request: Fetches from BCV website (~500ms)
GET /api/rates/dollar
# Subsequent requests within cache TTL: Returns from cache (~1ms)
GET /api/rates/dollar # Cached response- The API fetches rates by scraping the official BCV website (https://www.bcv.org.ve/)
- HTML selectors may need updates if BCV changes their website structure
- The service fetches rates concurrently for better performance
- SSL certificate handling is automatic
- Cached rates are served instantly without making requests to BCV
The code automatically handles BCV SSL certificate issues.
If BCV changes their website structure, you may need to update selectors in internal/service/bcv_service.go.
The API can be configured using environment variables. All settings are optional and have sensible defaults.
| Variable | Default | Description | Example |
|---|---|---|---|
PORT |
8080 |
Server port | PORT=3000 |
BCV_URL |
https://www.bcv.org.ve |
BCV website URL | BCV_URL=https://www.bcv.org.ve |
HTTP_TIMEOUT |
30s |
HTTP request timeout | HTTP_TIMEOUT=45s or HTTP_TIMEOUT=1m |
CACHE_TTL |
5m |
Cache TTL for exchange rates | CACHE_TTL=10m or CACHE_TTL=1h |
USER_AGENT |
(default browser) | User agent for HTTP requests | USER_AGENT=MyApp/1.0 |
RATE_LIMIT_PER_MIN |
60 |
Rate limit per IP (requests per minute) | RATE_LIMIT_PER_MIN=100 |
Basic usage with defaults:
./bin/bcv-apiCustom port:
PORT=3000 ./bin/bcv-apiExtended cache (10 minutes):
CACHE_TTL=10m ./bin/bcv-apiHigher rate limit:
RATE_LIMIT_PER_MIN=100 ./bin/bcv-apiFull custom configuration:
PORT=3000 \
CACHE_TTL=10m \
HTTP_TIMEOUT=45s \
RATE_LIMIT_PER_MIN=100 \
./bin/bcv-apiThe API uses in-memory caching to reduce requests to the BCV website:
- Cache TTL: Configurable via
CACHE_TTL(default: 5 minutes) - Automatic cleanup: Expired entries are automatically removed
- Per-currency caching: Dollar and Euro rates are cached separately
- Thread-safe: Safe for concurrent access
When a cached rate is requested, the API returns the cached value immediately without making a request to BCV, significantly improving response times.
This project is actively being developed and improved. The following features are planned for future releases:
- π§ͺ Unit Tests: Comprehensive test coverage for services, handlers, and utilities
- π Advanced Debugging: Enhanced logging and debugging capabilities with structured logging
- π‘οΈ Advanced Error Handling: More specific error types and better error messages for easier troubleshooting
- β€οΈ Health Check: Add
/healthendpoint for monitoring and load balancer integration - π API Documentation: Generate OpenAPI/Swagger documentation for better developer experience
Note: Rate limiting, caching, and environment variable configuration have been implemented and are now active.
Contributions are welcome! If you'd like to contribute or suggest new features, feel free to open an issue or submit a pull request.
Sebastian Cheikh
This project represents my journey into Go programming. As I continue to learn and grow with this beautiful language, I'm building practical solutions that solve real-world problems.
Contributors are welcome! This project is open to contributions. Whether you want to:
- π Report bugs
- π‘ Suggest new features
- π§ Submit pull requests
- π Improve documentation
- β Share feedback
Your contributions help make this project better for everyone. Feel free to open an issue or submit a pull request.
MIT License