<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.4</version>
<executions>
...
</executions>
</plugin>
Generation
API-First
by Talend
by Talend
by API Team
by Talend
by API Team
by me
API-first software development refers to a set of practices that formally recognize APIs as a first-class artefact of software development, and emphasize their strategic and architectural importance.
Quicker, easier, more seductive
Lib springfox-swagger2
Dev must work before others can
Start with a contract
Everyone can mock from the contract
Slower to evolve
We need a tool for creating an API definition :
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>3.3.4</version>
<executions>
...
</executions>
</plugin>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
...
</configuration>
</execution>
</executions>
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/api.yml
</inputSpec>
<generatorName>spring</generatorName>
<configOptions>
<sourceFolder>src/gen/java/main</sourceFolder>
<interfaceOnly>true</interfaceOnly>
</configOptions>
<modelPackage>bzh.zomzog.apifirst.domain</modelPackage>
<apiPackage>bzh.zomzog.apifirst.api</apiPackage>
<generateSupportingFiles>true</generateSupportingFiles>
</configuration>
@RestController
public class PoniesController implements PoniesApi {
@Override
public ResponseEntity<Pony> getOne(String ponyId) {
Pony pony = new Pony();
pony.setId( "1" );
pony.setName( "Rainbow dash" );
pony.setColor( Pony.ColorEnum.RAINBOW );
return ResponseEntity.ok( pony );
}
}
<configuration>
<inputSpec>
${project.basedir}/src/main/resources/api.yml
</inputSpec>
<generatorName>java</generatorName>
<library>feign</library>
<configOptions>
<sourceFolder>src/gen/java/main</sourceFolder>
</configOptions>
<modelPackage>bzh.zomzog.prez.apifirst.domain</modelPackage>
<apiPackage>bzh.zomzog.prez.apifirst.client.api</apiPackage>
<generateSupportingFiles>true</generateSupportingFiles>
</configuration>
ApiClient apiClient = new ApiClient();
apiClient.setBasePath("http://localhost:8080");
Pony one = apiClient.buildClient(DefaultApi.class).getOne("1");
BeanUtils.copyProperties(newObject, oldObject);
Only simple mapping same name, same type
Generate mapper implementation at compile-time (annotation-processor).
Can do transformation
Can map immutable, use builder
Can be extended
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-jdk8</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<scope>provided</scope>
</dependency>
@Data
public class MyPony {
private long id;
private String name;
private String color;
private LocalDateTime createdAt;
private String hiddenField;
}
@Mapper
public abstract class MyPonyMapper {
public abstract MyPony map(Pony pony);
}
public LocalDateTime map(Long l) {
return LocalDateTime.ofEpochSecond(l, 0, ZoneOffset.UTC);
}
@Mapper(componentModel = "spring",
injectionStrategy = InjectionStrategy.CONSTRUCTOR,
uses = NativeMapper.class)
@Mapping(target = "id", ignore = true)
public abstract MyPony update(Pony pony, @MappingTarget MyPony myPony);
@Builder
@Data
public class MyPony {
Springfox is less than perfect
Spring Pageable
Generics
Nicknames
Generate DTO and map them to your domain
Generate and replace API
Design API with a tools
Generate client and server from it
Use a mapper to your domain objects
Show love with your APIs
Source code and slide can be found on https://github.com/Zomzog/api-first