Linqra Sample Inventory Service
View the complete sample service implementation with CRUD operations and service-to-service communication.
Linqra Sample Product Service
View the sample product service implementation with REST endpoints for product management and integration with other microservices.
Creating Custom Microservices
This guide demonstrates how to create and configure new microservices that integrate with the Linqra platform. We’ll use the “Inventory Service” as a reference implementation.Project Structure
A typical Linqra microservice follows this structure:Creating a New Microservice
Let’s walk through creating the Inventory Service example:1. Set Up Project Structure
Create the directories shown below:2. Configure Maven Dependencies
Create apom.xml with the necessary dependencies:
3. Create Main Application Class
Create the main application classInventoryServiceApplication.java:
4. Configure Service Discovery
CreateEurekaClientConfig.java to enable service discovery:
5. Configure Application Properties
Createapplication.yml with necessary settings:
Run Configuration in IntelliJ
1. VM Options Configuration
Set the following VM options:
2. Environment Variables
Set the following environment variables:
Remember to adjust the paths according to your actual project location.
Verifying Service Registration
After starting your service, verify that it has registered with Eureka by accessing the Eureka dashboard athttps://localhost:8761/.
You should see your service listed in the “Instances currently registered with Eureka” section:

A successful registration means:
- Your service shows as “UP” in the Status column
- It appears with a unique instance ID
- The API-GATEWAY service is also registered and running
Extending Your Microservice
Let’s extend our inventory service with additional components:Updated Project Structure
After adding the controller and model classes, your project structure should look like this:Adding Health Monitoring
1. Create Health Model
Create theHealthStatus.java class in the model package:
2. Create Health Controller
Create theHealthController.java class in the controller package:
Integration with API Gateway
The API Gateway will automatically communicate with your service’s health endpoint if health checking is enabled. The/api/health endpoint will return detailed information about your service’s health status, including:
- Service identifier
- Current status (UP/DOWN)
- Service uptime
- Current timestamp
- Performance metrics like heap usage and CPU information
Since we’re using dynamic port allocation (
server.port: 0), you’ll need to check the Eureka dashboard or your service logs to determine the assigned port.Best Practices for Controllers
When building REST APIs in your microservice:-
Use Proper Request Mapping: Prefix all endpoints with
/api/{resource}for consistency -
Return Appropriate Status Codes:
- 200 OK for successful operations
- 201 Created for resource creation
- 204 No Content for successful operations with no response body
- 400 Bad Request for client errors
- 404 Not Found when resources don’t exist
- 500 Internal Server Error for server errors
-
Validation: Add validation to request models using annotations like
@Validand constraint annotations - Exception Handling: Create a global exception handler to provide consistent error responses
- Documentation: Use Swagger/OpenAPI annotations to document your API endpoints
Enhancing Security Configuration
Let’s extend our microservice with proper security configuration to validate JWT tokens and implement mutual TLS (mTLS) authentication.Updated Project Structure
After adding the security components, your project structure should look like this:Security Implementation
1. JWT Role Validation Filter
Create a filter to validate JWT tokens and check for required roles:2. Security Configuration
Create theSecurityConfig.java class to configure Spring Security:
Understanding the Security Architecture
Dual Authentication Mechanism
Our microservice uses two authentication mechanisms:-
JWT Token Validation
- OAuth2 Resource Server configuration authenticates JWT tokens from Keycloak
- JwtRoleValidationFilter validates that tokens contain required roles:
- Realm role:
gateway_admin_realm - Client role:
gateway_admin(for thelinqra-gateway-client)
- Realm role:
- These roles were configured in Keycloak as described in the Keycloak Configuration documentation
-
Mutual TLS (mTLS)
- SSL configuration in
application.ymlenables client authentication (client-auth: want) - X509 configuration extracts the Common Name (CN) from client certificates
- This enables secure service-to-service communication with certificate-based authentication
- SSL configuration in
Authorization Flow
- When a request arrives, the JWT token is validated for proper signatures and expiration
- Our custom
JwtRoleValidationFilterchecks for the presence of required roles - If mTLS is enabled, client certificates are also validated
- If all checks pass, the request is processed; otherwise, a 403 Forbidden response is returned
Testing Security Configuration
To test with a valid JWT token, you need to:- Obtain a token from Keycloak using the client credentials grant type
- Include the token in the Authorization header of your requests:
Creating REST API Controllers and Intercommunication
Before implementing business logic, let’s set up proper service-to-service communication and create our main API controller.Updated Project Structure
After adding these components, your project structure will look like this:Service Identification in Communication
1. Create Service Interceptor
TheServiceNameInterceptor adds a service identifier to all outgoing REST calls, which helps with logging, debugging, and request tracing:
2. Configure RestTemplate
Create aRestTemplateConfig class to set up a pre-configured RestTemplate with our interceptor:
3. Create Main Controller
Create a skeleton for theInventoryController that will house our business logic endpoints:
Understanding the Intercommunication Architecture
Service Identification
Every microservice in the Linqra ecosystem should identify itself in communications with other services. This provides several benefits:- Request Tracing: The source of each request is clearly identified in logs
- Debugging: Makes troubleshooting complex service interactions easier
- Auditing: Allows for proper auditing of service-to-service communication
- Access Control: Enables service-specific access policies
RestTemplate Configuration
OurRestTemplateConfig provides:
- Media Type Support: Handles both JSON and binary data
- Service Identity: Automatically adds the service name to all outgoing requests
- Centralized Configuration: One place to add any future interceptors or converters
Building RESTful APIs
When implementing theInventoryController, follow these patterns for standard CRUD operations:
GET (Retrieve)
POST (Create)
DELETE (Remove)
Service-to-Service Communication Example
When your service needs to communicate with another microservice, use the injected RestTemplate:Security Considerations for APIs
When implementing API endpoints, keep these security considerations in mind:- Input Validation: Always validate incoming data with
@Validannotations - Authentication Checks: Ensure endpoints check for appropriate authentication
- Authorization Logic: Implement fine-grained authorization in service methods
- Rate Limiting: Consider adding rate limiting for high-traffic endpoints
- Sensitive Data: Never expose sensitive data in responses
Implementing Business Logic with REST Controllers
Let’s finalize our Inventory Service by implementing a fully functional controller with CRUD operations and inter-service communication.Updated Project Structure
After adding all the business logic components, your project structure will look like this:Domain Models
First, let’s create the domain models for our inventory system:1. InventoryItem
Create a model to represent inventory items:2. ProductInfo
Create a model for product information that will be enriched with inventory data:3. ProductAvailabilityResponse
Create a wrapper for product responses:Complete Inventory Controller
Now let’s implement the fullInventoryController with CRUD operations and service-to-service communication:
Understanding the Controller Implementation
CRUD Operations
The controller implements standard CRUD operations for inventory items:- CREATE (POST): Adds a new inventory item
- READ (GET): Retrieves either all items or a specific item by ID
- UPDATE (PUT): Updates an existing inventory item
- DELETE (DELETE): Removes an inventory item
In-Memory Data Store
For simplicity, this implementation uses an in-memoryHashMap to store inventory data:
inventoryItems: Map that stores items with their ID as the keyidCounter: Atomic counter that ensures unique IDs for new itemsaddMockItem: Helper method to initialize some sample data
Service-to-Service Communication
The/product-availability endpoint demonstrates service-to-service communication:
- It calls the Product Service (via the API Gateway) to get product information
- It enriches the product data with inventory information (availability, delivery estimates)
- It returns the combined data to the caller
Testing the Inventory Service
When running the Inventory Service, you can test its endpoints:- Get all items:
GET https://localhost:{port}/inventory-service/api/inventory - Get a specific item:
GET https://localhost:{port}/inventory-service/api/inventory/1 - Create a new item:
POST https://localhost:{port}/inventory-service/api/inventory - Update an item:
PUT https://localhost:{port}/inventory-service/api/inventory/1 - Delete an item:
DELETE https://localhost:{port}/inventory-service/api/inventory/1 - Product availability:
GET https://localhost:{port}/inventory-service/api/inventory/product-availability
Remember that the actual port will be dynamically assigned since we’re using
server.port: 0. Check the Eureka dashboard or service logs to find the assigned port.Next Steps in Development
Now that you have implemented the core service with proper security, you can extend it with:-
Business Logic Controllers
- Create additional controllers for your service’s functionality
- Implement proper authorization checks based on user roles
-
Database Integration
- Add Spring Data repositories for persistence
- Configure database connections in application.yml
-
Service-to-Service Communication
- Use RestTemplate or WebClient to call other microservices
- Configure circuit breakers for resilience
-
Testing
- Implement unit tests for controllers and services
- Create integration tests for full API verification
-
Swagger Documentation
- Add OpenAPI annotations to document endpoints
- Configure Swagger UI for interactive documentation
Reference Implementation
A complete reference implementation of the Inventory Service is available on GitHub for your reference:Linqra Sample Inventory Service
View the complete sample service implementation with CRUD operations and service-to-service communication.
Linqra Sample Product Service
View the sample product service implementation with REST endpoints for product management and integration with other microservices.
- Full implementation of the InventoryController with CRUD operations
- Models for inventory items and product availability
- Service-to-service communication with the Product Service
- Mock data for testing purposes
CI/CD Deployment
The Inventory Service uses GitHub Actions for continuous integration and deployment. When code is merged into the master branch, it automatically deploys to EC2. Here’s the complete CI/CD configuration:Automatic Deployment Process
When code is merged into the master branch, the following process occurs automatically:-
Source Code Upload
- The entire source code is uploaded as an artifact
- Docker compose file and pom.xml are uploaded separately
- Kubernetes and keys configurations are uploaded if present
-
EC2 Deployment
- The deployment job is triggered only on master branch
- SSH key is installed for secure EC2 access
- Files are transferred to EC2 using rsync
- Proper permissions are set for sensitive files
-
Docker Operations
- Unused Docker resources are pruned
- Disk usage is checked
- Docker network is ensured
- Container is built and started
-
Security
- Sensitive files (keys) are handled with proper permissions
- SSH key is used for secure deployment
- Strict host key checking is disabled for automation
Required GitHub Secrets
The following secrets must be configured in your GitHub repository:EC2_SSH_KEY_PROD: SSH private key for EC2 accessHOST_DNS_PROD: EC2 instance DNSUSERNAME_PROD: EC2 username (typically ‘ubuntu’)TARGET_DIR_PROD: Target directory on EC2
Dependency Review
For pull requests, a dependency review is performed to check for:- High severity vulnerabilities
- Outdated dependencies
- License compliance

