GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Java Webservice REST Sử dụng Swagger UI trong jersey REST WS project

Sử dụng Swagger UI trong jersey REST WS project

Đăng vào 15/08/2019 . Được đăng bởi GP Coder . 5819 Lượt xem . Toàn màn hình

Trong các bài viết trước, tôi đã giới thiệu với các bạn Swagger và cách cài đặt, sử dụng Swagger UI. Trong thực tế, các API thường được thay đổi bởi các developer và họ ít khi mở Swagger editor để cập nhật lại các document hoặc vì lý do nào đó mà họ không cập nhật document mới nhất theo source code. Một vấn đề đặt ra là có cách nào để API document có thể cập nhật một cách tự động mỗi khi code thay đổi và đặt cùng một nơi trong code để developer dễ dàng cập nhật hay không? Câu trả là là có và tôi sẽ hướng dẫn các bạn thực hiện trong phần tiếp theo của bài viết này.

Nội dung

  • 1 Tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động
  • 2 Ví dụ

Tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động

Tiếp tục bài viết về xây dựng RESTful API với Jersey, trong bài này tôi sẽ hướng dẫn các bạn cách tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động. Nếu các bạn làm Spring project có thể tìm hiểu về Springfox – đây là một thư viện rất mạnh mẽ và dễ sử dụng để tạo REST API document. Tôi sẽ hướng dẫn các bạn Springfox ở series bài viết về Spring Framework.

Ý tưởng:

  • Tạo REST API sử dụng Jersey 2.
  • Sử dụng Swagger Annotation để mô tả thông tin về resource.
  • Sử dụng Swagger core để sinh file đặc tả Swagger API theo chuẩn OpenAPI 3, output có thể là json hoặc yaml.
  • Sử dụng thư viện Swagger UI để sinh ra giao diện cho document từ file config dưới chuẩn OpenAPI.

Để mọi thứ có thể thực hiện một cách tự động, chúng ta sẽ sử dụng Maven – một chương trình quản lý dự án cho phép các developers có thể quản lý về version, các dependencies (các component, thư viện sử dụng trong dự án) , quản lý build, tự động download javadoc & source, ….

Các maven plugin cần thiết để tích hợp Jersey với Swagger UI:

  • maven-dependency-plugin : plugin này giúp donwload các static Swagger UI file được đóng gói trong webjar từ Maven dependency.
  • maven-war-plugin : plugin này giúp copy các static Swagger UI file vào thư mục swagger-ui trong war file của project.
  • replacer : được sử dụng để thay thế URL đến file OpenAPI specification trong file index.html của Swaggers UI.

Ví dụ

Tôi sẽ sử dụng lại ví dụ ở bài viết “JWT – Token-based Authentication trong Jersey 2.x” để hướng dẫn các bạn cách tạo document tự động cho các API này.

Các bước thực hiện:

  • Tạo maven project và khai báo các thư viện, plugin cần thiết.
  • Cấu hình Jersey.
  • Thêm cấu hình API trong file web.xml.
  • Tạo file đặc tả API cho project: openapi.yaml.
  • Sử dụng các Swagger Annotation để mô tả API.
  • Build project và sử dụng.

Tạo maven project và khai báo các thư viện, plugin cần thiết

Tạo maven project với cấu trúc như sau:

Mở file pom.xml và thêm các dependency sau:


<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>SwaggerWithJersey2Example</groupId>
	<artifactId>SwaggerWithJersey2Example</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>war</packaging>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<jersey.version>2.28</jersey.version>
		<lombok.version>1.16.20</lombok.version>
		<javax.servlet-api.version>4.0.1</javax.servlet-api.version>
		<javax.ws.rs-api.version>2.1.1</javax.ws.rs-api.version>
 		<swagger.version>2.0.8</swagger.version>
        <swagger-ui.version>3.23.4</swagger-ui.version>
        <replacer.version>1.5.3</replacer.version>
	</properties>

	<dependencies>
		<!-- Javax -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>${javax.servlet-api.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.ws.rs</groupId>
			<artifactId>javax.ws.rs-api</artifactId>
			<version>${javax.ws.rs-api.version}</version>
		</dependency>
		<!-- Jersey -->
		<dependency>
            <groupId>org.glassfish.jersey.connectors</groupId>
            <artifactId>jersey-apache-connector</artifactId>
            <version>${jersey.version}</version>
        </dependency>
		<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
		<dependency>
			<groupId>org.glassfish.jersey.core</groupId>
			<artifactId>jersey-server</artifactId>
			<version>${jersey.version}</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish.jersey.containers</groupId>
			<artifactId>jersey-container-servlet</artifactId>
			<version>${jersey.version}</version>
		</dependency>
		<dependency>
			<groupId>org.glassfish.jersey.inject</groupId>
			<artifactId>jersey-hk2</artifactId>
			<version>${jersey.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client -->
		<dependency>
			<groupId>org.glassfish.jersey.core</groupId>
			<artifactId>jersey-client</artifactId>
			<version>${jersey.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->
		<dependency>
			<groupId>org.glassfish.jersey.core</groupId>
			<artifactId>jersey-common</artifactId>
			<version>${jersey.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
		<dependency>
			<groupId>org.glassfish.jersey.media</groupId>
			<artifactId>jersey-media-json-jackson</artifactId>
			<version>${jersey.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-multipart -->
		<dependency>
			<groupId>org.glassfish.jersey.media</groupId>
			<artifactId>jersey-media-multipart</artifactId>
			<version>${jersey.version}</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<version>${lombok.version}</version>
			<scope>provided</scope>
		</dependency>

		<!-- Java JWT: JSON Web Token for Java -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-api</artifactId>
			<version>0.10.5</version>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-impl</artifactId>
			<version>0.10.5</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-jackson</artifactId>
			<version>0.10.5</version>
			<scope>runtime</scope>
		</dependency>
		<!-- Uncomment this next dependency if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms: -->
		<!-- <dependency> 
			<groupId>org.bouncycastle</groupId> 
			<artifactId>bcprov-jdk15on</artifactId>
			<version>1.60</version> 
			<scope>runtime</scope> 
		</dependency> -->

		<!-- Swagger -->
		<!-- https://mvnrepository.com/artifact/io.swagger.core.v3/swagger-jaxrs2 -->
		<dependency>
			<groupId>io.swagger.core.v3</groupId>
			<artifactId>swagger-jaxrs2</artifactId>
			<version>${swagger.version}</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/io.swagger.core.v3/swagger-jaxrs2-servlet-initializer -->
		<dependency>
			<groupId>io.swagger.core.v3</groupId>
			<artifactId>swagger-jaxrs2-servlet-initializer</artifactId>
			<version>${swagger.version}</version>
		</dependency>

	</dependencies>

	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<!-- Build with specified Java version -->
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<source>1.8</source>
					<target>1.8</target>
				</configuration>
			</plugin>
			<plugin>
				<!-- Download Swagger UI webjar -->
				<artifactId>maven-dependency-plugin</artifactId>
				<version>3.1.1</version>
				<executions>
					<execution>
						<phase>prepare-package</phase>
						<goals>
							<goal>unpack</goal>
						</goals>
						<configuration>
							<artifactItems>
								<!-- https://mvnrepository.com/artifact/org.webjars/swagger-ui -->
								<dependency>
								    <groupId>org.webjars</groupId>
								    <artifactId>swagger-ui</artifactId>
								    <version>${swagger-ui.version}</version>
								</dependency>
							</artifactItems>
							<outputDirectory>${project.build.directory}/swagger-ui</outputDirectory>
						</configuration>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<!-- Add Swagger UI resources to the war file. -->
				<!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-war-plugin -->
			    <groupId>org.apache.maven.plugins</groupId>
			    <artifactId>maven-war-plugin</artifactId>
			    <version>3.2.3</version>
				<configuration>
					<webResources combine.children="append">
						<resource>
							<directory>${project.build.directory}/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}</directory>
							<includes>
								<include>**/*.*</include>
							</includes>
							<targetPath>swagger-ui</targetPath>
						</resource>
					</webResources>
				</configuration>
			</plugin>
			<plugin>
				<!-- Replace the OpenAPI specification example URL with the local one. -->
				<!-- https://mvnrepository.com/artifact/com.google.code.maven-replacer-plugin/replacer -->
			    <groupId>com.google.code.maven-replacer-plugin</groupId>
			    <artifactId>replacer</artifactId>
				<version>${replacer.version}</version>
				<executions>
					<execution>
						<phase>prepare-package</phase>
						<goals>
							<goal>replace</goal>
						</goals>
					</execution>
				</executions>
				<configuration>
					<file>${project.build.directory}/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version}/index.html</file>
					<replacements>
						<replacement>
							<token>https://petstore.swagger.io/v2/swagger.json</token>
							<value>/api/openapi.json</value>
						</replacement>
					</replacements>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Các bạn nhớ update maven project để download tất cả thư viện về máy nhé.

Cấu hình Jersey

Mở file com.gpcoder.config.JerseyServletContainerConfig thêm khai báo package swagger: io.swagger.v3.jaxrs2.integration.resources.


package com.gpcoder.config;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.logging.LoggingFeature;
//Deployment of a JAX-RS application using @ApplicationPath with Servlet 3.0
//Descriptor-less deployment
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature;

public class JerseyServletContainerConfig extends ResourceConfig {
	public JerseyServletContainerConfig() {
		// if there are more than two packages then separate them with semicolon
		packages("io.swagger.v3.jaxrs2.integration.resources,com.gpcoder");
		register(new LoggingFeature(Logger.getLogger(LoggingFeature.DEFAULT_LOGGER_NAME), Level.INFO,
				LoggingFeature.Verbosity.PAYLOAD_ANY, 10000));
		register(JacksonFeature.class);
		
		// This authorization feature is not automatically turned on.
		// We need to turn it on by ourself.
		register(RolesAllowedDynamicFeature.class);
	}
}

Thêm cấu hình API trong file web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
	<display-name>Swagger with Jersey2 Example by gpcoder</display-name>
	<servlet>
        <servlet-name>api</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
			<param-name>javax.ws.rs.Application</param-name>
			<param-value>com.gpcoder.config.JerseyServletContainerConfig</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>api</servlet-name>
        <url-pattern>/api/*</url-pattern>
    </servlet-mapping>
</web-app>

Tạo file đặc tả API cho project: openapi.yaml

Khai báo một số thông tin cơ bản về API và security theo OpenAPI Specification.


prettyPrint: true
cacheTTL: 0
openAPI:
  info:
    description: "Swagger UI demo by gpcoder.com"
    version: "1.0.0"
    title: "Swagger UI Demo"
    termsOfService: "http://swagger.io/terms/"
    contact:
      email: "contact@gpcoder.com"
    license:
      name: "Apache 2.0"
      url: "http://www.apache.org/licenses/LICENSE-2.0.html"
  servers:
    - url: '/api'
  # 1) Define the security scheme type (HTTP bearer)
  components:
    securitySchemes:
      bearerAuth:            # arbitrary name for the security scheme
        type: http
        scheme: bearer
        bearerFormat: JWT    # optional, arbitrary value for documentation purposes
  # 2) Apply the security globally to all operations
  security:
    - bearerAuth: []         # use the same name as above

Trong project này, chúng ta cần chứng thực user sử dụng JWT, nên cần khai báo một số thông tin về security. Chi tiết về Security OpenAPI Specification, các bạn tham khảo thêm ở link sau: https://swagger.io/docs/specification/authentication/bearer-authentication/

Sử dụng các Swagger Annotation để mô tả API

Bây giờ chúng ta sử dụng các Swagger Annotation được cung cấp bởi Swagger core để mô tả các API.

Chi tiết tất cả các Swagger Annotation, các bạn tham khảo tại đây: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X—Annotations

AuthService.java


package com.gpcoder.api;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import com.gpcoder.helper.JwTokenHelper;
import com.gpcoder.model.User;
import com.gpcoder.service.UserService;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;

@Path("/auth")
@Tag(name = "Authentication services", 
	description = "Authenticating a user and issuing a JSON Web Token (JWT)")
public class AuthService {

	@POST
	@Produces(MediaType.APPLICATION_JSON)
	@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
	@Operation(summary = "Authenticating a user", 
		description = "Authenticating a user with their username/ password and issuing a JSON Web Token (JWT)",
		responses = {
		         @ApiResponse(description = "Authenticated user based on the given information", 
		        		 content = @Content(mediaType = "application/json", 
		        		 schema = @Schema(implementation = String.class))),
		         @ApiResponse(responseCode = "200", description = "success"),
		         @ApiResponse(responseCode = "403", description = "Wrong username or password."),
		         @ApiResponse(responseCode = "500", description = "Internal Server Error.") 
	         })
	public Response authenticateUser(
			@Parameter(description = "The user name for login. Some test account: admin, customer, gpcoder", required = true)
			@FormParam("username") String username, 
			@Parameter(description = "The password for login", required = true)
			@FormParam("password") String password) {

		// Authenticate the user using the credentials provided
		UserService userService = new UserService();
		User user = userService.getUser(username);
		if (user == null || !user.getPassword().equals(password)) {
			return Response.status(Response.Status.FORBIDDEN) // 403 Forbidden
					.entity("Wrong username or password") // the response entity
					.build();
		}

		// Issue a token for the user
		String token = JwTokenHelper.createJWT(user);

		// Return the token on the response
		return Response.ok(token).build();
	}
}

OrderService.java


package com.gpcoder.api;

import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;

import com.gpcoder.model.Order;
import com.gpcoder.model.Role;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;

// URI:
// http(s)://<domain>:(port)/<YourApplicationName>/<UrlPattern in web.xml>/<path>
// http://localhost:8080/api/orders
@Path("/orders")
@PermitAll
@Consumes(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
@Produces(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_PLAIN })
@Tag(name = "Order service", 
	description = "CRUD operations for order service. User must be authorized with some resources.")
public class OrderService {

	@GET
	@Path("/{id}")
	@Operation(summary = "Get order by id", description = "This action published for everyone")
	@ApiResponse(responseCode = "200", description = "Get order by id")
	public Response get(@PathParam("id") int id) {
		System.out.println("OrderService->get()");
		return Response.ok("OrderService->get()").build();
	}

	@Operation(
		summary = "Insert an order", 
		responses = {
	         @ApiResponse(description = "Inserted an order based on the given information", 
	        		 content = @Content(mediaType = "application/json", 
	        		 schema = @Schema(implementation = String.class))),
	         @ApiResponse(responseCode = "200", description = "success"),
	         @ApiResponse(responseCode = "401", description = "User cannot access this resource."),
	         @ApiResponse(responseCode = "403", description = "User not authorized."),
	         @ApiResponse(responseCode = "500", description = "Internal Server Error.") 
         })
	@POST
	@RolesAllowed(Role.ROLE_CUSTOMER)
	public Response insert(Order order, @Context SecurityContext securityContext) {
		System.out.println("User: " + securityContext.getUserPrincipal().getName());
		System.out.println("OrderService->insert()");
		return Response.ok("OrderService->insert()").build();
	}

	@PUT
	@RolesAllowed({ Role.ROLE_ADMIN, Role.ROLE_CUSTOMER })
	@Operation(summary = "Update order", description = "Admin and Customer can do this action")
	public Response update(Order order) {
		System.out.println("OrderService->update()");
		return Response.ok("OrderService->update()").build();
	}

	@DELETE
	@Path("/{id}")
	@RolesAllowed(Role.ROLE_ADMIN)
	@Operation(summary = "Delete order by id", description = "Only Admin can do this action")
	public Response delete(@PathParam("id") int id) {
		System.out.println("OrderService->delete()");
		return Response.ok("OrderService->delete()").build();
	}
}

Build project và sử dụng

Các bạn chọn chuột phải lên project -> Run As -> Maven install. Sau khi chạy xong bạn sẽ thấy các thư viện Swagger UI đã được tải về và giải nén trong thư mục target của project như sau:

Mở file index.html trong thư mục target/swagger-ui/META-INF/resources/webjars/swagger-ui/${swagger-ui.version} , bạn sẽ thấy đường dẫn đến file mô tả swagger.json đã được thay thế bằng /api/openapi.json như đã config trong file pom.xml.

Mọi thứ đã xong, bây giờ các bạn có thể start server lên để kiểm tra kết quả.

  • Kiểm tra file openapi.json tồn tại và chứa tất cả các đặc tả về API document. Truy cập vào địa chỉ: http://localhost:8080/api/openapi.json

{
  "openapi" : "3.0.1",
  "info" : {
    "title" : "Swagger UI Demo",
    "description" : "Swagger UI demo by gpcoder.com",
    "termsOfService" : "http://swagger.io/terms/",
    "contact" : {
      "email" : "contact@gpcoder.com"
    },
    "license" : {
      "name" : "Apache 2.0",
      "url" : "http://www.apache.org/licenses/LICENSE-2.0.html"
    },
    "version" : "1.0.0"
  },
  "servers" : [ {
    "url" : "/api"
  } ],
  "security" : [ {
    "bearerAuth" : [ ]
  } ],
  "tags" : [ {
    "name" : "Authentication services",
    "description" : "Authenticating a user and issuing a JSON Web Token (JWT)"
  }, {
    "name" : "Order service",
    "description" : "CRUD operations for order service. User must be authorized with some resources."
  } ],
  "paths" : {
    "/auth" : {
      "post" : {
        "tags" : [ "Authentication services" ],
        "summary" : "Authenticating a user",
        "description" : "Authenticating a user with their username/ password and issuing a JSON Web Token (JWT)",
        "operationId" : "authenticateUser",
        "requestBody" : {
          "content" : {
            "application/x-www-form-urlencoded" : {
              "schema" : {
                "type" : "object",
                "properties" : {
                  "username" : {
                    "type" : "string"
                  },
                  "password" : {
                    "type" : "string"
                  }
                }
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "Authenticated user based on the given information",
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "200" : {
            "description" : "success"
          },
          "403" : {
            "description" : "Wrong username or password."
          },
          "500" : {
            "description" : "Internal Server Error."
          }
        }
      }
    },
    "/orders/{id}" : {
      "get" : {
        "tags" : [ "Order service" ],
        "summary" : "Get order by id",
        "description" : "This action published for everyone",
        "operationId" : "get",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "200" : {
            "description" : "Get order by id"
          }
        }
      },
      "delete" : {
        "tags" : [ "Order service" ],
        "summary" : "Delete order by id",
        "description" : "Only Admin can do this action",
        "operationId" : "delete",
        "parameters" : [ {
          "name" : "id",
          "in" : "path",
          "required" : true,
          "schema" : {
            "type" : "integer",
            "format" : "int32"
          }
        } ],
        "responses" : {
          "default" : {
            "description" : "default response",
            "content" : {
              "application/json" : { },
              "application/xml" : { },
              "text/plain" : { }
            }
          }
        }
      }
    },
    "/orders" : {
      "put" : {
        "tags" : [ "Order service" ],
        "summary" : "Update order",
        "description" : "Admin and Customer can do this action",
        "operationId" : "update",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "application/xml" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "text/plain" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "default response",
            "content" : {
              "application/json" : { },
              "application/xml" : { },
              "text/plain" : { }
            }
          }
        }
      },
      "post" : {
        "tags" : [ "Order service" ],
        "summary" : "Insert an order",
        "operationId" : "insert",
        "requestBody" : {
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "application/xml" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            },
            "text/plain" : {
              "schema" : {
                "$ref" : "#/components/schemas/Order"
              }
            }
          }
        },
        "responses" : {
          "default" : {
            "description" : "Inserted an order based on the given information",
            "content" : {
              "application/json" : {
                "schema" : {
                  "type" : "string"
                }
              }
            }
          },
          "200" : {
            "description" : "success"
          },
          "401" : {
            "description" : "User cannot access this resource."
          },
          "403" : {
            "description" : "User not authorized."
          },
          "500" : {
            "description" : "Internal Server Error."
          }
        }
      }
    }
  },
  "components" : {
    "schemas" : {
      "Order" : {
        "type" : "object",
        "properties" : {
          "id" : {
            "type" : "integer",
            "format" : "int32"
          },
          "name" : {
            "type" : "string"
          }
        }
      }
    },
    "securitySchemes" : {
      "bearerAuth" : {
        "type" : "http",
        "scheme" : "bearer",
        "bearerFormat" : "JWT"
      }
    }
  }
}

  • Kiểm tra Swagger UI đã hiển thị đầy đủ các API document như đã config trong file WebContent/WEB-INF/openapi.yaml và đúng như mô tả trong Swagger Annotation. Truy cập địa chỉ: http://localhost:8080/swagger-ui/index.html

Các bạn có thể chạy thử POST /auth để lấy jwt token và chọn Authorize để config token cho các request đến API cần chứng thực.

Tiếp tục, chúng ta sẽ kiểm tra thông tin đã mô tả trong phương thức OrderService#insert.

Như các bạn có thể thấy, Swagger có thể generate ra 1 file config (.json hoặc .yaml) từ chính code của chương trình. Tuy nhiên phần UI của swagger lại khá rườm rà không đẹp lắm. Để có một beautiful document cho các API, các bạn có thể tìm hiểu thêm về Slate – một công cụ open source giúp generate ra các file html, css,… từ 1 file config .md . Slate có UI cực kì đẹp và khoa học.

Slate rất đẹp nhưng lại không thể generate ra file config như swagger. Vì vậy để tận dụng thế mạnh của Swagger và Slate, chúng ta cần phải convert 1 file config.yaml của Swagger sang 1 file config.md. Sau đó dùng Slate để generate ra các file html, css,… để publish ra bên ngoài. Chi tiết các bạn có thể tham khảo thêm tại link sau: https://github.com/lord/slate.

Bài viết đến đây là hết. Cám ơn các bạn đã quan tâm và theo dõi.

Tài liệu tham khảo:

  • https://swagger.io/docs/specification/about/
  • https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X—Annotations
  • https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md
  • https://www.openapis.org/
4.8
05
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Java Webservice, REST Được gắn thẻ: Jersey, REST, Swagger, Webservice

Cài đặt và sử dụng Swagger UI
Làm thế nào để Test Jersey Rest API với JUnit?

Có thể bạn muốn xem:

  • Làm thế nào để Test Jersey Rest API với JUnit? (22/08/2019)
  • Java Web Services – JAX-WS – SOAP (27/05/2019)
  • Tìm hiểu về xác thực và phân quyền trong ứng dụng (01/07/2019)
  • Test REST Web Service đơn giản hơn với REST Assured (26/08/2019)
  • Rest Web service: Filter và Interceptor với Jersey 2.x (P1) (25/06/2019)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (97382 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97030 lượt xem)
  • Giới thiệu Design Patterns (86697 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (85530 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83078 lượt xem)

Nội dung bài viết

  • 1 Tích hợp JAX-RS REST project với Swagger UI để tạo API document một cách tự động
  • 2 Ví dụ

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link