1. The background
Because of the business relationship, there are many different third-party companies to connect with. Each of these providers provides AN HTTP-based API. But the exact details of the API provided by each company vary greatly. Some are based on RESTFUL specifications, some are based on traditional HTTP specifications; Some require a signature in the header, some require SSL bidirectional authentication, and some require ONLY SSL unidirectional authentication. Some serialize in JSON mode, others in XML mode. There are too many differences in details like this.
It’s normal for different companies to have different API specifications. But for me, if I want my code to be elegant. I had to deal with one pain point:
How can you maintain a common suite of non-business HTTP calls with so many differences in the apis of different providers? It is best to distinguish them by configuration or simple parameters. Make a convenient call?
I certainly know that there are many excellent and well-known HTTP open source frameworks that can implement any kind of HTTP call, and I have used them in my years of development experience. For example, apache’s httpClient package, the excellent Okhttp, Jersey Client.
The interfaces of these HTTP open source frameworks are relatively different. Either way, in my scenario, I don’t want to write a bunch of HTTP calling code for every third party’S HTTP API.
So, in this scenario, I had to encapsulate each of the different HTTP apis. The code is more elegant, and the business code is less coupled to the HTTP invocation logic.
Unfortunately, I’m lazy. Both because encapsulation is time-consuming and because encapsulation of this underlying HTTP call is a better option. I don’t want to build a wheel myself.
As a result, I found a great open source HTTP framework that masked all the differences caused by the different details of the HTTP API. Extremely complex HTTP calls can be made with simple configuration just like the RPC framework.
Forest
Gitee.com/dt_flys/for…
2. Get started
Forest supports Springboot autowunning, so you only need to introduce one dependency
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>spring-boot-starter-forest</artifactId>
<version>1.3.0</version>
</dependency>
Copy the code
Define your own interface class
public interface MyClient {
@Request(url = "http://baidu.com")
String simpleRequest(a);
@Request(
url = "http://ditu.amap.com/service/regeo",
dataType = "json"
)
Map getLocation(@DataParam("longitude") String longitude, @DataParam("latitude") String latitude);
}
Copy the code
Configure the scan package of the proxy interface class in the startup class
@SpringBootApplication
@ForestScan(basePackages = "com.example.demo.forest")
public class DemoApplication {
public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); }}Copy the code
At this point, you can inject your proxy interface from the Spring container to call the HTTP API as if it were a native method
@Autowired
private MyClient myClient;
@Override
public void yourMethod throws Exception {
Map result = myClient.getLocation("124.730329"."31.463683");
System.out.println(JSON.toJSONString(result,true));
}
Copy the code
Log printing, Forest prints the INTERNAL HTTP framework used, and the actual request URL and return. Of course logging can be configured to control the switch.
Characteristics of 3.
I think this open source framework is a great way to improve your productivity, especially if you’re working with third-party apis.
Forest encapsulates two different HTTP frameworks: Apache httpClient and OKhttp. So the open source framework doesn’t reinvent the wheel on the underlying implementation, but focuses on ease of use.
I ended up using Forest for a project that interacted with a number of service provider apis, all of which were very different, and I converted them into local methods in about an hour. Then the project went live.
Forest is a higher-level HTTP framework, and you don’t need to write a lot of code. Most of the time, you can make localized HTTP calls with just a few configurations. This framework can cover a wide range of areas, but the vast majority of your HTTP calls.
Forests have the following characteristics:
- In order to
Httpclient
andOkHttp
Is for the back-end framework - By calling local methods to send Http requests, the business logic and THE Http protocol are decoupled
- Compared to Feign, it is lighter weight and does not rely on
Spring Cloud
And any registry - Support all request methods:
GET
.HEAD
.OPTIONS
.TRACE
.POST
.DELETE
.PUT
.PATCH
- Flexible template expressions are supported
- Supports filters to filter incoming data
- Defined in an annotated, configurable manner
Http
request - support
Spring
andSpringboot
integration - implementation
JSON
andXML
Serialization and deserialization of - Support JSON conversion framework:
Fastjson
.Jackson
.Gson
- support
JAXB
In the form ofXML
conversion - support
SSL
Unidirectional and bidirectional encryption - Supports HTTP connection pooling
- Can be achieved by
OnSuccess
andOnError
The interface parameter implements a callback to the result of the request - The configuration is simple and generally requires only
@Request
A single annotation completes the definition of most requests - Support for asynchronous request invocation
4. Two great features
The usage and configuration methods are not described here, but you can read the detailed documentation if you are interested:
https://dt_flys.gitee.io/forest
I want to analyze just two features of the framework that I think are good
4.1 Mapping binding for template expressions and parameters
Template expressions are especially handy when you use them, for example
@Request(
url = "${0}/send? un=${1}&pw=${2}&ph=${3}&ct=${4}",
type = "get",
dataType = "json"
)
public Map send( String base, String userName, String password, String phone, String content );
Copy the code
The above values are measured by serial number subscript, or by name:
@Request(
url = "${base}/send? un=${un}&pw=${pw}&ph=${3}&ct=${ct}",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataVariable("un") String userName,
@DataVariable("pw") String password,
@DataVariable("ph") String phone,
@DataVariable("ct") String content
);
Copy the code
It can even be simplified like this:
@Request(
url = "${base}/send",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataParam("un") String userName,
@DataParam("pw") String password,
@DataParam("ph") String phone,
@DataParam("ct") String content
);
Copy the code
These three ways of writing are equivalent
Of course, you can also bind parameters to header and body, and you can even serialize objects to JSON or XML simply by using expressions:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
headers = {"Authorization: ${1}"},
data = "${json($0)}"
)
public PayResponse pay(PayRequest request, String auth);
Copy the code
Of course, please refer to the documentation for details on data binding
4.2 toHTTPS
The support of
Dealing with HTTPS with other HTTP frameworks has always been a hassle, especially with bidirectional certificates. Every time I encounter problems, I can only go to Baidu. Then modify your own code based on the experience of others.
Forest is also thoughtful in this regard, and the underlying layer perfectly encapsulates support for HTTPS singleway and bidirectional certificates. It can be done quickly with simple configuration. Take a two-way certificate for example:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
keyStore = "pay-keystore",
data = "${json($0)}"
)
public PayResponse pay(PayRequest request);
Copy the code
Where the pay-keystore corresponds to the SSL-key-stores in application.yml
forest:
.
ssl-key-stores:
- id: pay-keystore
file: test.keystore
keystore-pass: 123456
cert-pass: 123456
protocols: SSLv3
Copy the code
So if you do that, it’s ok, and all you have left is a call in the form of native code.
5. The last
Forest has many other features, if you are interested, please read the documentation and examples carefully.
But I want to say, I’m sure a lot of people are looking at this and saying, isn’t that Feign?
I also used Feign for a while while working on the Spring Cloud project and personally felt that Forest was similar to Feign’s design in terms of configuration and usage, but Feign’s role was more as a member of the Spring Cloud ecosystem. As the role of RPC communication, it is not only responsible for HTTP communication, but also for the load balancing of the call address delivered by the registry.
Forest, an open source project, is positioned as a high-level HTTP tool that is friendly and easy to use. From the point of view of use, the personal sense of Forest configuration is more simple and direct. Many of the features on offer also address pain points for many people.
Open source spirit is valuable, good open source needs everyone’s building blocks and support. Hopefully, this article will give you a new choice when choosing an HTTP client framework: Forest
Contact the author
Wechat follow Jishuyuanren for more technical dry goods