A production-ready cryptocurrency exchange backend built with Spring Boot, Redis, JWT Authentication, OAuth2, Docker and external exchange integrations.
ExchangeAPIv1 is a backend application that provides a secure and scalable infrastructure for cryptocurrency trading platforms.
The project offers authentication, account management, order book retrieval, currency conversion, fee calculation, and integration with external cryptocurrency exchanges while leveraging Redis for caching and Docker for deployment.
The architecture follows common Spring Boot design principles by separating responsibilities into controllers, services, repositories, DTOs, entities, security, and configuration layers.
- JWT Authentication
- OAuth2 Login Support
- Redis Cache Integration
- Redis Sentinel Support
- Docker & Docker Compose
- RESTful API
- External Exchange Integration
- Order Book API
- Currency Conversion API
- Fee Management
- Spring Security
- Validation
- Exception Handling
- Layered Architecture
The project follows a layered architecture to ensure maintainability and scalability
src
├── config
├── controller
├── dto
├── entity
├── exception
├── mapper
├── repository
├── security
├── service
├── util
└── ExchangeApiApplication.java
| Package | Description |
|---|---|
| config | Spring configuration classes |
| controller | REST API endpoints |
| dto | Request & Response models |
| entity | Database entities |
| exception | Global exception handling |
| mapper | Entity ↔ DTO mapping |
| repository | JPA repositories |
| security | JWT & OAuth2 configuration |
| service | Business logic |
| util | Utility classes |
ExchangeAPIv1 is composed of several independent modules, each responsible for a specific business domain.
Base Path
/api/v1/auth
Responsible for:
- User authentication
- JWT token generation
- OAuth2 authentication
- Access token validation
- Secure login flow
Technologies
- Spring Security
- JWT
- OAuth2
- BCrypt Password Encoder
Base Path
/api/v1/accounts
Responsible for:
- Account information
- User profile management
- Account retrieval
- User-related business operations
Base Path
/api/v1/conversion
Responsible for:
- Cryptocurrency conversion
- Fiat currency conversion
- Exchange rate calculation
- External exchange communication
Base Path
/api/v1/orderbook
Responsible for:
- Current market depth
- Bid/Ask information
- Order book retrieval
- Redis caching for fast responses
Base Path
/api/v1/fees
Responsible for:
- Trading fee calculation
- Exchange commission rates
- Fee information
- Trading cost estimation
ExchangeAPIv1 uses Spring Security together with JWT Authentication to secure protected resources.
Authentication flow:
Client
│
│ Login Request
▼
Authentication Controller
│
▼
Authentication Manager
│
▼
JWT Token Generated
│
▼
Client Stores Token
│
▼
Authorization: Bearer <token>
│
▼
Protected Endpoints
- JWT Authentication
- Stateless Sessions
- OAuth2 Login
- Password Encryption (BCrypt)
- Request Authorization
- Role-Based Access Control (RBAC)
- Authentication Filters
- Global Exception Handling
Redis is used to improve application performance by caching frequently requested market data.
Current usages include:
- Order Book Cache
- Market Data Cache
- Temporary Exchange Responses
- Reduced External API Calls
Benefits:
- Faster API responses
- Lower latency
- Reduced load on external exchanges
- Better scalability
The project provides Docker support for easier deployment.
Services include:
- Application Container
- Redis
- Redis Sentinel
- PostgreSQL (if configured)
This allows the entire backend to be started with Docker Compose in a single command.
All endpoints are exposed through REST APIs and return JSON responses.
Base URL:
http://localhost:8080/api/v1Authentication endpoints are responsible for login, registration and token management.
POST /auth/login{
"email": "user@example.com",
"password": "password123"
}{
"token": "eyJhbGciOiJIUzI1NiJ9...",
"expiresIn": 3600
}| Status | Description |
|---|---|
| 200 | Login successful |
| 401 | Invalid credentials |
| 403 | Access denied |
GET /oauth2/authorization/{provider}Supported providers may include:
- GitHub
- Other configured providers
GET /oauth2/authorization/googleBase Path
/api/accountThe Account Service manages user wallets and balances. All endpoints require JWT authentication and operate on the authenticated user's accounts.
| Method | Endpoint | Description |
|---|---|---|
| GET | /wallets |
Get all user wallets |
| GET | /wallets/thirdPart |
Get wallets from third-party exchange (Binance) |
| GET | /wallet/{asset} |
Get wallet information for a specific asset |
| GET | /balance |
Get available balance of an asset |
| POST | /create |
Create a new wallet |
| POST | /deposit/{description} |
Deposit funds into a wallet |
GET /api/account/walletsReturns all wallets belonging to the authenticated user.
Response
[
{
"asset": "BTC",
"balance": 0.45,
"available": 0.42
},
{
"asset": "USDT",
"balance": 5200.50,
"available": 5200.50
}
]GET /api/account/wallets/thirdPartReturns wallet balances retrieved from the connected Binance account.
GET /api/account/wallet/{asset}Example
GET /api/account/wallet/BTCReturns detailed wallet information for the specified asset.
GET /api/account/balance?asset=BTCReturns only the available balance.
Example response
0.53425POST /api/account/create?asset=ETHCreates a wallet for the specified asset if it does not already exist.
POST /api/account/deposit/{description}Parameters
| Parameter | Type |
|---|---|
| asset | String |
| amount | BigDecimal |
| description | String |
Example
POST /api/account/deposit/Salary?asset=USDT&amount=1000&description=SalaryResponse
{
"asset": "USDT",
"balance": 6200.50
}Base Path
/api/conversionsThe Conversion Service allows users to create cryptocurrency conversion offers, execute conversions, cancel pending offers, and retrieve conversion details.
All endpoints require JWT authentication.
| Method | Endpoint | Description |
|---|---|---|
| POST | / |
Create a new conversion offer |
| POST | /{id}/accept |
Accept and execute a conversion |
| POST | /{id}/cancel |
Cancel an existing conversion |
| GET | /{id} |
Get conversion details |
POST /api/conversionsCreates a new conversion quotation between two assets.
| Parameter | Type | Description |
|---|---|---|
| fromAsset | String | Source asset |
| toAsset | String | Target asset |
| amount | BigDecimal | Amount to convert |
| description | String | Conversion description |
| side | String | BUY or SELL |
| conversionType | String | Conversion type |
| idempotencyId | String | Unique request identifier |
POST /api/conversions?fromAsset=BTC&toAsset=USDT&amount=0.5&description=Convert BTC&side=SELL&conversionType=MARKET&idempotencyId=8c5c76fa{
"id": "conv_001",
"fromAsset": "BTC",
"toAsset": "USDT",
"amount": 0.5,
"status": "PENDING"
}POST /api/conversions/{id}/acceptExecutes a previously created conversion offer.
POST /api/conversions/conv_001/accept{
"message": "Conversion completed successfully",
"conversion": {
"id": "conv_001",
"status": "COMPLETED"
}
}{
"error": "Conversion offer has expired."
}POST /api/conversions/{id}/cancelCancels a pending conversion offer.
POST /api/conversions/conv_001/cancel{
"message": "Conversion cancelled successfully",
"conversion": {
"id": "conv_001",
"status": "CANCELLED"
}
}GET /api/conversions/{id}Returns detailed information about a conversion.
GET /api/conversions/conv_001?userId=12345{
"id": "conv_001",
"fromAsset": "BTC",
"toAsset": "USDT",
"amount": 0.50,
"status": "COMPLETED",
"createdAt": "2026-07-04T13:45:10Z"
}Client
│
▼
Create Conversion Offer
│
▼
Offer Created (PENDING)
│
├───────────────┐
▼ ▼
Accept Cancel
│ │
▼ ▼
COMPLETED CANCELLED
- All asset symbols are automatically converted to uppercase.
- Every conversion request requires an idempotencyId to prevent duplicate processing.
- Conversion execution is available only while the offer remains valid.
- Failed operations return a descriptive error message with HTTP
400 Bad Request.
Base Path
/api/managementThe Fee Management Service is responsible for retrieving current trading fees, refreshing fee rates, and calculating final trading prices based on spreads and commissions.
| Method | Endpoint | Description |
|---|---|---|
| GET | /fees |
Get current fee configuration |
| POST | /refresh |
Refresh fee rates manually |
| GET | /calculate |
Calculate final price based on base amount |
| GET | /calculate/quote |
Calculate required quote amount |
GET /api/management/feesReturns all active trading fees.
{
"makerFee": 0.0015,
"takerFee": 0.0025,
"spread": 0.001
}POST /api/management/refreshTriggers a manual refresh of fee configurations.
Manual refresh completed.
GET /api/management/calculate| Parameter | Type |
|---|---|
| amount | BigDecimal |
| pair | String |
| side | BUY / SELL |
GET /api/management/calculate?amount=0.5&pair=BTC-USD&side=BUY{
"requestedAmount": 0.5,
"averagePrice": 65421.50,
"fee": 21.43,
"totalPrice": 32731.18
}GET /api/management/calculate/quoteCalculates the required base amount from a desired quote amount.
Example
GET /api/management/calculate/quote?targetAmount=1000&pair=BTC-USD&side=BUYBase Path
/api/exchangeThe Order Book Service provides real-time market prices, market depth, best execution prices, and volume-aware calculations.
The service consumes live market data and exposes both REST and Server-Sent Events (SSE) endpoints.
| Method | Endpoint | Description |
|---|---|---|
| GET | /stream/prices |
Live market price stream (SSE) |
| GET | /prices |
Get all ticker prices |
| GET | /price |
Get ticker price for a trading pair |
| GET | /orderbook/best-price |
Get best bid/ask price |
| GET | /orderbook/volume/best-price |
Best executable price considering volume |
| GET | /orderbook/totalPrice |
Calculate total & average execution price |
GET /api/exchange/stream/pricesContent-Type
text/event-stream
Returns continuously updated market prices using Server-Sent Events (SSE).
GET /api/exchange/pricesReturns the latest ticker prices for all supported trading pairs.
GET /api/exchange/price?pair=BTC-USDExample Response
{
"pair": "BTC-USD",
"price": 65421.35
}GET /api/exchange/orderbook/best-priceParameters
| Parameter | Type |
|---|---|
| pair | String |
Example
GET /api/exchange/orderbook/best-price?pair=BTC-USDResponse
{
"bid": 65420.20,
"ask": 65421.10
}GET /api/exchange/orderbook/volume/best-priceParameters
| Parameter | Type |
|---|---|
| pair | String |
| amount | BigDecimal |
| side | BUY / SELL |
Example
GET /api/exchange/orderbook/volume/best-price?pair=BTC-USD&amount=2&side=BUYReturns the executable market price while considering available liquidity.
GET /api/exchange/orderbook/totalPriceCalculates:
- Total execution cost
- Average execution price
- Liquidity consumption
Example
GET /api/exchange/orderbook/totalPrice?pair=BTC-USD&amount=1.25&side=SELLExample Response
{
"averagePrice": 65398.24,
"totalPrice": 81747.80
}If there is insufficient market liquidity, the API returns:
{
"error": "Insufficient liquidity for requested amount."
}HTTP Status
400 Bad Request
The Orderbook Service is responsible for providing real-time cryptocurrency market data using Coinbase Exchange market feeds.
It exposes REST APIs and Server-Sent Events (SSE) endpoints to retrieve ticker prices, order book information, liquidity-aware pricing, and execution cost calculations.
Base Path
/api/exchange- Real-time market prices
- Server-Sent Events (SSE)
- Live ticker updates
- Level-2 order book support
- Best Bid / Ask calculation
- Volume-aware execution pricing
- Average execution price calculation
- Liquidity validation
| Method | Endpoint | Description |
|---|---|---|
| GET | /stream/prices |
Live market price stream (SSE) |
| GET | /prices |
Get all ticker prices |
| GET | /price |
Get ticker price by trading pair |
| GET | /orderbook/best-price |
Get current best bid & ask |
| GET | /orderbook/volume/best-price |
Best executable price considering liquidity |
| GET | /orderbook/totalPrice |
Calculate average and total execution price |
Returns continuously updated market prices using Server-Sent Events.
GET /api/exchange/stream/pricesProduces
Content-Type: text/event-streamExample Event
{
"BTC-USD": 65421.82,
"ETH-USD": 3512.15,
"SOL-USD": 148.37
}Returns the latest ticker prices for all available trading pairs.
GET /api/exchange/pricesExample Response
{
"BTC-USD": 65421.82,
"ETH-USD": 3512.15,
"SOL-USD": 148.37,
"AVAX-USD": 24.85
}Returns the latest ticker price for a specific trading pair.
GET /api/exchange/price?pair=BTC-USDExample Response
65421.82Returns the current best executable bid and ask prices from the Level-2 Order Book.
GET /api/exchange/orderbook/best-price?pair=BTC-USDExample Response
{
"bid": 65420.75,
"ask": 65421.10
}Calculates the executable price by consuming available liquidity from the order book.
Unlike the ticker endpoint, this calculation takes order volume into account.
GET /api/exchange/orderbook/volume/best-price| Name | Type | Required |
|---|---|---|
| pair | String | Yes |
| amount | BigDecimal | Yes |
| side | BUY / SELL | Yes |
Example
GET /api/exchange/orderbook/volume/best-price?pair=BTC-USD&amount=2&side=BUYExample Response
65434.28Calculates how much a market order would cost based on the current order book liquidity.
The service traverses Level-2 market depth and computes:
- Average execution price
- Total execution cost
- Liquidity consumption
GET /api/exchange/orderbook/totalPrice| Name | Type |
|---|---|
| pair | String |
| amount | BigDecimal |
| side | BUY / SELL |
Example
GET /api/exchange/orderbook/totalPrice?pair=BTC-USD&amount=1.25&side=BUYExample Response
{
"averagePrice": 65433.41,
"totalPrice": 81791.76
}If the requested order size exceeds the available market liquidity, the service throws an InsufficientLiquidityException.
Example Response
{
"error": "Insufficient liquidity for requested amount."
}HTTP Status
400 Bad Requestflowchart TD
A[Client Request]
A --> B[Orderbook Controller]
B --> C[Orderbook Service]
C --> D[Redis Cache]
D -->|Cache Miss| E[Coinbase WebSocket Data]
E --> F[Level-2 Order Book]
F --> G[Liquidity Calculation]
G --> H[Average Price]
H --> I[Return Response]
-
Prices are retrieved from Coinbase Exchange.
-
Trading pair symbols are automatically normalized to uppercase.
-
Level-2 order book data is used for all volume-based calculations.
-
Best execution prices consider available market liquidity rather than only the latest ticker price.
-
Live prices are streamed using Server-Sent Events (SSE) for low-latency updates.
The application receives real-time cryptocurrency market data from Coinbase Exchange using a persistent WebSocket connection.
Instead of sending HTTP requests for every price update, the application subscribes to Coinbase's WebSocket feed and continuously receives market events.
This approach significantly reduces latency while minimizing external API requests.
wss://ws-feed-public.sandbox.exchange.coinbase.com
When the application starts, it automatically establishes a WebSocket connection and subscribes to multiple market data channels.
| Channel | Purpose |
|---|---|
| ticker | Live market prices |
| level2 | Order book updates |
| heartbeat | Connection health monitoring |
Current subscribed product:
BTC-USD
The subscription request is authenticated using Coinbase WebSocket credentials.
Each request contains:
- API Key
- Passphrase
- Timestamp
- HMAC Signature
Example subscription payload:
{
"type":"subscribe",
"product_ids":[
"BTC-USD"
],
"channels":[
"ticker",
"level2",
"heartbeat"
],
"signature":"********",
"key":"********",
"passphrase":"********",
"timestamp":"1720098123"
}Every incoming WebSocket message follows the same processing pipeline.
flowchart LR
A[Coinbase Exchange]
A --> B[WebSocket Client]
B --> C[Parse JSON]
C --> D[Detect Message Type]
D --> E[MessageHandlerFactory]
E --> F[Ticker Handler]
E --> G[Level2 Handler]
E --> H[Heartbeat Handler]
F --> I[Redis Cache]
G --> I
H --> I
The application uses the Factory Pattern to process incoming messages.
Each WebSocket event is delegated to its dedicated handler.
Example flow:
Incoming JSON
│
▼
type = ticker
│
▼
MessageHandlerFactory
│
▼
TickerMessageHandler
│
▼
Update Cache
Supported message types include:
- ticker
- level2
- heartbeat
The WebSocket client automatically reconnects whenever the connection is interrupted.
Reconnection strategy:
- Initial retry after 2 seconds
- Exponential backoff
- Maximum backoff of 30 seconds
- Unlimited retry attempts
This ensures uninterrupted market data streaming even during temporary network failures.
After processing, incoming market data is stored in the application's cache.
Cached data includes:
- Latest ticker prices
- Level-2 order book
- Best Bid
- Best Ask
- Market depth
Other services retrieve data directly from the cache instead of calling Coinbase repeatedly.
The WebSocket connection is initialized automatically during application startup.
Application Start
│
▼
@PostConstruct
│
▼
Open WebSocket Connection
│
▼
Authenticate
│
▼
Subscribe Channels
│
▼
Receive Live Market Data
- Reactive WebSocket client using Spring WebFlux
- Asynchronous startup (
@Async) - Automatic reconnection strategy
- Factory-based message processing
- Real-time market data streaming
- Redis-backed market cache
- Low-latency order book updates
The application can be configured using the application.yml or environment variables.
| Property | Description |
|---|---|
SERVER_PORT |
Application port |
SPRING_DATASOURCE_URL |
Database connection URL |
SPRING_DATASOURCE_USERNAME |
Database username |
SPRING_DATASOURCE_PASSWORD |
Database password |
JWT_SECRET |
Secret key used to sign JWT tokens |
JWT_EXPIRATION |
JWT expiration time |
REDIS_HOST |
Redis server hostname |
REDIS_PORT |
Redis server port |
REDIS_PASSWORD |
Redis password (optional) |
COINBASE_API_KEY |
Coinbase API Key |
COINBASE_API_SECRET |
Coinbase API Secret |
The project includes Docker support for local development and deployment.
docker compose builddocker compose up -ddocker compose downTo rebuild after code changes:
docker compose up --buildgit clone https://github.com/CANWIA00/ExchangeAPIv1.gitcd ExchangeAPIv1./mvnw clean installor
mvn clean install./mvnw spring-boot:runor
mvn spring-boot:runDefault URL
http://localhost:8080
The following diagram shows how a typical authenticated request is processed.
Client
│
▼
Spring Security Filter
│
JWT Authentication Filter
│
▼
REST Controller
│
▼
Service Layer
│
┌────────┴────────┐
▼ ▼
Redis Cache External API
│ │
└────────┬────────┘
▼
Response DTO
│
▼
Client
Redis is used to cache frequently requested data.
Cached resources include:
- Order Books
- Market Data
- Currency Conversion Results
- Frequently Requested Exchange Responses
Advantages:
- Reduced latency
- Fewer external API requests
- Improved scalability
- Better user experience
All API errors follow a consistent JSON format.
Example:
{
"timestamp": "2026-07-04T14:25:10Z",
"status": 400,
"error": "Bad Request",
"message": "Invalid request parameters",
"path": "/api/v1/orderbook/BTC-USD"
}| Status | Description |
|---|---|
| 200 | Request completed successfully |
| 201 | Resource created |
| 400 | Validation or business error |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Resource not found |
| 409 | Conflict |
| 500 | Internal server error |
Run all unit tests:
./mvnw testGenerate package:
./mvnw clean packageRun a specific test:
./mvnw test -Dtest=ClassName
# 🏗️ System Architecture
```mermaid
flowchart TD
A[Client Application]
A --> B[Spring Security]
B --> C[JWT Authentication Filter]
C --> D[REST Controllers]
D --> E[Service Layer]
E --> F[(Redis Cache)]
E --> G[(Database)]
E --> H[Coinbase Exchange API]
F --> E
G --> E
H --> E
E --> D
D --> AsequenceDiagram
participant Client
participant Security
participant AuthController
participant JWT
participant API
Client->>AuthController: Login Request
AuthController->>Security: Validate Credentials
Security-->>AuthController: Authentication Success
AuthController->>JWT: Generate Token
JWT-->>Client: JWT Token
Client->>API: Authorization Bearer Token
API->>JWT: Validate Token
JWT-->>API: Valid
API-->>Client: Protected Resource
| Category | Technologies |
|---|---|
| Language | Java |
| Framework | Spring Boot |
| Security | Spring Security, JWT, OAuth2 |
| Cache | Redis |
| ORM | Spring Data JPA |
| Build Tool | Maven |
| Containerization | Docker |
| External APIs | Coinbase Exchange API |
| REST Client | Spring WebClient |
| Validation | Jakarta Validation |
| Authentication | JWT + OAuth2 |
Planned enhancements include:
- WebSocket Market Streaming
- Kafka Event Processing
- RabbitMQ Integration
- Kubernetes Deployment
- Prometheus Monitoring
- Grafana Dashboards
- API Rate Limiting
- Multi Exchange Support
- OpenAPI (Swagger) Documentation
- CI/CD Pipeline
- Unit & Integration Test Coverage Improvements
Contributions are welcome.
-
Fork the repository.
-
Create a feature branch.
git checkout -b feature/new-feature- Commit your changes.
git commit -m "Add new feature"- Push the branch.
git push origin feature/new-feature- Open a Pull Request.
This project is licensed under the MIT License.
See the LICENSE file for more details.
Can Aydın
Backend Developer
GitHub
https://github.com/CANWIA00
If you found this project useful, consider giving it a ⭐ on GitHub.
It helps the project grow and motivates future development.
