Thursday, August 20, 2020

How to use Redis caching server with Spring Boot.

Firstly, I would like to explain about the advantage about cacheing.


When we use RESTFull applicatoin, most of the time, we are using token (Ex: JWT) base authentication/authorization. Since we are using token base authentication/authorization, we don't cross check the user infomation with the database. Therefore, if somebody copy the token and logout from the system, still, if he/she knows the API details, they can invoke the APIs (Using Postman, curl or similer tools). It is very unsecure, so, better to keep the token information somewhere, we can access the inforation very quickly and easily, then we can validate service invokation whether is it valid or not.

In this article I'm going to describe, how to conect and use Redis server in Spring Boot application.

Steps:

1. Start the Redis server. For this explanation I'm going to use the docker.

 docker run -p 6379:6379 --name redis -v redis.conf:/usr/local/etc/redis/redis.conf -d --memory 100m redis


2. Then we need to add below dependency for the project

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>


Here I'm going to use jedis client.

3. Enable caching

import org.springframework.cache.annotation.EnableCaching;

@SpringBootApplication
@EnableCaching
public class TestApplication {
    ....
}


4. Redis cache repository

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.util.concurrent.TimeUnit;

@Repository
public class RedisCacheRepository {
    private HashOperations hashOperations;
    private RedisTemplate redisTemplate;

    private final Logger logger = LoggerFactory.getLogger(RedisCacheRepository.class);

    private long tokenValidity = 180000;

    public RedisCacheRepository(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
        this.hashOperations = this.redisTemplate.opsForHash();
    }

    public void save(String tokenId) {
        try {
            hashOperations.put("USERS", tokenId, tokenId);
            redisTemplate.expire("USERS", tokenValidity, TimeUnit.MILLISECONDS);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
    }
    
    public boolean findById(String tokenId) {
        boolean activeUser = false;
        try {
            activeUser = hashOperations.get("USERS", tokenId) != null;
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
        return activeUser;
    }

    public void delete(String tokenId) {
        try {
            hashOperations.delete("USERS", tokenId);
        } catch (Exception ex) {
            logger.error(ex.getMessage());
        }
    }
}


Above data is just for explain purpose only.
I have added token validity period (tokenValidity), because, if user ideal and/or doesn't logout properly, we cannot delete the login info from the cache. Therefore, we can add a expire time as above.

Wednesday, February 12, 2020

Feign Client - Spring Boot (Microservice) inter service call

In this article I'm planing to explain the way we can implement Feign Client to invoke inter service call.

We have eurekaServer, zuulServer, clientServer, serverServer. Initially, we need to register our all servers with the eurekaServer.
zuulServer register as proxyService
clientServer register as oneService
serverServer register as twoService
twoService has a end-point as below:
 http method: POST

 url: /api/person/{personId}/bank

1st of all, we need to add dependency to the application. In this example I'm going to use maven dependency as below.
<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-feign</artifactId>
      <version>#{feign.version}</version>
</dependency>

According to the above end-point, we need to implement the feign-client as below
 @FeignClient(name = "twoservice", path = "/api",
        fallback = TwoServiceFallBack.class,
        configuration = DefaultFeignConfig.class)
public interface TwoServiceClient {

    @RequestMapping(path = "/person/{personId}/bank", method = RequestMethod.POST)
    CustomResponseMessage addBankInfo(@PathVariable("personId") String personId, @RequestBody BankDTO bankDTO);

}

And also fall-back class below (when calling the service, if something happen, you can handle the situation here).
@Component
public class TwoServiceClientFallBack implements TwoServiceClient {

    @Override
    public CustomResponseMessage addBankInfo(String personId, BankDTO bankDTO) {
     //
        return null;
    }
}

CustomResponseMessage -> response payload.
BankDTO -> request body

Hope this will helpful.