Best practices for building containers
Adding Open API Swagger support to Spring Boot
Pagination and Sorting using Spring Data JPA
Introduction
Spring Boot Rest Application
BlogControllerV0,
BlogControllerV1,
BlogControllerV2 etc.
<!-- swagger ui -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.5.10</version>
</dependency>Accessing the Swagger documentations
http://localhost:8080/swagger-ui/index.html{
"openapi":"3.0.1",
"info":{
"title":"OpenAPI definition",
"version":"v0"
},
"servers":[
{
"url":"http://localhost:8080",
"description":"Generated server url"
}
],
"paths":{
"/blogapi/v2/blogs":{
"get":{
"tags":[
"blog-controller-v-2"
],
"operationId":"getBlogStories",
"responses":{
"200":{
"description":"OK",
"content":{
"application/json":{
"schema":{
"type":"array",
"items":{
"$ref":"#/components/schemas/BlogStory"
}
}
}
}
}
}
},
"post":{
"tags":[
"blog-controller-v-2"
],
"operationId":"addBlogStory",
"requestBody":{
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/BlogStory"
}
}
},
"required":true
},
"responses":{
"200":{
"description":"OK",
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/BlogStory"
}
}
}
}
}
}
},
"/blogapi/v1/categories":{
"get":{
"tags":[
"category-controller"
],
"operationId":"getBlogCats",
"responses":{
"200":{
"description":"OK",
"content":{
"application/json":{
"schema":{
"type":"array",
"items":{
"$ref":"#/components/schemas/BlogCategory"
}
}
}
}
}
}
},
"post":{
"tags":[
"category-controller"
],
"operationId":"addCats",
"requestBody":{
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/BlogCategory"
}
}
},
"required":true
},
"responses":{
"200":{
"description":"OK",
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/BlogCategory"
}
}
}
}
}
}
},
"/blogapi/v2/blogs/{id}":{
"get":{
"tags":[
"blog-controller-v-2"
],
"operationId":"getBlogStory",
"parameters":[
{
"name":"id",
"in":"path",
"required":true,
"schema":{
"type":"string"
}
}
],
"responses":{
"200":{
"description":"OK",
"content":{
"application/json":{
"schema":{
"$ref":"#/components/schemas/BlogStory"
}
}
}
}
}
}
}
},
"components":{
"schemas":{
"BlogStory":{
"type":"object",
"properties":{
"id":{
"type":"string"
},
"name":{
"type":"string"
},
"summary":{
"type":"string"
},
"description":{
"type":"string"
},
"category":{
"type":"string"
}
}
},
"BlogCategory":{
"type":"object",
"properties":{
"id":{
"type":"string"
},
"name":{
"type":"string"
}
}
}
}
}
}Summary
References
Pagination and Sorting in REST API using Spring Data JPA
Pagination and Sorting using Spring Data JPA
Introduction
Total number of records
Number of records on a page (page size)
Current Page number (page order number) Based on the above informations we can build the algorithm to fetch the respective data. In the SQL world given the current page and page size, we can retrieve the information using limit and offset like follows, Select * from [TABLE NAME] limit pageSize, offset pageNumber*pageSize Spring Data encapsulates all these algorithms/queries and handles all edge cases to return us paginated data.
Implementations
@Entity
@Table (name = "dish_table")
public class Dish {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "id")
private Long id;
@NotNull
@Size(min=2, message="Name should have atleast 5 characters")
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "lowprice")
private Double lowPrice;
@Column(name = "highprice")
private Double highPrice;
public Dish () {}
//Getter and Setters
}@Repository
public interface DishRepository extends JpaRepository {
public Page findByName(String name, Pageable pageable);
} @RestController
@RequestMapping("api/v2")
public class DishControllerPaginatedV2 {
private static final int pageSize = 2;
@Autowired
DishRepository repo;
@GetMapping(value="/dishes",produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity> getDish3(@RequestParam (defaultValue = "0") int pageNo) throws Exception {
Sort sort = Sort.by("name");
Pageable pageReq = PageRequest.of(pageNo, pageSize, sort);
Page result = repo.findAll(pageReq);
return ResponseEntity.ok(result);
}
} curl --request GET \
--url 'http://localhost:8080/api/v1/dishes3?pageNo=0' \
--header 'cache-control: no-cache'{
"content": [
{
"id": 12,
"name": "Anchovies",
"description": "Anchovies",
"lowPrice": 1987,
"highPrice": 0
},
{
"id": 14,
"name": "Celery",
"description": "Celery",
"lowPrice": 2928,
"highPrice": 0
}
],
"pageable": {
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"offset": 0,
"pageNumber": 0,
"pageSize": 2,
"paged": true,
"unpaged": false
},
"last": false,
"totalPages": 7,
"totalElements": 14,
"size": 2,
"number": 0,
"sort": {
"sorted": true,
"unsorted": false,
"empty": false
},
"numberOfElements": 2,
"first": true,
"empty": false
}Summary
References
Restful API using Jersey 3 Jakarta EE 9
Project Structure
- Java 15
- Mvn 3.5.0
- Jersey 3.0.2
- JUnit 5.3.1
Java Classes
public class JakartaRestfulApp extends Application {
private final Set> classes;
public JakartaRestfulApp() {
HashSet> c = new HashSet>();
c.add(MenuResource.class);
classes = Collections.unmodifiableSet(c);
}
@Override
public Set> getClasses() {
return classes;
}
} @Path("/rest")
public class MenuResource {
MenuService service = MenuService.getInstance();
@GET
@Path("/menus")
@Produces("application/json")
public Listpublic class MenuService {
private static MenuService instance = new MenuService();
private static HashSetpublic class Menu {
private Long id;
private String name;
public Menu() {
}
public Menu(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}public class JDKSEServer {
private static final Logger LOGGER = Logger.getLogger(JDKSEServer.class.getName());
/**
* Starts the JDK HTTP server serving the JAX-RS application.
*/
static HttpServer startServer() throws IOException {
ResourceConfig config = new ResourceConfig(MenuResource.class);
HttpServer server = JdkHttpServerFactory.createHttpServer(getBaseURI(), config);
return server;
}
public static void main(String[] args) {
try {
final HttpServer httpServer = startServer();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
try {
LOGGER.info("Shutting down the application...");
httpServer.stop(0);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, null, e);
}
}));
LOGGER.info("Application started.%nStop the application using CTRL+C");
Thread.currentThread().join();
} catch (Exception ex) {
LOGGER.log(Level.SEVERE, null, ex);
}
}
/**
* Gets base {@link URI}.
*/
public static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost/").port(8080).build();
}
}Unit Testing
public class TestMenuResource extends JerseyTest {
@BeforeEach
void init() throws Exception {
super.setUp();
}
@Override
protected Application configure() {
//to start a new container in s different port
forceSet(TestProperties.CONTAINER_PORT, "0");
return new ResourceConfig(MenuResource.class);
}
@Test
public void get_one() throws Exception {
Response response = target("/rest/menus/1").request().get();
System.out.println("sd " + response.getStatus());
assertEquals(response.getStatus(), 200);
assertEquals(response.readEntity(Menu.class).getName(), "Menu One");
}
protected TestContainerFactory getTestContainerFactory() {
return new JdkHttpServerTestContainerFactory();
}
}Executing Code
References
REST API Design principles
Introduction
What is REST
REST API Design Principles
- Uniform Interface: REST APIs are designed around resources, which are any kind of object, data, or service that can be accessed by the client. A resource has an identifier, which is a URI that uniquely identifies that resource.
Use Noun and not verb to represent a resource
In general, it helps to use plural nouns - Client-Server: Client and Server are independent of each others and the only way the client interacts is through the URI of the resources.
Client and server can evolve independently.
Client and server can be implemented in different tech stack. - Stateless : REST APIs use a stateless request model. HTTP requests should be independent and may occur in any order. The only place where information is stored is in the resources themselves, and each request should be an atomic operation.
Being stateless means REST API can scale easily. - Cacheable: response to a request be implicitly or explicitly labeled as cacheable or non-cacheable.
- Layered System: Client and Server should not be tightly coupled and if required and added any intermediate layer the API still should work.
Navigating Treemap in Java
Table of Content
Navigating Treemap in Java
NavigableMap
- lowerkey (key): Returns the greatest key strictly less than the given key, or null if there is no such key
- lowerEntry (key): Follows the above and returns the key-value mapping for the key.
- floorKey (key): Returns the greatest key less than the given key or equal to the given key, or null if there is no such key
- floorEntry (key): Follows the above and returns the key-value mapping for the key.
- higherKey (key): Returns the lowest key strictly greater than the given key, or null if there is no such key
- higherEntry (key): Follows the above and returns the key-value mapping for the key.
- ceilingKey (key): Returns the least key greater than or equal to the given key, or null if there is no such key
- ceilingEntry (key): Follows the above and returns the key-value mapping for the key.
- firstEntry (): Returns a key-value mapping associated with the least key in this map
- lastEntry (): Returns a key-value mapping associated with the highest key in this map
- pollFirstEntry (): Remove and returns a key-value mapping associated with the least key in this map
- pollLastEntry (): Remove and returns a key-value mapping associated with the highest key in this map
Java Code to see above methods
TreeMap<Integer, String> map = new TreeMap<> ();
map.put(15, "banana");
map.put(16, "apple");key = map.lowerKey(16);
test = map.lowerEntry(16);
System.out.println(key); //15
System.out.println(test); //bananakey = map.floorKey(16);
test = map.floorEntry(16);
System.out.println(key); //16
System.out.println(test); //applekey = map.higherKey(14);
test = map.higherEntry(14);
System.out.println(key); //15
System.out.println(test); //bananakey = map.ceilingKey(16);
test = map.ceilingEntry(16);
System.out.println(key); //16
System.out.println(test.getValue()); //apple- Treemap is Red-Black tree-based implementation.
- Treemap provides guaranteed log(n) time cost for containsKey(), get(), put(), and remove() .
References
Useful resources for Dijkstra's Algorithm
Dijkstra's algorithm
Important Points
Complexity
References
Examples
Increasing monotonic array:
[1, 2, 20, 30]
[1, 2, 20, 20, 30]
decreasing monotonic array:
[66, 50, 40, 4]
[66, 50, 40, 40]
Algorithm
Implementation
public class MonotonicArray {
public boolean isMonotonic(int[] nums) {
int signal = -1; // -1 = not set, 0 = increasing, 1 = decreasing
// iterate over the array till the arry.length-1 from 0
for (int i = 0; i < nums.length - 1; i++) {
// if signal is not initialized and we see either increasing or decreasing array
// initialize it accordingly
if (signal == -1) {
if (nums[i] < nums[i + 1]) {
signal = 0; // increasing
} else if (nums[i] > nums[i + 1]) {
signal = 1; // decreasing
}
} else {
// once the signal is already initialized
// then check if for other elements it holds true or not
if (signal == 0 && nums[i] > nums[i + 1]) {
return false;
}
if (signal == 1 && nums[i] < nums[i + 1]) {
return false;
}
}
}
return true;
}
}
References
Java PriorityQueue Complexity
PriorityQueue
O(1) opearations: peek(), size()
O(n) operations: remove(object), contains(object)
HashMap
O(n) operations: clone(), equals(), hashCode(), toArray(), toString()
O(1) opearations: clear(), isEMpty(), size()
TreeMap
O(n) operations: clone(), equals(), hashCode(), toArray(), toString(), containsValue()
O(1) opearations: clear(), isEMpty(), size()
TreeSet
O(1) opearations: clear(), first(), isEMpty(), size(), last(), pollFirst(), pollLast()
O(n) operations: clone(), equals(), hashCode(), toArray() and toString()
Java un-initializing Array
byte rollNums1[] = new byte[10];
short rollNums2[] = new short[10];
int rollNums3[] = new int[10];
long rollNums4[] = new long[10];
float rollNums5[] = new float[10];
double rollNums6[] = new double[10];
char rollNums7[] = new char[10];
boolean rollNums8[] = new boolean[10];
Integer rollNums9[] = new Integer[10]; byte rollNums1[] = new byte[10];
System.out.println("\nbyte array");
for (byte i : rollNums1) {
System.out.print(i + ", ");
}
short rollNums2[] = new short[10];
System.out.println("\nshort array");
for (short i : rollNums2) {
System.out.print(i + ", ");
}
int rollNums3[] = new int[10];
System.out.println("\nint array");
for (int i : rollNums3) {
System.out.print(i + ", ");
}
long rollNums4[] = new long[10];
System.out.println("\nlong array");
for (long i : rollNums4) {
System.out.print(i + ", ");
}
float rollNums5[] = new float[10];
System.out.println("\nfloat array");
for (float i : rollNums5) {
System.out.print(i + ", ");
}
double rollNums6[] = new double[10];
System.out.println("\ndouble array");
for (double i : rollNums6) {
System.out.print(i + ", ");
}
char rollNums7[] = new char[10];
System.out.println("\nchar array");
for (char i : rollNums7) {
System.out.print(i + ", ");
}
boolean rollNums8[] = new boolean[10];
System.out.println("\nboolean array");
for (boolean i : rollNums8) {
System.out.print(i + ", ");
}
Integer rollNums9[] = new Integer[10];
System.out.println("\nInteger array");
for (Integer i : rollNums9) {
System.out.print(i + ", ");
}double array 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
- If the array is just created and not initialized with data then the content of the arrays depends on the data type.
- For byte, short, int, long it is 0
- For float and double it is 0.0
- for char it is '' (empty character)
- for boolean it is false
- for Integer or any other object, it is null
- The value of the array depends on the type of the array and a default value for the respective data types.
References
Array Initialize
//initialize array of size 10 of type int
int rollNums[] = new int[10];
//iterate from 0 to the last index of the array and set values
for (int i = 0; i < rollNums.length; i++) {
rollNums[i] = i + 1;
}int rollNums[] = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int rollNums[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};int rollNums[] = new int[10];
Arrays.setAll(rollNums, p -> p + 1);int rollNums[] = new int[10];
Arrays.setAll(rollNums, new IntUnaryOperator () {
@Override
public int applyAsInt(int operand) {
return operand + 1;
}} );int rollNums2[] = Arrays.copyOf(rollNums, rollNums.length);- We can create an array in java using a new operator and specify size while creating.
- We can also specify the content of the array and java will create an array of sufficient size.
- When we create an array and does not initialize then the content of the array is null if the type of the array is of type object
- and 0 if the type is int.
Default Method in Java
What are default methods?
Java 5
interface Java5Interface {
public static int four = 4;
int five = 5; // implicitly public static
public abstract void welcome();
public void sayHi();
void bye();
}interface Java5Invalid {
private int six = 6; //illegal only public static and final is permitted
private void cleanuup(); // illegal only public and abstract is permitted
}Java 8 and onwards
interface Greetings {
public default void greet() {
openDoor();
sayHi();
sayBye();
closeDoor();
}
default void openDoor() {
//open the door
}
void sayHi();
void sayBye();
private void closeDoor() {
lockDoor();
}
static void lockDoor() {
//lock door implementation
}
}- default methods are public.
- default methods are inherited by implementation classes.
- default methods can be overridden by implementation classes.
- a default method can add more functionality to the Interface without breaking binary compatibility.
- static methods are also allowed which are Interface level methods and cannot be overridden by subclasses.
- Java 8 methods can have public, private, abstract, default, static, and strictfp.
References
Convert Java Set to Java List
Convert Java Set to List
Set mySet = new HashSet(Arrays.asList("Red", "Yellow", "Green", "Blue")); List myList = new ArrayList(mySet); List myList2 = new ArrayList();
myList2.addAll(mySet); List myList3 = new ArrayList();
mySet.forEach(a->myList3.add(a)); List myList4 = mySet.stream().collect(Collectors.toList()); package myjava.work.general;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public class JavaListFromSet {
public static void main(String[] args) {
Set<String> mySet = new HashSet<String>(Arrays.asList("Red", "Yellow", "Green", "Blue"));
// Using Constructor
List<String> myList = new ArrayList<String>(mySet);
myList.forEach(a -> System.out.println(a));
// Using addAll
List<String> myList2 = new ArrayList<String>();
myList2.addAll(mySet);
myList2.forEach(a -> System.out.println(a));
// Using For Each
List<String> myList3 = new ArrayList<String>();
mySet.forEach(a -> myList3.add(a));
myList3.forEach(a -> System.out.println(a));
// Using Stream
List<String> myList4 = mySet.stream().collect(Collectors.toList());
myList4.forEach(a -> System.out.println(a));
}
}
Sorting Multidimensional array in Java
Sorting Array
{ { 20, 25 },{ 10, 15 }, { 10, 25 }, { 20, 15 }}Comparators
class MultiDimArrayComparator implements Comparator {
@Override
public int compare(int[] m, int[] n) {
return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
}
}
Arrays.sort(arr, new MultiDimArrayComparator()); Arrays.sort(arr, new Comparator() {
@Override
public int compare(int[] m, int[] n) {
return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
}
}); Arrays.sort(arr, (m, n) -> m[0] == n[0] ? m[1] - n[1] : m[0] - n[0]);Full Example
public class ArraysSort {
public static void main(String[] args) {
int arr[][] = { { 20, 25 },{ 10, 15 }, { 10, 25 }, { 20, 15 }};
int arr1[][] = arr;
Arrays.sort(arr1, new MultiDimArrayComparator());
System.out.println("Sorted Result");
for (int[] x : arr1) {
System.out.println(x[0] + " " + x[1]);
}
arr1 = arr;
Arrays.sort(arr1, new Comparator<int[]>() {
@Override
public int compare(int[] m, int[] n) {
return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
}
});
System.out.println("Sorted Result");
for (int[] x : arr1) {
System.out.println(x[0] + " " + x[1]);
}
arr1 = arr;
Arrays.sort(arr1, (m, n) -> m[0] == n[0] ? m[1] - n[1] : m[0] - n[0]);
System.out.println("Sorted Result");
for (int[] x : arr1) {
System.out.println(x[0] + " " + x[1]);
}
}
}
class MultiDimArrayComparator implements Comparator<int[]> {
@Override
public int compare(int[] m, int[] n) {
return m[0] == n[0] ? m[1] - n[1] : m[0] - n[0];
}
}
Running the code
Conclusion
aws lambda handlers options
Aws lambda handlers
The aws-lambda-java-core library defines two interfaces for handler methods.
com.amazonaws.services.lambda.runtime.RequestHandler
com.amazonaws.services.lambda.runtime.RequestStreamHandler
Choosing the right handler
public interface RequestHandler {
/**
* Handles a Lambda Function request
* @param input The Lambda Function input
* @param context The Lambda execution environment context object.
* @return The Lambda Function output
*/
public O handleRequest(I input, Context context);
}
public interface RequestStreamHandler {
/**
* Handles a Lambda Function request
* @param input The Lambda Function input stream
* @param output The Lambda function output stream
* @param context The Lambda execution environment context object.
* @throws IOException
*/
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException;
}- RequestStreamHandler : If we need to customize the serialization and deserialization process then RequestStreamHandler is the choice.
- RequestHandler: It is the most suitable handler in most cases.
References
How to install Maven artifact with sources
How to download source for maven artifacts
1) How to generate source code for third-party artifacts that my project is using
mvn eclipse:eclipse -DdownloadSources=trueExecuting the following command from the terminal will download the sources for all the artifacts only, attaching the sources in the IDE with the binaries needed to be done seperately..mvn dependency:sources -Dsilent=true
mvn source:jar install
java.util.Random Example
Generating Random Number in Java
public static void generateRadom() {
System.out.println("\nPrinting 10 Random Numbers");
Random generator = new Random();
for (int i = 0; i < 5; i++) {
System.out.print(generator.nextInt() + " ");
}
}public static void generateRadomBounded() {
System.out.println("\nPrinting 5 Random Numbers Between 0 and 99");
Random generator = new Random();
for (int i = 0; i < 5; i++) {
System.out.print(generator.nextInt(100) + " ");
}
}public static void generateRadomWithSeed(long seed) {
System.out.println("\nPrinting 5 Random Numbers Between 0 and 99 with seed");
Random generator = new Random(seed);
for (int i = 0; i < 5; i++) {
System.out.print(generator.nextInt(100) + " ");
}
}- If we want to generate the same set of random numbers, we can set seed.
- Test cases can use seed to make sure it gets same set of random numbers.
- We can have bounded or unbounded random numbers.
Change Project Explorer tree view font size in Eclipse
Change Project Explorer tree view font size in Eclipse
Window > Preferences > General > Appearance > Colors and Fonts > View and Editor Folders > Tree and Table font for viewsremove version tracking from a project cloned from git
Remove Git from a Repo
.gitkeep: allows us to include an empty directory to be synced to git remote server
. gitattributes: allows us to ensure consistent git settings across the machine.
Essentially we need to delete all these git related folder/files that will make our repository clean and without any git version details. The following sections show how to achieve the same in a Windows environment and Mac environment
Windows
del /F /S /Q /A .git
rmdir .gitMac
rm -rf .git
rm -rf .gitkeep
rm -rf .gitignore
rm -rf .gitattributesfind . | grep -i .gitMicroservices Registration and Discovery using Spring Cloud and Eureka
Microservices Registration and Discovery using Spring Cloud, Eureka
This blog post walks through an implementation pattern and a working setup with multiple microservices where they get registered with Eureka and the client can discover them and invoke them.
What is Eureka
Eureka is a REST-based service that provides support for discovering other services so that clients can use the Eureka service to discover and call them.
Why we need Discovery Service
In a microservices architecture, each service typically runs on a different URL or IP address. Clients need a way to know when new microservices are added or existing ones go down for maintenance. Discovery service provides that mechanism—services register themselves, and clients query the discovery service to know available microservices.
Project Achievement
In this project, we will build:
- A Eureka Discovery Service
- An Article Microservice (CRUD operations)
- A Client Microservice (consumes the Article service)
Goal: invoke a target service without hardcoding URLs, IPs, or ports, by resolving via service discovery.
Technology Used
- Java 11
- Apache Maven 3.5.0
- Spring Boot 2.2.6
- Spring Cloud Hoxton.SR1
- Netflix Ribbon 2.3.0
- Open Feign
- JSON
Discovery Server
Add the Eureka Discovery Server dependency:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-server
application.properties:
server.port=8761
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true
Main Application:
@EnableEurekaServer
@SpringBootApplication
public class ServiceDiscovery {
public static void main(String[] args) {
SpringApplication.run(ServiceDiscovery.class, args);
}
}
Article Service
Add Eureka Client dependency:
org.springframework.cloud
spring-cloud-starter-netflix-eureka-client
application.properties:
server.port=9051
eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8761/eureka/
eureka.client.register-with-eureka=true
spring.application.name=article-service
Main Application:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class ArticleMicroservice {
public static void main(String args[]) {
SpringApplication.run(ArticleMicroservice.class, args);
}
}
REST Endpoints:
- GET /api/articles
- GET /api/articles/{id}
- POST /api/articles
- DELETE /api/articles/{id}
Sample Response
[
{
"id": "America-Travel",
"name": "America Travel",
"description": "Places to travel in America ...",
"category": "Travel"
}
]
Article Client Service
This is another Spring Boot service that discovers and calls the Article service using Ribbon/Feign.
Consumer Controller Example:
@RestController
public class RibbonController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "render", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> renderArticles() throws Exception {
JsonNode repos =
restTemplate.getForObject("http://article-service-consumer/api/articles", JsonNode.class);
...
}
}
Start Microservices
- Clone repo:
git clone https://github.com/siddharthagit/spring-boot-sdc - Run each service:
mvn spring-boot:run - Check discovery server: http://localhost:8761
- Call consumer service: http://localhost:9053/render
Conclusion
We demonstrated how to use Spring Cloud Eureka for service discovery. The client can invoke services without hardcoding addresses, relying on the discovery service to resolve them dynamically.





