1. Introduct to EzyHTTP

EzyHTTP (Easy going to HTTP Interaction) is a lightweight framework support to interact to HTTP, it includes both http server and http client.

2. Structure of ezyhttp-server

https://tvd12.com/wp-content/uploads/ezyhttp-structure.png

  1. When client request to server, Servlet receive the request first
  2. The request must pass through the list of interceptor before pass to controller
  3. The controller handle the request and return response to the Servlet
  4. If have any exceptions unprocessed by the Interceptor and the Controller, an ExcetionHandler will process that exception and return result to the Servlet
  5. After all the Servlet will send the response to client

3. Install EzyHTTP

To create a http server application we need add dependency

<dependency>
    <groupId>com.tvd12</groupId>
    <artifactId>ezyhttp-server-boot</artifactId>
    <version>0.0.6</version>
</dependency>

To use http cleint we need add dependency

<dependency>
    <groupId>com.tvd12</groupId>
    <artifactId>ezyhttp-client</artifactId>
    <version>0.0.6</version>
</dependency>

The latest version can be found in the Maven Central repository.

4. Create an http server example

Let’s say we need create an http server application to manage user, we need 2 apis:

  • api/v1/users/add: Add user to system
  • api/v1/users/{username}: Get user by name

Firstly, we need create a maven project with

  • name: user-management-application
  • package: com.example.user_management
  • java version: 1.8

Next, we need add ezyhttp-server-boot dependency We use lombok to generate getter, setter, contructor so you need install and add lombok dependency to pom.xml

4.1 Create the application entry point class

package com.example.user_management;
import com.tvd12.ezyhttp.core.boot.EzyHttpApplicationBootstrap;
import com.tvd12.ezyhttp.server.core.asm.RequestHandlerImplementer;

public class App {

    public static void main(String[] args) throws Exception {
        RequestHandlerImplementer.setDebug(true);
        EzyHttpApplicationBootstrap.start(App.class);
    }

}

4.2 Create User class to keep user information

package com.example.user_management.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class User {

    protected String username;
    protected String password;

}

4.3 Create UserService class to manage user information

package com.example.user_management.service;

import com.example.user_management.entity.User;
import com.tvd12.ezyfox.bean.annotation.EzySingleton;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@EzySingleton
public class UserService {

    protected final Map<String, User> users = new ConcurrentHashMap<>();

    public User addUser(User user) {
        return users.put(user.getUsername(), user);
    }

    public User getUser(String username) {
        return users.get(username);
    }

}

4.4 Create UserController class to handle request from client

package com.example.user_management.controller;

import com.example.user_management.entity.User;
import com.example.user_management.service.UserService;
import com.tvd12.ezyfox.bean.annotation.EzyAutoBind;
import com.tvd12.ezyhttp.core.exception.HttpConflictException;
import com.tvd12.ezyhttp.core.exception.HttpNotFoundException;
import com.tvd12.ezyhttp.core.response.ResponseEntity;
import com.tvd12.ezyhttp.server.core.annotation.*;
import lombok.Setter;

@Setter
@Controller("/api/v1/users")
public class UserController {

    @EzyAutoBind
    protected UserService userService;

    @DoPost("/add")
    public ResponseEntity addUser(@RequestBody User user) {
        User existed = userService.addUser(user);
        if(existed == null)
            return ResponseEntity.ok(Boolean.TRUE);
        throw new HttpConflictException("user: " + user.getUsername() + " existed");
    }

    @DoGet("/{username}")
    public User getUser(@PathVariable("username") String username) {
        User user = userService.getUser(username);
        if(user != null)
            return user;
        throw new HttpNotFoundException("user: " + username + " not found");
    }

}

4.5 Create log4j.properties file in src/resources folder

The log4j.properties's content:

# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

Ok, we done all, let’s start main class ‘App’ and great! We’ve had a http server application

4.6 Let’s take a test on postman

With api: /api/v1/users/add we have

https://tvd12.com/wp-content/uploads/add_user.png

With api: /api/v1/users/{username} we have:

https://tvd12.com/wp-content/uploads/get_user.png

Awesome! Everything ok.

5. Create a client example

With client, we have 2 way (2 class) to call http request

  • HttpClient: A simple http client, it simply open a connection, send the request and return the response, it only supports sync method
  • HttpClientProxy: It use HttpClient class to send the request, but every request will add to a queue, and we need config number of threads to process this queue. It supports both sync and async method Firstly, we need add ezyhttp-client dependency to maven Next, create a test package with name: com.example.user_management.test in src/test/java folder To test /api/v1/users/add api, we need create a class ApiAddUserTest with content:
package com.example.user_management.test;

import com.example.user_management.entity.User;
import com.tvd12.ezyhttp.client.HttpClient;
import com.tvd12.ezyhttp.client.request.PostRequest;
import com.tvd12.ezyhttp.client.request.Request;
import com.tvd12.ezyhttp.client.request.RequestEntity;
import com.tvd12.ezyhttp.core.constant.StatusCodes;

public class ApiAddUserTest {

    public static void main(String[] args) throws Exception {
        HttpClient httpClient = HttpClient.builder()
                .build();
        User body = new User();
        body.setUsername("dev");
        body.setPassword("123456");
        RequestEntity entity = RequestEntity.body(body);
        Request request = new PostRequest()
                .setURL("http://localhost:8080/api/v1/users/add")
                .setEntity(entity)
                .setResponseType(Boolean.class)
                .setResponseType(StatusCodes.CONFLICT, String.class);
        Boolean reponse = httpClient.call(request);
        System.out.println("add user reponse: " + reponse);
    }

}

And we get output: add user reponse: true To test /api/v1/users/users/{username} api, we need create a class ApiAddUserTest with content:

package com.example.user_management.test;

import com.tvd12.ezyhttp.client.HttpClientProxy;
import com.tvd12.ezyhttp.client.request.GetRequest;
import com.tvd12.ezyhttp.client.request.Request;
import com.tvd12.ezyhttp.client.request.RequestEntity;
import com.tvd12.ezyhttp.core.constant.StatusCodes;

public class ApiGetUserTest {

    public static void main(String[] args) throws Exception {
        HttpClientProxy httpClient = HttpClientProxy.builder()
                .build();
        httpClient.start();
        RequestEntity entity = RequestEntity.builder().build();
        Request helloRequest = new GetRequest()
                .setURL("http://localhost:8080/api/v1/users/dev")
                .setEntity(entity)
                .setResponseType(String.class)
                .setResponseType(StatusCodes.NOT_FOUND, String.class);
        String reponse = httpClient.call(helloRequest, 10000);
        System.out.println("get user reponse: " + reponse);
    }

}

And get get output: get user reponse:

{"username":"dev","password":"123456"}

6. Conclusion

With EzyHTTP everything are simple, you don’t need care about HttpServlet, HttpRequest, HttpResponse, how to serialize/deserialize request/response and bean management, with the IOC EzyHTTP will care for you