STACKJAVA

Code ví dụ Swagger với springfox-swagger2, swagger ui

Code ví dụ Swagger với springfox-swagger2, swagger ui

(Xem lại: Swagger là gì)

Trong bài này mình sẽ sử dụng lại Code ví dụ Spring Boot RESTful Webservice với các api thêm, sửa, xóa user và tạo tài liệu để import vào swagger.

Tạo Spring Boot Project

Thư viện sử dụng

Để sử dụng swagger ta thêm 2 thư viện sau:

<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger2</artifactId>
  <version>2.8.0</version>
</dependency>
<dependency>
  <groupId>io.springfox</groupId>
  <artifactId>springfox-swagger-ui</artifactId>
  <version>2.8.0</version>
</dependency>

Thư viện springfox-swagger-ui giúp bạn nhúng sẵn phần mềm swagger-ui vào project, phần mềm swagger ui sẽ được start cùng project.

Cấu hình swagger

package stackjava.com.sbrestful.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
        		.apiInfo(getApiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("stackjava.com.sbrestful.controller"))
                .paths(PathSelectors.any())
                .build();
    }
    
    private ApiInfo getApiInfo() {
        Contact contact = new Contact("stackjava.com", "https://stackjava.com", "cuong.9312@gmail.com");
        return new ApiInfoBuilder()
                .title("Spring Boot Swagger")
                .description("Demo Spring Boot Swagger")
                .version("1.0.0")
                .license("Apache 2.0")
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0")
                .contact(contact)
                .build();
    }
}

File entity

package stackjava.com.sbrestful.entities;

import io.swagger.annotations.ApiModelProperty;
public class User {
  
    @ApiModelProperty(notes = "Id auto increase upon create new")
  private int id;
  private String username;
  private String password;

  // getter - setter
}

Ví dụ trên swagger, class User sẽ hiển thị như sau:

File Controller

package stackjava.com.sbrestful.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import stackjava.com.sbrestful.entities.User;

@RestController
@RequestMapping("/rest")
@Api(tags = "Users Rest Controller")
public class UserRestController {

  public static HashMap<Integer, User> mapUser = new HashMap<Integer, User>();
  static {
    mapUser.put(1, new User(1, "kai", "123456"));
    mapUser.put(2, new User(2, "admin", "admin1234"));
    mapUser.put(3, new User(3, "sena", "123456"));
    mapUser.put(4, new User(4, "peter", "1234"));
  }

  @RequestMapping(value = "/users", method = RequestMethod.GET, produces= MediaType.APPLICATION_JSON_UTF8_VALUE)
  @ApiOperation(value = "Get all users", tags = "Users Rest Controller")
  @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
      @ApiResponse(code = 400, message = "Bad request"),
      @ApiResponse(code = 500, message = "Internal server error") })
  public ResponseEntity<List<User>> getAllUser() {
    List<User> listUser = new ArrayList<User>(mapUser.values());
    return new ResponseEntity<List<User>>(listUser, HttpStatus.OK);
  }

  @ApiOperation(value = "Get User By ID", tags = "Users")
  @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
      @ApiResponse(code = 400, message = "Bad request"),
      @ApiResponse(code = 500, message = "Internal server error") })
  @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
  public ResponseEntity<Object> getUserById(@PathVariable int id) {
    User user = mapUser.get(id);
    if (user != null) {
      return new ResponseEntity<Object>(user, HttpStatus.OK);
    }
    return new ResponseEntity<Object>("Not Found User", HttpStatus.NO_CONTENT);
  }

  @ApiOperation(value = "Create new User")
  @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
      @ApiResponse(code = 400, message = "Bad request"),
      @ApiResponse(code = 500, message = "Internal server error") })
  @RequestMapping(value = "/users", method = RequestMethod.POST)
  public ResponseEntity<String> createUser(@RequestBody User user) {
    if (mapUser.containsKey(user.getId())) {
      return new ResponseEntity<String>("User Already Exist!", HttpStatus.CONFLICT);
    }
    mapUser.put(user.getId(), user);
    return new ResponseEntity<String>("Created!", HttpStatus.CREATED);
  }

  @ApiOperation(value = "Delete User")
  @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
      @ApiResponse(code = 400, message = "Bad request"),
      @ApiResponse(code = 500, message = "Internal server error") })
  @RequestMapping(value = "/users/{id}", method = RequestMethod.DELETE)
  public ResponseEntity<String> deleteUserById(@PathVariable int id) {
    User user = mapUser.get(id);
    if (user == null) {
      return new ResponseEntity<String>("Not Found User", HttpStatus.OK);
    }

    mapUser.remove(id);
    return new ResponseEntity<String>("Deleted!", HttpStatus.OK);
  }

  @ApiOperation(value = "Update User")
  @ApiResponses(value = { @ApiResponse(code = 200, message = "Success"),
      @ApiResponse(code = 400, message = "Bad request"),
      @ApiResponse(code = 500, message = "Internal server error") })
  @RequestMapping(value = "/users", method = RequestMethod.PUT)
  public ResponseEntity<String> updateUser(@RequestBody User user) {
    User oldUser = mapUser.get(user.getId());
    if (oldUser == null) {
      return new ResponseEntity<String>("Not Found User", HttpStatus.NO_CONTENT);
    }
    mapUser.put(user.getId(), user);
    return new ResponseEntity<String>("Updated!", HttpStatus.OK);
  }

}

Ví dụ mô tả của method getAllUser trên swagger sẽ như sau:

Trong trường hợp bạn muốn giải thích các paramater trong request thì ta có thể dùng annotation @ApiImplicitParams

Ví dụ trong method getAllUser mình muốn truyền thêm thông tin page và size để phân trang kết quả trả về thì mình sẽ dùng thêm annotation sau trước method getAllUser

@ApiImplicitParams(
        value = {
                @ApiImplicitParam(name = "page", value = "page number start from 0", dataType = "integer",
                        examples = @Example(@ExampleProperty("1")), paramType = "query"),
                @ApiImplicitParam(name = "size", value = "maximum number of item in page", dataType = "integer",
                        examples = @Example(@ExampleProperty("40")), paramType = "query"),
        }
)

Config Cors

Trong trường hợp phần mềm swagger và project của bạn không cùng địa chỉ, ta cần enable cors để cho phép swagger có thể gửi ajax tới project spring boot.

Ví dụ trong trường hợp mình chạy phần mềm swagger ui riêng rồi start project spring boot riêng, nếu không enable cors thì sẽ gặp lỗi sau:

package stackjava.com.sbrestful.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
  
  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**");
  }
  
  @Bean
  public CorsFilter corsFilter() {
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    // Allow anyone and anything access. Probably ok for Swagger spec
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");
    source.registerCorsConfiguration("/v2/api-docs", config);
    return new CorsFilter(source);
  }
}

Demo:

Sau khi cấu hình xong swagger và start project, mặc định thông tin swagger sẽ được tạo ra ở url: http://localhost:8080/v2/api-docs

Bây giờ bạn chỉ cần nhập http://localhost:8080/v2/api-docs vào ô input explorer của swagger là nó sẽ tạo document api cho bạn:

Hoặc bạn có thể chạy swagger trên project với url localhost:8080/swagger-ui.html

Ví dụ thực hiện kiểm tra, chạy thử api get all users trên swagger:

Ví dụ thực hiện lấy thông tin của user có id = 1

Với những trường hợp put, post các bạn thêm data giống vào body, nhìn chung swagger hoạt động giống hệt như một rest client (ví dụ như postman)

Code ví dụ Swagger với springfox-swagger2, swagger ui stackjava.com

Okay, Done!

Download code ví dụ trên tại đây.

References:

swagger.io/docs/specification/about