JHIpster is great, like xdoclet (remember it?) on steroids and it allows you to get your applications runnung fast. All the basic stuff. But it is not always clear how to do other things when you need them. I hat to mate 2 microservices. Here is how it can be done
JH generates all the basic CRUD for you, and also rest services to do this - but sometimes you need more, and you can not declare this in JDL. Here is step by step guide how ot do this.
We assume that you already have generated jhipster applications, and are using gradle as build tool
Define target service
If you have activated in your .yo-rc.json like this:
"enableSwaggerCodegen": true,
(if not yet, activate and run jhipster again)
Then there shall be openapi declaration file located at src/main/resources/swagger/api.yml looking like this:
# API-first development with OpenAPI
# This file will be used at compile time to generate Spring-MVC endpoint stubs using openapi-generator
openapi: '3.0.1'
info:
title: 'adapter'
version: 0.0.1
servers:
- url: http://localhost:8082/api
description: Development server
- url: https://localhost:8082/api
description: Development server with TLS Profile
paths: {}
components:
responses:
Problem:
description: error occurred - see status code and problem object for more information.
content:
'application/problem+json':
schema:
$ref: 'https://opensource.zalando.com/problem/schema.yaml#/Problem'
securitySchemes:
jwt:
type: http
description: JWT Authentication
scheme: bearer
bearerFormat: JWT
security:
- jwt: []
This is the place where you define your rest interface ( out of scope of this article, there are countless tools and editors to help you do this). Once interface is defined, next build will automatically generate server stubs via gradle task openApiGenerate. You will find the generated sources under build/openapi/src/main/java/ - and if you are using InteliJ it will be already on your source path. Now you are only a step away from implementing your service - just implement <YourCooleServiceName>Delegate interface, and mark the class with @Component annotation.
Now you have implemented service.
Implementing Client code
And now we need client. Just invoke:
jhipster openapi-client
Provide path to target service source directory, and now you will have a client code generated in a package <base package>>client/. You will find there service interfaces (just autowire them to your spring beans):
public class Caller {
private static final Logger log = LoggerFactory.getLogger(Caller.class);
private final DefaultApiClient callCient;
private final TokenProvider tokenProvider;
public Caller(DefaultApiClient callCient, TokenProvider tokenProvider) {
this.callCient = callCient;
this.tokenProvider = tokenProvider;
}
All the feign infrastructure is to your disposal. If your context is authenticated with JWT everything shall work out of the box.
Tweaking JWT authentication
In my use case I do not have prior external call, so I need to set up JWT token myself before calling methods on client interface:
// create JWT token, password is not important in this context
String jwtToken = tokenProvider.createToken(
new UsernamePasswordAuthenticationToken("foobar", "", Arrays.asList(new SimpleGrantedAuthority("ADMIN"))),
true
);
// and now authentication object
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken("foobar", jwtToken);
// insert it into security context
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
ResponseEntity<Void> responseEntity = callCient.create(new InlineObject().callerId("foo bar " + System.currentTimeMillis()));
Like that.
It is important that both sides share the same JWT secret (if you are using jhipster gateway and registry it is automatic, if not - store it in respective properties)