Jhipster Beyond CRUD
API First for Enterprise
2 7 / 0 6 / 2 0 1 9 - I N T E S Y S
This material has been prepared by personnel of Intesys S.r.l. and is provided on a confidential basis.
All the materials, animations, graphics and concepts may not be used, reproduced, redistributed or transmitted, in whole or in part, without prior written permission from the owner. Any unauthorized use is strictly prohibited.
W H O A R E W E ?
Who we are
Paolo Quaglia
senior project manager
and software architect - @p_quail
Enrico Costanzi
senior software developer - @enricocostanzi
W H O A R E W E ?
Italian 100 employees company
Enterprise industry: Banks, insurance companies,
manufacturing
Our Development Pattern: Design to Deliver
W H O A R E W E ?
• We started with Jhipster in 2017
• 3rd Jhipster Bronze Sponsor
• ~10 developers on average working with Jhipster
• 5 projects running in production
• 3 big project in Development phase
• 2 Jhipster modules published
• More modules/blueprints – work in progress
• Some contributions to the main generator
Intesys & Jhipster
How we started
I N T E S Y S & J H I P S T E R
2017
I N T E S Y S & J H I P S T E R
2017 • Angular Monolith (Single Node)
• Jhipster 4.10.1
• 12 entities
• ~200 users
• No swagger endpoints
• 3 Roles
• No native queries
• Local Cache
• 2 dev teams involved
I N T E S Y S & J H I P S T E R
2019 • React Monolith (multiple nodes)
• Jhipster 5.8.2
• 120 entities (2 JDL files)
• ~4000 users
• 100 OpenAPI endpoints
• 7 roles
• Many native queries
• Distributed cache
• 5 dev teams involved
API Driven Enterprise
A P I D R I V E N E N T E R P R I S E
Enterprise Systems
(SAP, AS400,
TIBCO, API
Gateways)
Legacy databases
A G E N D A
• Why Beyond CRUD?
• Code First Jhipster
• API First Jhipster
• Modules Demo
• Testcontainers & Jhipster
Agenda
Why Beyond CRUD?
B E Y O N D C R U D
UserJWTController
AccountResource
UserResource
Entity1Resource Entity1Service Entity1Repository
Entity1ResourceExt Entity1ServiceExt Entity1RepoExt
CustomController1
UserService UserRepository
CustomService1
CustomController2 CustomService2
UserResourceExt UserServiceExt
How do I make life easy for API
consumers?
B E Y O N D C R U D
• Interoperability
• Productivity
• User Experience (UX)
• Developer Experience (DX)
We need
Code First Jhipster
C O D E F I R S T J H I P S T E R
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
Swagger UI & Springfox
/v2/api-docs
Some Customizations
C O D E F I R S T J H I P S T E R
Split your Swagger specs
/v2/api-docs?group=auth
/v2/api-docs?group=admin
/v2/api-docs
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
C O D E F I R S T J H I P S T E R
Split your Swagger specs
/v2/api-docs?group=auth
/v2/api-docs?group=admin
/v2/api-docs
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
@Bean
public Docket authDocket() {
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.groupName("auth")
.forCodeGeneration(true)
.directModelSubstitute(java.nio.ByteBuffer.class, String.class)
.directModelSubstitute(URI.class, String.class)
.directModelSubstitute(StatusType.class, Integer.class)
.genericModelSubstitutes(ResponseEntity.class)
.additionalModels(typeResolver.resolve(Problem.class))
.select()
.paths(Predicates.or(
regex("/api/account.*"), regex("/api/authenticate.*"),
regex("/api/activate.*"), regex("/api/register.*"))
)
.build();
return docket;
}
C O D E F I R S T J H I P S T E R
Export your Swagger specs
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
account-spec.json
default-spec.json
account-spec.json
C O D E F I R S T J H I P S T E R
Export your Swagger specs
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
account-spec.json
default-spec.json
account-spec.json
@SpringBootTest(classes = JhipetstoreApp.class)
@ActiveProfiles(value = {JHipsterConstants.SPRING_PROFILE_SWAGGER})
public class OpenApiSpecGeneratorIT {
@Autowired DocumentationCache documentationCache;
@Autowired ServiceModelToSwagger2Mapper mapper;
@Autowired JsonSerializer jsonSerializer;
@Test
void createOpenApiJsonSpec() throws IOException {
for (Map.Entry<String, Documentation> documentationEntry : documentationCache.all().entrySet()) {
String groupName = documentationEntry.getKey();
Documentation documentation = documentationEntry.getValue();
Swagger swagger = mapper.mapDocumentation(documentation);
Json spec = jsonSerializer.toJson(swagger);
File specsDir = new File("target/swagger-specs");
if (!specsDir.exists()) specsDir.mkdirs();
IOUtils.write(spec.value().getBytes(), new FileOutputStream("target/swagger-specs/”
+ groupName + «-spec.json"));
}
}
}
C O D E F I R S T - C O N T R A C T D R I V E N C O M M U N I C A T I O N
UserJWTController
AccountResource
UserResource
Entity1Resource Entity1Service Entity1Repository
Entity1ResourceExt Entity1ServiceExt Entity1RepoExt
CustomController1
UserService UserRepository
CustomService1
CustomController2 CustomService2
UserResourceExt UserServiceExt
B E Y O N D C R U D
Code First
• API Consumers must wait for specs to be
exposed or exported
• Only Swagger v2 support (OpenAPI 3
generation is WIP)
• Springfox scanning is slow with lots of
controllers
• Security rules must be coded in dockets
API First Jhipster
A P I F I R S T J H I P S T E R
API First
• Design
• API Design before writing code
• Interoperability
• Helps detecting breaking changes
• Developer Experience
• Decoupling client/server development
• Developers contribute to API definition
• Approval process during API design
• User Experience
• API design with UX/UI in mind
27
A P I F I R S T J H I P S T E R
Server side code generation from swagger / openapi specifications
ReadPetsApi
ReadPetApiDelegate
API First Jhipster
src/main/resources/swagger/api.yml
ReadPetsApiDelegateImpl
ReadPetsApiController
A P I F I R S T
modelNameSuffix: avoid DTOS
with the same class name:
• PetDTO (Jhipster)
• PetApiDto (OpenAPI DTO)
useTags: Groups the OpenAPI
endpoints by tag (not by path
prefix)
OpenAPI Generator Configuration
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>${openapi-generator-maven-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>…/resources/swagger/api.yml</inputSpec>
<generatorName>spring</generatorName>
…
<modelNameSuffix>ApiDTO</modelNameSuffix>
<configOptions>
<delegatePattern>true</delegatePattern>
<title>jhipetstore</title>
<useTags>true</useTags>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
C O D E F I R S T A N D A P I F I R S T
What changed?
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
CustomController1
CustomController2
UserResourceExt
OpenAPIController1
OpenAPIController2
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
UserResourceExt
C O D E F I R S T A N D A P I F I R S T
UserJWTController
AccountResource
UserResource
Entity1Resource Entity1Service Entity1Repository
Entity1ResourceExt Entity1ServiceExt Entity1RepoExt
UserService UserRepository
CustomAPIService1
UserResourceExt UserServiceExt
OpenAPIController1
OpenAPIController2 CustomAPIService2
JDL
Code First
API First
C O D E F I R S T A N D A P I F I R S T
Jhipster Frontend
OpenAPIController1
OpenAPIController2
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
UserResourceExt
JDL APIs:
• Jhipster CRUD
• Jhipster Administration
• Customizations
API First Endpoints
(generated client SDK):
• Custom Pages
• Design First
C O D E F I R S T A N D A P I F I R S T
External Apps – API + Code First
OpenAPIController1
OpenAPIController2
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
UserResourceExt
External Backend Applications
Mobile Apps
Custom Single Page Applications
C O D E F I R S T A N D A P I F I R S T
External Apps – API First only
OpenAPIController1
OpenAPIController2
UserJWTController
AccountResource
UserResource
Entity1Resource
Entity1ResourceExt
UserResourceExt
External Backend Applications
Mobile Apps
Custom Single Page Applications
A P I F I R S T
• Code duplication
• Jhipster DTOs ~= OpenAPI DTOs
• Basic CRUD Operations have to be rewritten in the spec
• Metamodel Filtering and pagination (coded in the spec)
• Authentication (duplicated endpoints in some cases)
API First Limitations
Demo
D E M O
Customizing Using Modules
OpenAPIController1
OpenAPIController2
OpenAPIController1
OpenAPIController2
Generated by OpenAPI Generator
Generated by
Springfox
Designed specs
Designed specs
• api.yml served statically (not generated by Springfox)
by a dedicated endpoint
• Replaces Swagger UI 2 with Swagger UI 3 (iframe)
• API version tag published in consul or Jhipster registry
D E M O
• Jhipster submodule to generate client code from swagger/openapi
specifications
• Integration of generator-jhipster-swagger-cli in the main generator
• Wraps the official npm module openapi-generator-cli
• Supports backend client generation (Feign clients)
• Future steps: generate client code for Angular / React
Jhipster OpenAPI Client (Preview)
$ jhipster openapi-client
Testcontainers & Jhipster
T E S T C O N T A I N E R S
Testcontainers
“Testcontainers is a Java library that
supports JUnit tests, providing
lightweight, throwaway instances of
common databases, Selenium web
browsers, or anything else that can run
in a Docker container”
Jhipster Integration Tests
• Native SQL Queries & Functions
• Liquibase changelogs
T E S T C O N T A I N E R S
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<version>1.11.3</version>
<scope>test</scope>
</dependency>
The easy way
jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore
org.testcontainers.jdbc.ContainerDatabaseDriver
1. add dependency
2. change test properties
3. ./mvnw verify
4. DONE! ☺
T E S T C O N T A I N E R S
The custom way
jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore
org.testcontainers.jdbc.ContainerDatabaseDriver
@TestConfiguration
@Profile("testcontainers")
public class IntegrationTestsConfiguration {
@Bean
public DataSource dataSource() {
dbContainer =
new MSSQLServerContainer("my-docker-account/mssql-server-custom:latest")
.withPassword("yourStrong(!)Password");
dbContainer.start(); //starts the container
String jdbcUrl = dbContainer.getJdbcUrl();
logger.info("Database started, creating datasource for url: '{}'", jdbcUrl);
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUsername(dbContainer.getUsername());
dataSource.setPassword(dbContainer.getPassword());
dataSource.setDriverClassName(dbContainer.getDriverClassName());
dataSource.setAutoCommit(false);
return dataSource;
}
generator-jhipster-testcontainers
T E S T C O N T A I N E R S
The custom way
jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore
org.testcontainers.jdbc.ContainerDatabaseDriver
@TestConfiguration
@Profile("testcontainers")
public class IntegrationTestsConfiguration {
@Bean
public DataSource dataSource() {
dbContainer =
new MSSQLServerContainer("my-docker-account/mssql-server-custom:latest")
.withPassword("yourStrong(!)Password");
dbContainer.start(); //starts the container
String jdbcUrl = dbContainer.getJdbcUrl();
logger.info("Database started, creating datasource for url: '{}'", jdbcUrl);
HikariDataSource dataSource = new HikariDataSource();
dataSource.setJdbcUrl(jdbcUrl);
dataSource.setUsername(dbContainer.getUsername());
dataSource.setPassword(dbContainer.getPassword());
dataSource.setDriverClassName(dbContainer.getDriverClassName());
dataSource.setAutoCommit(false);
return dataSource;
}
generator-jhipster-testcontainers
$ yo jhipster-testcontainers
$ ./mvnw verify -Dspring.profiles.active=testcontainers
Recap
A P I F I R S T
• CRUD stack is the foundation of your APP
• How CRUD and OpenAPI layers coexist
• Go API First only for mission critical APIs
• Use Testcontainers
• Share your modules ☺
Recap
A P I F I R S T
• Jhipster Conf 2018
• Connect your JHipster apps to APIs with Swagger and gRPC by Christophe Bornet
(https://www.youtube.com/watch?v=XWa-53-mDwY)
• Custom and Generated Code Side by Side by Antonio Goncalves
(https://www.youtube.com/watch?v=9WVpwIUEty0)
• generator-jhipster-apiutils module
• https://www.npmjs.com/package/generator-jhipster-apiutils
• Testcontainers & Jhipster
• https://www.youtube.com/watch?time_continue=3&v=L_i61qTg510
• https://atomfrede.gitlab.io/2019/05/jhipster-with-testcontainers/
• https://www.npmjs.com/package/generator-jhipster-testcontainers
• https://github.com/danielgtaylor/apisprout
• Demo Code Samples:
• https://github.com/intesys/jhipsterconf2019-petstore-demo
• https://github.com/intesys/jhipsterconf2019-petstore-client
References
Intesys S.r.l.
Via Roveggia, 122/A - 37136 Verona VR
T. +39 045 503 663
F. +39 045 503 604
@ info@intesys.it
intesys.it
Enrico Costanzi
S e n i o r s o f t w a r e d e v e l o p e r
enrico.costanzi@intesys.it
@enricocostanzi
Paolo Quaglia
S e n i o r P r o j e c t M a n a g e r a n d A r c h i t e c t
paolo.quaglia@intesys.it
@p_quail

JHipster Beyond CRUD - JHipster Conf' 2019

  • 1.
    Jhipster Beyond CRUD APIFirst for Enterprise 2 7 / 0 6 / 2 0 1 9 - I N T E S Y S This material has been prepared by personnel of Intesys S.r.l. and is provided on a confidential basis. All the materials, animations, graphics and concepts may not be used, reproduced, redistributed or transmitted, in whole or in part, without prior written permission from the owner. Any unauthorized use is strictly prohibited.
  • 2.
    W H OA R E W E ? Who we are Paolo Quaglia senior project manager and software architect - @p_quail Enrico Costanzi senior software developer - @enricocostanzi
  • 3.
    W H OA R E W E ? Italian 100 employees company Enterprise industry: Banks, insurance companies, manufacturing Our Development Pattern: Design to Deliver
  • 4.
    W H OA R E W E ? • We started with Jhipster in 2017 • 3rd Jhipster Bronze Sponsor • ~10 developers on average working with Jhipster • 5 projects running in production • 3 big project in Development phase • 2 Jhipster modules published • More modules/blueprints – work in progress • Some contributions to the main generator Intesys & Jhipster
  • 5.
  • 6.
    I N TE S Y S & J H I P S T E R 2017
  • 7.
    I N TE S Y S & J H I P S T E R 2017 • Angular Monolith (Single Node) • Jhipster 4.10.1 • 12 entities • ~200 users • No swagger endpoints • 3 Roles • No native queries • Local Cache • 2 dev teams involved
  • 8.
    I N TE S Y S & J H I P S T E R 2019 • React Monolith (multiple nodes) • Jhipster 5.8.2 • 120 entities (2 JDL files) • ~4000 users • 100 OpenAPI endpoints • 7 roles • Many native queries • Distributed cache • 5 dev teams involved
  • 9.
  • 10.
    A P ID R I V E N E N T E R P R I S E Enterprise Systems (SAP, AS400, TIBCO, API Gateways) Legacy databases
  • 11.
    A G EN D A • Why Beyond CRUD? • Code First Jhipster • API First Jhipster • Modules Demo • Testcontainers & Jhipster Agenda
  • 12.
  • 13.
    B E YO N D C R U D UserJWTController AccountResource UserResource Entity1Resource Entity1Service Entity1Repository Entity1ResourceExt Entity1ServiceExt Entity1RepoExt CustomController1 UserService UserRepository CustomService1 CustomController2 CustomService2 UserResourceExt UserServiceExt
  • 14.
    How do Imake life easy for API consumers?
  • 15.
    B E YO N D C R U D • Interoperability • Productivity • User Experience (UX) • Developer Experience (DX) We need
  • 16.
  • 17.
    C O DE F I R S T J H I P S T E R UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt Swagger UI & Springfox /v2/api-docs
  • 18.
  • 19.
    C O DE F I R S T J H I P S T E R Split your Swagger specs /v2/api-docs?group=auth /v2/api-docs?group=admin /v2/api-docs UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt
  • 20.
    C O DE F I R S T J H I P S T E R Split your Swagger specs /v2/api-docs?group=auth /v2/api-docs?group=admin /v2/api-docs UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt @Bean public Docket authDocket() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .groupName("auth") .forCodeGeneration(true) .directModelSubstitute(java.nio.ByteBuffer.class, String.class) .directModelSubstitute(URI.class, String.class) .directModelSubstitute(StatusType.class, Integer.class) .genericModelSubstitutes(ResponseEntity.class) .additionalModels(typeResolver.resolve(Problem.class)) .select() .paths(Predicates.or( regex("/api/account.*"), regex("/api/authenticate.*"), regex("/api/activate.*"), regex("/api/register.*")) ) .build(); return docket; }
  • 21.
    C O DE F I R S T J H I P S T E R Export your Swagger specs UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt account-spec.json default-spec.json account-spec.json
  • 22.
    C O DE F I R S T J H I P S T E R Export your Swagger specs UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt account-spec.json default-spec.json account-spec.json @SpringBootTest(classes = JhipetstoreApp.class) @ActiveProfiles(value = {JHipsterConstants.SPRING_PROFILE_SWAGGER}) public class OpenApiSpecGeneratorIT { @Autowired DocumentationCache documentationCache; @Autowired ServiceModelToSwagger2Mapper mapper; @Autowired JsonSerializer jsonSerializer; @Test void createOpenApiJsonSpec() throws IOException { for (Map.Entry<String, Documentation> documentationEntry : documentationCache.all().entrySet()) { String groupName = documentationEntry.getKey(); Documentation documentation = documentationEntry.getValue(); Swagger swagger = mapper.mapDocumentation(documentation); Json spec = jsonSerializer.toJson(swagger); File specsDir = new File("target/swagger-specs"); if (!specsDir.exists()) specsDir.mkdirs(); IOUtils.write(spec.value().getBytes(), new FileOutputStream("target/swagger-specs/” + groupName + «-spec.json")); } } }
  • 23.
    C O DE F I R S T - C O N T R A C T D R I V E N C O M M U N I C A T I O N UserJWTController AccountResource UserResource Entity1Resource Entity1Service Entity1Repository Entity1ResourceExt Entity1ServiceExt Entity1RepoExt CustomController1 UserService UserRepository CustomService1 CustomController2 CustomService2 UserResourceExt UserServiceExt
  • 24.
    B E YO N D C R U D Code First • API Consumers must wait for specs to be exposed or exported • Only Swagger v2 support (OpenAPI 3 generation is WIP) • Springfox scanning is slow with lots of controllers • Security rules must be coded in dockets
  • 25.
  • 26.
    A P IF I R S T J H I P S T E R API First • Design • API Design before writing code • Interoperability • Helps detecting breaking changes • Developer Experience • Decoupling client/server development • Developers contribute to API definition • Approval process during API design • User Experience • API design with UX/UI in mind
  • 27.
    27 A P IF I R S T J H I P S T E R Server side code generation from swagger / openapi specifications ReadPetsApi ReadPetApiDelegate API First Jhipster src/main/resources/swagger/api.yml ReadPetsApiDelegateImpl ReadPetsApiController
  • 28.
    A P IF I R S T modelNameSuffix: avoid DTOS with the same class name: • PetDTO (Jhipster) • PetApiDto (OpenAPI DTO) useTags: Groups the OpenAPI endpoints by tag (not by path prefix) OpenAPI Generator Configuration <groupId>org.openapitools</groupId> <artifactId>openapi-generator-maven-plugin</artifactId> <version>${openapi-generator-maven-plugin.version}</version> <executions> <execution> <goals> <goal>generate</goal> </goals> <configuration> <inputSpec>…/resources/swagger/api.yml</inputSpec> <generatorName>spring</generatorName> … <modelNameSuffix>ApiDTO</modelNameSuffix> <configOptions> <delegatePattern>true</delegatePattern> <title>jhipetstore</title> <useTags>true</useTags> </configOptions> </configuration> </execution> </executions> </plugin>
  • 29.
    C O DE F I R S T A N D A P I F I R S T What changed? UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt CustomController1 CustomController2 UserResourceExt OpenAPIController1 OpenAPIController2 UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt UserResourceExt
  • 30.
    C O DE F I R S T A N D A P I F I R S T UserJWTController AccountResource UserResource Entity1Resource Entity1Service Entity1Repository Entity1ResourceExt Entity1ServiceExt Entity1RepoExt UserService UserRepository CustomAPIService1 UserResourceExt UserServiceExt OpenAPIController1 OpenAPIController2 CustomAPIService2 JDL Code First API First
  • 31.
    C O DE F I R S T A N D A P I F I R S T Jhipster Frontend OpenAPIController1 OpenAPIController2 UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt UserResourceExt JDL APIs: • Jhipster CRUD • Jhipster Administration • Customizations API First Endpoints (generated client SDK): • Custom Pages • Design First
  • 32.
    C O DE F I R S T A N D A P I F I R S T External Apps – API + Code First OpenAPIController1 OpenAPIController2 UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt UserResourceExt External Backend Applications Mobile Apps Custom Single Page Applications
  • 33.
    C O DE F I R S T A N D A P I F I R S T External Apps – API First only OpenAPIController1 OpenAPIController2 UserJWTController AccountResource UserResource Entity1Resource Entity1ResourceExt UserResourceExt External Backend Applications Mobile Apps Custom Single Page Applications
  • 34.
    A P IF I R S T • Code duplication • Jhipster DTOs ~= OpenAPI DTOs • Basic CRUD Operations have to be rewritten in the spec • Metamodel Filtering and pagination (coded in the spec) • Authentication (duplicated endpoints in some cases) API First Limitations
  • 35.
  • 36.
    D E MO Customizing Using Modules OpenAPIController1 OpenAPIController2 OpenAPIController1 OpenAPIController2 Generated by OpenAPI Generator Generated by Springfox Designed specs Designed specs • api.yml served statically (not generated by Springfox) by a dedicated endpoint • Replaces Swagger UI 2 with Swagger UI 3 (iframe) • API version tag published in consul or Jhipster registry
  • 37.
    D E MO • Jhipster submodule to generate client code from swagger/openapi specifications • Integration of generator-jhipster-swagger-cli in the main generator • Wraps the official npm module openapi-generator-cli • Supports backend client generation (Feign clients) • Future steps: generate client code for Angular / React Jhipster OpenAPI Client (Preview) $ jhipster openapi-client
  • 38.
  • 39.
    T E ST C O N T A I N E R S Testcontainers “Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container” Jhipster Integration Tests • Native SQL Queries & Functions • Liquibase changelogs
  • 40.
    T E ST C O N T A I N E R S <dependency> <groupId>org.testcontainers</groupId> <artifactId>postgresql</artifactId> <version>1.11.3</version> <scope>test</scope> </dependency> The easy way jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore org.testcontainers.jdbc.ContainerDatabaseDriver 1. add dependency 2. change test properties 3. ./mvnw verify 4. DONE! ☺
  • 41.
    T E ST C O N T A I N E R S The custom way jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore org.testcontainers.jdbc.ContainerDatabaseDriver @TestConfiguration @Profile("testcontainers") public class IntegrationTestsConfiguration { @Bean public DataSource dataSource() { dbContainer = new MSSQLServerContainer("my-docker-account/mssql-server-custom:latest") .withPassword("yourStrong(!)Password"); dbContainer.start(); //starts the container String jdbcUrl = dbContainer.getJdbcUrl(); logger.info("Database started, creating datasource for url: '{}'", jdbcUrl); HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(jdbcUrl); dataSource.setUsername(dbContainer.getUsername()); dataSource.setPassword(dbContainer.getPassword()); dataSource.setDriverClassName(dbContainer.getDriverClassName()); dataSource.setAutoCommit(false); return dataSource; } generator-jhipster-testcontainers
  • 42.
    T E ST C O N T A I N E R S The custom way jdbc:tc:postgresql:11.3://localhost:5432/jhipetstore org.testcontainers.jdbc.ContainerDatabaseDriver @TestConfiguration @Profile("testcontainers") public class IntegrationTestsConfiguration { @Bean public DataSource dataSource() { dbContainer = new MSSQLServerContainer("my-docker-account/mssql-server-custom:latest") .withPassword("yourStrong(!)Password"); dbContainer.start(); //starts the container String jdbcUrl = dbContainer.getJdbcUrl(); logger.info("Database started, creating datasource for url: '{}'", jdbcUrl); HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl(jdbcUrl); dataSource.setUsername(dbContainer.getUsername()); dataSource.setPassword(dbContainer.getPassword()); dataSource.setDriverClassName(dbContainer.getDriverClassName()); dataSource.setAutoCommit(false); return dataSource; } generator-jhipster-testcontainers $ yo jhipster-testcontainers $ ./mvnw verify -Dspring.profiles.active=testcontainers
  • 43.
  • 44.
    A P IF I R S T • CRUD stack is the foundation of your APP • How CRUD and OpenAPI layers coexist • Go API First only for mission critical APIs • Use Testcontainers • Share your modules ☺ Recap
  • 45.
    A P IF I R S T • Jhipster Conf 2018 • Connect your JHipster apps to APIs with Swagger and gRPC by Christophe Bornet (https://www.youtube.com/watch?v=XWa-53-mDwY) • Custom and Generated Code Side by Side by Antonio Goncalves (https://www.youtube.com/watch?v=9WVpwIUEty0) • generator-jhipster-apiutils module • https://www.npmjs.com/package/generator-jhipster-apiutils • Testcontainers & Jhipster • https://www.youtube.com/watch?time_continue=3&v=L_i61qTg510 • https://atomfrede.gitlab.io/2019/05/jhipster-with-testcontainers/ • https://www.npmjs.com/package/generator-jhipster-testcontainers • https://github.com/danielgtaylor/apisprout • Demo Code Samples: • https://github.com/intesys/jhipsterconf2019-petstore-demo • https://github.com/intesys/jhipsterconf2019-petstore-client References
  • 46.
    Intesys S.r.l. Via Roveggia,122/A - 37136 Verona VR T. +39 045 503 663 F. +39 045 503 604 @ info@intesys.it intesys.it Enrico Costanzi S e n i o r s o f t w a r e d e v e l o p e r enrico.costanzi@intesys.it @enricocostanzi Paolo Quaglia S e n i o r P r o j e c t M a n a g e r a n d A r c h i t e c t paolo.quaglia@intesys.it @p_quail