rest application
TRANSCRIPT
Technologies
● Spring Boot● Spring MVC● Spring Data● Spring Security● Liquibase● Maven● Swagger● Junit 4● Mockito● RestAssured● Postgresql● H2 – embeded for test
Rest main principals
● Client-Server with one API. Client and Server are two separated applications!!!
● Stateless – session on client side, all required info in url.
● Client can put to cash information from server
Main rest request
● GET – doesn't change resource● PUT – (create, replace, update)you can make it
many times without creating duplicates● POST - (The POST operation is very generic
and no specific meaning can be attached to it) create something new
● Delete – simple delete
First properties
● security.user.password=qwerty●
● #DB connection properties● spring.datasource.url=jdbc:postgresql://localhost:5432/test● spring.datasource.username=postgres● spring.datasource.password=qwerty● spring.datasource.driverClassName=org.postgresql.Driver● spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect● spring.jpa.show-sql=true● spring.jpa.hibernate.ddl-auto=none
Repositories
● No more same jpql!● No more DAO!
Methods from the box:
- save
- findOne
- exists
- findAll
- count
- delete
- deleteAll
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repository-query-keywords
Old good @Entity@Entity
public class Person{
@Id
@Column(name = "person_id", nullable = false)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 30)
private String login;
@Column(nullable = false, length = 30)
private String password;
@Column(nullable = false, length = 30)
private String name;
@Column(nullable = false)
@Enumerated(EnumType.STRING)
private UserRoleEnum role;
}
public enum UserRoleEnum {
MODERATOR,
USER
}
First controller
● @RestController● @RequestMapping("/api/person")● public class PersonController {●
● @RequestMapping(method = RequestMethod.GET)● public List<Person> getPersons(){● …...........................● }● }
Liquibase
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>3.3.2</version>
</dependency>
Profile● <profile>● <id>rebuild-db</id>● <build>● <plugins>● <plugin>● <groupId>org.liquibase</groupId>● <artifactId>liquibase-maven-plugin</artifactId>● <version>3.3.2</version>● <executions>● <execution>● <id>release-changelog</id>● <phase>clean</phase>● <goals>● <goal>dropAll</goal>● <goal>update</goal>● </goals>● <configuration>● <changeLogFile>${liquibase.createtables}</changeLogFile>● <propertyFileWillOverride>true</propertyFileWillOverride>● <propertyFile>src/main/resources/liquibase.properties</propertyFile>● </configuration>● </execution>● </executions>● </plugin>● </plugins>● </build>● </profile>
Integration tests
● public interface RestPublisher {●
● <T> T doGet(Class<T> clazz, String resourceURL);●
● <T> T doPost(String resourceURL, Object requestBody, Class<T> clazz);
●
● }
Restassured
<dependency>
<groupId>com.jayway.restassured</groupId>
<artifactId>rest-assured</artifactId>
<version>2.1.0</version>
<scope>test</scope>
</dependency>
given().auth().basic(username, password).when().get("/secured").then().statusCode(200);
RestPublisherImplpublic class RestPublisherImpl implements RestPublisher{
●
● public static final String REQUEST_BODY_TYPE = "application/json";● private String serverUrl;●
● private RequestSpecification requestSpecification;●
● public RestPublisherImpl(String serverUrl, String login, String password) {● this.serverUrl = serverUrl;● requestSpecification = given().authentication().basic(login, password).contentType(ContentType.JSON);●
● }●
● public <T> T doGet(Class<T> clazz, String resourceURL) {● Response response = requestSpecification.get(serverUrl + resourceURL);● return response.as(clazz);● }●
● public <T> T doPost(String resourceURL, Object requestBody, Class<T> clazz) {● return requestSpecification.body(requestBody).post(resourceURL).as(clazz);● }●
● }
Embedded DB for tests
● @TestPropertySource(locations="classpath:test.properties")
#DB connection properties
spring.datasource.url=jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
spring.datasource.initialize=true
liquibase.changeLog=classpath:changeset-test-data.xml
Integration with liqubase
● <dependency>● <groupId>org.liquibase</groupId>● <artifactId>liquibase-core</artifactId>● <scope>test</scope>● </dependency>
Swagger
@EnableSwagger2
@ComponentScan(basePackages = "com.illcko.demo.enjoyme.rest_controllers")
public class SwaggerConfig {
@Bean
public Docket swaggerSpringMvcPlugin() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo()).select().paths(regex("/api.*")).build();
}
private ApiInfo apiInfo() {
ApiInfo apiInfo = ApiInfo.DEFAULT;
return apiInfo;
}
}
Swagger dependencies
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.2.2</version>
</dependency>
<repository>
<id>spring-milestones</id>
<url>http://repo.spring.io/libs-milestone/</url>
</repository>
Quick Annotation Overview
@Api Marks a class as a Swagger resource.● @ApiImplicitParam Represents a single parameter in an API Operation.● @ApiImplicitParams A wrapper to allow a list of multiple ApiImplicitParam objects.● @ApiModel Provides additional information about Swagger models.● @ApiModelPropertyAdds and manipulates data of a model property.● @ApiOperation Describes an operation or typically a HTTP method against a specific path.● @ApiParam Adds additional meta-data for operation parameters.● @ApiResponse Describes a possible response of an operation.● @ApiResponses A wrapper to allow a list of multiple ApiResponse objects.● @Authorization Declares an authorization scheme to be used on a resource or an operation.● @AuthorizationScope Describes an OAuth2 authorization scope.● @ResponseHeader Represents a header that can be provided as part of the response.
Unit tests - Mockito
● <dependency>● <groupId>org.mockito</groupId>● <artifactId>mockito-all</artifactId>● <version>1.9.5</version>● </dependency>