通过Swagger管理API:API Management学习第一篇

2018-07-30 14:47:02 浏览数 (1)

前言

本文仅代表作者的个人观点;

本篇书写过程中,咨询了我的同事舒力,Kylin,在此表示感谢;

本文的内容仅限于技术探讨,不能作为指导生产环境的素材;

本文素材是红帽公司产品技术和手册;

本文分为系列文章,将会有多篇,初步预计将会有26篇。

一、Swagger

3 Scale有个很好的功能,它提供ActiveDocs实时文档。它基于Swagger框架,提供了一种记录API的方法,并包含在Developer Portal中。

随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染,变成了:前端渲染、先后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远。 前端和后端的唯一联系,变成了API接口;API文档变成了前后端开发人员联系的纽带,变得越来越重要,swagger就是一款让你更好的书写API文档的框架。

那么,swagger档如何生成?

在源码中进行如下定义,应用运行的时候,会自动生成。

二、一个Restful API例子的源码分析

我们看一个Restful API,这个API是可以查询种子信息的。

的两个源码文件:

我们看一下这个Restful API的源码:

查看第一个源码文件,它定义了root 上下文:

$ cat ProductsApplication.java

package com.redhat.service;

import javax.ws.rs.ApplicationPath;

import javax.ws.rs.core.Application;

import io.swagger.jaxrs.config.BeanConfig;

@ApplicationPath("rest")

public class ProductsApplication extends Application {

public ProductsApplication(){

BeanConfig beanConfig = new BeanConfig();

beanConfig.setVersion("1.0.2");

beanConfig.setSchemes(new String[]{"http"});

beanConfig.setHost("localhost:8080");

beanConfig.setBasePath("/rest");

beanConfig.setResourcePackage("com.redhat.service");

beanConfig.setScan(true);

beanConfig.setTitle("Products");

beanConfig.setDescription("RHMart's Products API");

beanConfig.setPrettyPrint(true);

}

}

查看第二个源码文件,ProductServices.java它定义了http方法和path:

$ cat ProductServices.java

package com.redhat.service;

import java.util.List;

import javax.inject.Inject;

import javax.ws.rs.Consumes;

import javax.ws.rs.DELETE;

import javax.ws.rs.GET;

import javax.ws.rs.POST;

import javax.ws.rs.Path;

import javax.ws.rs.PathParam;

import javax.ws.rs.Produces;

import javax.ws.rs.core.MediaType;

import com.redhat.model.JsonResponse;

import com.redhat.model.Product;

import com.redhat.model.ProductDao;

import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

@Path("/services")

@Api(value="services")

@Produces("application/json")

public class ProductServices {

@Inject

ProductDao productDAO;

@ApiOperation(value="Get all Products")

@Path("/products")

@GET

@Produces(MediaType.APPLICATION_JSON)

public List<Product> getAllProducts(){

List<Product> prod= productDAO.getAll();

return prod;

}

@ApiOperation(value="Get a Product by ID")

@Path("/product/{productId}")

@GET

@Produces(MediaType.APPLICATION_JSON)

public Product getProduct(@PathParam("productId") Integer productId){

return productDAO.getProductById(productId);

}

@ApiOperation(value="Create a new Product")

@Path("/product")

@POST

@Consumes(MediaType.APPLICATION_JSON)

@Produces(MediaType.APPLICATION_JSON)

public JsonResponse createProduct(Product product){

JsonResponse jr = new JsonResponse("");

try{

productDAO.createProduct(product);

}catch(Exception e){jr.setMessage(e.getMessage()); return jr;};

jr.setMessage("Product created");

return jr;

}

@ApiOperation(value="Delete a Product by ID")

@Path("/product/{productId}")

@DELETE

@Produces(MediaType.APPLICATION_JSON)

public JsonResponse deleteProduct(@PathParam("productId") Integer productId){

JsonResponse jr = new JsonResponse("");

try{

productDAO.deleteProduct(productId);

}catch (Exception e) { jr.setMessage(e.getMessage()); return jr;};

jr.setMessage("Product " productId " deleted");

return jr;

}

}

我们再看看之前curl的链接:curl -v -k http://products-api-david-products-api.apps.na39.openshift.opentlc.com/rest/services/product/1

上面黄色部分的rest,就是root上下文,在 ProductsApplication.java中定义的;

红色部分的/service,是定义的path,在ProductServices.java中定义的;

绿色部分的/product/{productId},是定义的path,在ProductServices.java中定义的;

那么,源码如何与数据库进行通讯呢?

查看源码中的数据访问对象: List<Product> prod= productDAO.getAll(),找到import的内容:

import com.redhat.model.ProductDao;

切换到import com.redhat.model目录中,查看源码文件:

先查看ProductDao.java,它定义了接口:

在查看访问数据库的实现,可以看到,通过CDJ注入了EM,也就是一个实体类,unitName="primary"

接下来,我们再查看unitName="primary"的出处,查看./src/main/resources/META-INF/persistence.xml文件,里面定义了primary的datasource,通过JPA的方式访问数据库:

/Products/src/main/webapp/WEB-INF/Products-ds.xml中进行查看:

上图可以看出,应用对jdbc的访问,最终是:

jdbc:postgresql://productsdb:5432/RHMart

而productsdb:5432/,实际上就是数据库的pod SVC。也就是说,应用的pod,通过SVC方式访问数据库。这方访问方式,叫application datasource。

还有一种叫server datasource。这种情况下,将JDBC的配置在app server的配置文件中,如EAP的standalone.xml中。

三、Restful API在OCP上的部署

在OCP上,为Products API应用程序创建一个新项目:

部署和测试产品API服务

将products-api模板导入OpenShift环境:

使用products-api模板创建一个新应用程序:

测试product API服务是否接受请求并返回正确的响应:

返回结果:

可以通过执行以下命令检索所有产品的列表:

[

{

"productid": 1,

"productname": "Ninja Blender",

"productprice": 320.0

},

{

"productid": 2,

"productname": "Ninja Blender Pro",

"productprice": 515.0

},

{

"productid": 3,

"productname": "Kicthenhelp Juicer",

"productprice": 149.99

},

{

"productid": 4,

"productname": "ArtCuisine Toaster",

"productprice": 79.99

},

{

"productid": 5,

"productname": "White and Decor Toaster Oven",

"productprice": 49.99

},

{

"productid": 6,

"productname": "Mexpresso Maker",

"productprice": 199.99

},

{

"productid": 7,

"productname": "Mini Fridge",

"productprice": 229.99

},

{

"productid": 8,

"productname": "Slow-Cooker Pot",

"productprice": 44.99

},

{

"productid": 9,

"productname": "SungSamn 4-Door Refrigerator",

"productprice": 2199.99

},

{

"productid": 10,

"productname": "Hanilton 12 cup Food Processor",

"productprice": 49.99

}

]

于PostgreSQL的Products数据库中的种子列表。

四、通过swagger工具分析swagger文件

product service提供了一个swagger.yaml配置文件,用于记录它公开的资源。

要访刚才应用的swagger.yaml配置文件,请将浏览器指向以下命令的输出:

echo http://"$(oc get route/products-api -o template --template {{.spec.host}})"/rest/swagger.yaml

结果:

http://products-api-david-products-api.apps.na39.openshift.opentlc.com/rest/swagger.yaml

我们看一下swagger文件中的内容:

---

swagger: "2.0"

info:

description: "RHMart's Products API"

version: "1.0.2"

title: "Products"

host: "localhost:8080"

basePath: "/rest"

tags:

- name: "services"

schemes:

- "http"

paths:

/services/product:

post:

tags:

- "services"

summary: "Create a new Product"

description: ""

operationId: "createProduct"

consumes:

- "application/json"

produces:

- "application/json"

parameters:

- in: "body"

name: "body"

required: false

schema:

$ref: "#/definitions/Product"

responses:

200:

description: "successful operation"

schema:

$ref: "#/definitions/JsonResponse"

/services/product/{productId}:

get:

tags:

- "services"

summary: "Get a Product by ID"

description: ""

operationId: "getProduct"

produces:

- "application/json"

parameters:

- name: "productId"

in: "path"

required: true

type: "integer"

format: "int32"

responses:

200:

description: "successful operation"

schema:

$ref: "#/definitions/Product"

delete:

tags:

- "services"

summary: "Delete a Product by ID"

description: ""

operationId: "deleteProduct"

produces:

- "application/json"

parameters:

- name: "productId"

in: "path"

required: true

type: "integer"

format: "int32"

responses:

200:

description: "successful operation"

schema:

$ref: "#/definitions/JsonResponse"

/services/products:

get:

tags:

- "services"

summary: "Get all Products"

description: ""

operationId: "getAllProducts"

produces:

- "application/json"

parameters: []

responses:

200:

description: "successful operation"

schema:

type: "array"

items:

$ref: "#/definitions/Product"

definitions:

Product:

type: "object"

properties:

productid:

type: "integer"

format: "int32"

productname:

type: "string"

productprice:

type: "number"

format: "double"

JsonResponse:

type: "object"

properties:

message:

type: "string"

我们使用在线https://editor.swagger.io/编辑器,导入刚下载的yaml文件。

导入以后,就可以看到四个http定义的方法:

将代码的地址从localhost:8080改成实际地址(第六行):

我们展开GET,点击try it out:

ID号输入1

查看执行方法:

查看执行结果:

接下来,我们换一个path测试,使用:

点击try it out:

输出结果是所有信息:

魏新宇

  • 红帽资深解决方案架构师
  • 专注开源云计算、容器及自动化运维在金融行业的推广
  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。
  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。

0 人点赞