Auto generate HTTP REST classes for interfaces.
- Java 8
- Spring 4
- Spring Cloud
- Add
@EnableMicroserviceCommunicator
to any @Configuration class. Optionally setbasePackages
orbasePackages
from@ComponentScan
will be used - Create interface, for example
@Microservice("test-microservice") // test-microservice is id in service discovery
public interface MicroserviceUsersRepository {
// HTTP GET - default, you can leave it
@MicroMapping(path = "/domain/users/mock/one", method = HttpMethod.GET)
UserAccount returnSingleObject();
@MicroMapping("/domain/users/mock/null")
UserAccount returnNullBodyResponse();
@MicroMapping("/domain/users/mock/null")
ResponseEntity<UserAccount> returnNonNullBodyResponse();
@MicroMapping("/domain/users/mock")
List<UserAccount> returnGenericList();
@MicroMapping("/domain/users/mock/one")
ResponseEntity<UserAccount> returnGenericResponseEntity();
// russian special language
// equals to findAllUsersInDomainMock() - GET /domain/users/mock
@MicroMapping
List<UserAccount> построитьПолучитьМестоDomainГдеUsersГдеMock();
// in tests url will be /domain/users/mock/one
@MicroMapping("/domain/{s1}/{s2}/one")
UserAccount returnSingleObjectWithPathParam(@MicroPathVar("s1") String s,
@MicroPathVar("s2") String s2);
@MicroMapping("/domain/users/mock/one")
JsonNode returnJson();
@MicroMapping(path = "/domain/users/mock/one", convertResponseToMap = true)
Map<String, Object> returnResponseAsJsonMap();
@MicroMapping("/domain/users/mock/send_invalid_request")
ResponseEntity<UserAccount> returnInvalidResponse();
@MicroMapping("/domain/users/mock/send_invalid_request")
UserAccount returnInvalidResponseException();
// this endpoint simulate server error
// will be 3 attempts (by default) to try again with interval (default 1100ms)
@MicroMapping("/domain/users/mock/generate_500_http_error")
UserAccount returnInvalidServerException();
@MicroMapping("/domain/users/mock/generate_500_http_error")
ResponseEntity<UserAccount> returnInvalidServerExceptionEntity();
@MicroMapping(path = "/domain/users/mock/authenticate", method = HttpMethod.POST)
UserAccount returnAuthenticatedUser(@MicroPayloadVar("username") String username,
@MicroPayloadVar("password") String password);
// will be POST json
// {
// "username": %username%,
// "password": %password%,
// "address" : {
// "country": %country%,
// "city": %city%
// }
// }
// %username% etc... will be replaced by java function param
@MicroMapping(path = "/domain/users/mock/echo", method = HttpMethod.POST)
UserAccount returnAuthenticatedUserComplexEcho(@MicroPayloadVar("username") String username,
@MicroPayloadVar("password") String password,
@MicroPayloadVar("address.country") String country,
@MicroPayloadVar("address.city") String city);
@MicroMapping(path = "/domain/users/mock/echo", method = HttpMethod.POST)
byte[] returnByteArrayEcho(@MicroPayloadVar("username") String username,
@MicroPayloadVar("password") String password,
@MicroPayloadVar("address.country") String country,
@MicroPayloadVar("address.city") String city);
// use java 8 with javac -parameters to add parameter name and use as json node name
// instead of annotation value with dot(.) delimiter - in parameter name - is decimeter
@MicroMapping(path = "/domain/users/mock/echo", method = HttpMethod.POST)
UserAccount returnPayloadFromName(@MicroPayloadVar String username,
@MicroPayloadVar String password,
@MicroPayloadVar String address_country,
@MicroPayloadVar String address_city);
// from server we will get json like that {username: ... , address :{city: "SomeString" } }
// so, if we are interesting only in city field, we can immediately return it, instead of all server return data
@MicroMapping(path = "/domain/users/mock/echo", method = HttpMethod.POST, returnExpression = "address.city")
String returnJsonExpression(@MicroPayloadVar String username,
@MicroPayloadVar String password,
@MicroPayloadVar String address_country,
@MicroPayloadVar String address_city);
@MicroMapping("/domain/users/mock/one")
CompletableFuture<UserAccount> returnCompletableFutureSingleObject();
@MicroMapping("/domain/users/mock")
CompletableFuture<List<UserAccount>> returnListCompletableFutureObjects();
@MicroMapping("/domain/users/mock/one")
Optional<UserAccount> returnSingleOptionalObject();
@MicroMapping("/domain/users/mock")
Optional<List<UserAccount>> returnListOptionalObject();
@MicroMapping("/domain/users/mock/null")
Optional<UserAccount> returnSingleOptionalEmptyObject();
@MicroMapping("/domain/users/mock/authorization_header")
JsonNode sendAuthHeaderInEcho(@MicroHeader("Authorization") String authHeader);
// default will be executed on error main request
@MicroMapping("/domain/users/mock/generate_500_http_error")
default UserAccount returnDefaultValue() {
return new UserAccount("I'm default Java 8 interface");
}
// default will be executed on error main request
@MicroMapping("/domain/users/mock/generate_500_http_error")
default UserAccount returnDefaultValue(String name) {
return new UserAccount(name);
}
}
- Inject
MicroserviceUsersRepositoryTest
to any bean
@Service
public class UsersRepository {
@Autowired
private MicroserviceUsersRepository microserviceUsersRepository;
public void testReturnGenericList(){
List<UserAccount> allUsers = microserviceUsersRepository.returnGenericList();
}
}
To use this extension on Maven-based projects, use following dependency:
<dependency>
<groupId>com.biqasoft</groupId>
<artifactId>microservice-communicator</artifactId>
<version>1.2.13-RELEASE</version>
</dependency>
- CompletableFuture<> - async execute request
- Any your Data object (DTO), will be deserialize with Jackson; supported return
List<SomeClass>
- ResponseEntity<> - spring MVC object, with headers, response code, response body
- JsonNode - if you do not want to map response to some object
- Optional<>
Internally, library use spring bean LoadBalancerClient
with default implementation of spring cloud RibbonLoadBalancerClient
. So, you can use Consul, Zookeeper, Cloudfoundry.
if you have not configured service discovery in Spring Cloud, you can do it easily, for example for consul create configuration bean
@EnableDiscoveryClient
@Configuration
public class ServiceDiscoveryConfiguration {
@Value("${spring.cloud.consul.host}")
private String serverUrl;
@Bean
public ConsulClient consulClient(){
ConsulClient client = new ConsulClient( serverUrl );
return client;
}
}
- demo server, used for tests
- MicroserviceUsersRepositoryTest - test interface usage
- usage by another project
If you have return type ResponseEntity
you will never have exceptions from method. For example with responseEntity.getStatusCode().is2xxSuccessful()
.
Also, you have access to headers and body with responseEntity.getHeaders()
and responseEntity.getBody()
If you have return type some object (not ResponseEntity) following unchecked exceptions can be thrown:
InvalidRequestException
this exceptions is throws if remote host set HTTP status 422 (Unprocessable Entity), 401, 403. When we recieve such response, we immedialty throw exception, without trying new requests to another microservicesInternalSeverErrorProcessingRequestException
if we have non 422, 401, 403 response code, can not find suitable microservice URL in service discovery predetermined number of time, or can not retry request to microservices predetermined number of times(on error)
Spring 4.3 requires to add custom VM option to run -addmods java.xml.bind
,
optionally you can use -ea -XaddExports:java.base/jdk.internal.loader=ALL-UNNAMED -addmods java.xml.bind
Jackson is used to serialize/deserialize json. So, you can customize ObjectMapper bean, by injected it with @Qualifier("defaultObjectMapperConfiguration")
Copyright © 2016 Nikita Bakaev. Licensed under the Apache License.