微信号:david-share

介绍:乐于分享,才有进步.

技术派:谁说API网关只能集成REST APIs?

2018-05-15 16:56 魏新宇

一、API网关对API的集成


REST APIs的特点有:

  • 数据驱动

  • 允许多种数据格式(JSON,XML,文本)

  • 使用HTTPS协议的安全性

  • 轻量级框架


API的REST不适用的场景:

  • 使用非HTTP协议

  • 有状态

  • 受限于HTTP动词太少


接下来,我来看一种非REST APIs协议--SOAP。

WebService有两种方式,一是SOAP协议方式,在这种方式下需要WSDL,UDDI等,二是REST方式,这种方式不需要WSDL,UDDI等。


SOAP(原为Simple Object Access Protocol首字母缩写,即简单对象访问协议)是交换数据的一种协议规范,使用在计算机网络Web服务(web service)中,交换带结构信息。SOAP为了简化网页服务器(Web Server)从XML数据库中提取数据时,节省去格式化页面时间,以及不同应用程序之间按照HTTP通信协议,遵从XML格式执行资料互换,使其抽象于语言实现、平台和硬件。


用一个简单的例子来说明SOAP使用过程,一个SOAP消息可以发送到一个具有Web Service功能的Web站点,例如,一个含有房价信息的数据库,消息的参数中标明这是一个查询消息,此站点将返回一个XML格式的信息,其中包含了查询结果(价格,位置,特点,或者其他信息)。由于数据是用一种标准化的可分析的结构来传递的,所以可以直接被第三方站点所利用。


SOAP它的特点有:

  • 功能驱动

  • WS-Security

  • 调用不能被缓存

  • 重载荷

  • XML数据格式


其他类型的非REST APIs协议还有:

Apache Thrift、Apache Spark and Python、Apache Avro


其中,Apache Thrift的特点有:

  • 接口定义语言

  • 多种目标语言

  • 低级传输(套接字,管道等)

  • 多种协议(JSON,紧凑型,二进制等)

  • 示例:Facebook FBOSS API,Evernote SDK,Elasticsearch API


Evernote就是印象笔记的国际版,这个我天天在用:



在3Scale中,我们可以通过 Fuse 作为集成平台,将非REST APIs集成进来。Fuse既可以集成REST也可以集成非REST的API:

  • Camel route exposing REST/HTTP endpoint

  • Camel producer endpoint using non-REST endpoin


也就说说,对于如SOAP类的API,我们会将它和Fuse进行集成,然后再将Fuse集成到API网关上。


二、实验验证

本实验中,我们部署一个SOAP-based JEE application。


我们先看一下应用的web service定义:

<wsdl:portType name="Stores">

    <wsdl:operation name="getAllStores">

      <wsdl:input message="tns:getAllStoresRequest"/>

      <wsdl:output message="tns:getAllStoresResponse"/>

    </wsdl:operation>

    <wsdl:operation name="getStore">

        <wsdl:input message="tns:getStoreRequest"></wsdl:input>

        <wsdl:output message="tns:getStoreResponse"></wsdl:output>

    </wsdl:operation>

    <wsdl:operation name="createStore">

        <wsdl:input message="tns:createStoreRequest"></wsdl:input>

        <wsdl:output message="tns:createStoreResponse"></wsdl:output>

    </wsdl:operation>

    <wsdl:operation name="deleteStore">

        <wsdl:input message="tns:deleteStoreRequest"></wsdl:input>

        <wsdl:output message="tns:deleteStoreResponse"></wsdl:output>

    </wsdl:operation>

  </wsdl:portType>

  <wsdl:binding name="StoresSOAP" type="tns:Stores">


查看源码:

查看SOAP web service的实施部分(我们看到源码中的四个public class最终会在前端展现):

@WebService(endpointInterface="com.redhat.service.Stores")

public class StoresWS implements Stores {


        @Inject

        StoreDao storeDAO;


        @Override

        public String createStore(Store store) {

                store = new Store(store.getStoreName(),store.getStoreLat(),store.getStoreLong());

                storeDAO.createStore(store);

                return "Store ID:" + store.getStoreID() + " CREATED";

        }


        @Override

        public StringdeleteStore(int storeID) {

                storeDAO.deleteStore(storeID);

                return "Store ID: " + storeID + " DELETED";

        }


        @Override

        public Store getStore(int storeID) {

                return storeDAO.getStoreById(storeID);

        }


        @Override

        public StoresType getAllStores() {

                StoresType st = new StoresType();

                st.store = storeDAO.getAll();

                return st;

        }


}


这个应用将会部署在基于Oenshift的EAP上。


接下来,部署应用。先创建一个部署应用的project:

创建一个部署应用的模板:

接下来,部署应用:

--> Deploying template "david-stores-api/stores-soap" to project david-stores-api


     Red Hat JBoss EAP 7.0 (no https)

     ---------

     Stores SOAP Template.


     A new EAP 7 based application has been created in your project.



     * With parameters:

        * Application Name=stores-soap

        * Custom http Route Hostname=stores-api-david.apps.na1.openshift.opentlc.com

        * Git Repository URL=https://github.com/gpe-mw-training/3scale_development_labs

        * Git Reference=master

        * Context Directory=Stores

        * Queues=

        * Topics=

        * A-MQ cluster password=1wWTWDuk # generated

        * Github Webhook Secret=GCubd7Tr # generated

        * Generic Webhook Secret=hi5Aiw2r # generated

        * ImageStream Namespace=openshift

        * JGroups Cluster Password=RsIIhtvr # generated

        * Deploy Exploded Archives=false

        * Maven mirror URL=

        * ARTIFACT_DIR=

        * DATABASE_SERVICE_NAME=storesdb


--> Creating resources ...

    configmap "create-db" created

    secret "storesdb" created

    service "storesdb" created

    deploymentconfig "storesdb" created

    service "stores-soap" created

    route "stores-soap" created

    imagestream "stores-soap" created

    buildconfig "stores-soap" created

    deploymentconfig "stores-soap" created

--> Success

    Build scheduled, use 'oc logs -f bc/stores-soap' to track its progress.

    Run 'oc status' to view your app.


查看应用的部署结果:

查看应用的路由:

通过浏览器进行访问:http://stores-api-david.apps.na1.openshift.opentlc.com/StoresWS?wsdl

接下来,我们使用一个在线的web based soap客户端:

输入刚才的地址进行浏览:

可以看到应用web service定义的内容(我们看到源码中的四个public class在前端展现):

点击call function,输出结果是:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:getAllStoresResponse xmlns:ns2="http://www.rhmart.com/Stores/"><Stores><store><storeID>1</storeID><storeName>Downtown
  Store</storeName><storeLat>-34.6052704</storeLat><storeLong>-58.3791766</storeLong></store><store><storeID>2</storeID><storeName>EastSide
  Store</storeName><storeLat>-34.5975668</storeLat><storeLong>-58.3710199</storeLong></store></Stores></ns2:getAllStoresResponse></soap:Body></soap:Envelope>


接下来,我们部署fuse:

oc project $OCP_PROJECT_PREFIX-stores-api


oc create -f $HOME/lab/3scale_development_labs/templates/stores-fis.json


oc new-app --template=stores-fis --param ROUTE_HOST=stores-fis-$OCP_PROJECT_PREFIX.$OCP_WILDCARD_DOMAIN

fis构建并部署成功。


接下来,登录Openshift web console,查看fsi pod,打开java console:


查看路由信息:

我们可以看到,fuse的route已经将soap应用的各个功能模块( createStore、deleteStore、getAllStores、getStore)集成:

在源码层,一个路由调用SOAP的方法是:

    <route customId="true" id="soapRoute">

        <from customId="true" id="_from5" uri="direct:soap"/>

        <toD customId="true" id="tod" uri="cxf:bean:wsStores?defaultOperationName=${header.soapMethod}&amp;exchangePattern=InOut"/>

        <setBody customId="true" id="_setBodySoap">

            <simple>${body[0]}</simple>

        </setBody>

        <setHeader customId="true" headerName="Content-Type" id="_setHeaderContextType">

            <constant>application/json</constant>

        </setHeader>

    </route>


将curl请求发送到stores-fis路由以调用REST Web服务,并检查是否调用了SOAP Web服务并将响应转换为application / json:


我们查看OCP中fuse的路由:


 $ curl -k stores-fis-david.apps.na1.openshift.opentlc.com/allstores


{"store":[{"storeID":1,"storeName":"Downtown\n  Store","storeLat":-34.6052704,"storeLong":-58.3791766},{"storeID":2,"storeName":"EastSide\n  Store","storeLat":-34.5975668,"storeLong":-58.3710199}]}


截至到目前,REST-SOAP Camel代理现在已正确部署,我们可以开始配置APIcast网关以使用此REST端点与SOAP Web服务进行通信。


创建应用到apicast-staging and apicast-production的路由:


接下来,我们到3scale上对应用进行集成.


创建应用:

创建app plan:

发布plan:

创建应用,选择刚才创建的app plan:


接下来,对应用进行API集成:

http://stores-fis-david.apps.na1.openshift.opentlc.com:80

https://stores-staging-apicast-david.apps.na1.openshift.opentlc.com:443

https://stores-production-apicast-david.apps.na1.openshift.opentlc.com:443


测试集成成功:

Prompt应用到生产:

接下来,我们分别访问两个环境中的引用:

Staging Environment

https://stores-staging-apicast-david.apps.na1.openshift.opentlc.com:443


Production Environment

https://stores-production-apicast-david.apps.na1.openshift.opentlc.com:443


 $ curl -k "https://stores-staging-apicast-david.apps.na1.openshift.opentlc.com:443/allstores?user_key=d2a880ba1428dd8a505acae61349108f"


{"store":[{"storeID":1,"storeName":"Downtown\n  Store","storeLat":-34.6052704,"storeLong":-58.3791766},{"storeID":2,"storeName":"EastSide\n  Store","storeLat":-34.5975668,"storeLong":-58.3710199}]}


 $ curl -k "https://stores-production-apicast-david.apps.na1.openshift.opentlc.com:443/allstores?user_key=d2a880ba1428dd8a505acae61349108f"

{"store":[{"storeID":1,"storeName":"Downtown\n  Store","storeLat":-34.6052704,"storeLong":-58.3791766},{"storeID":2,"storeName":"EastSide\n  Store","storeLat":-34.5975668,"storeLong":-58.3710199}]}

测试成功!



接下来,我们将Stock API部署到运行在OpenShift上的JBoss EAP容器上。 Stock数据在两个数据库:MySQL和PostgreSQL。 JBoss Data Virtualization用于提供数据虚拟化,并将组合数据视图作为OData REST服务提供。


创建stock API business service applications:

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

oc create -f $HOME/lab/3scale_development_labs/templates/stock-api.json


将数据源环境变量security添加到项目中:

oc secret new datavirt-app-config $HOME/lab/3scale_development_labs/Stock/datasources.env


创建SA:

jboss@rhtapimgmt / $  oc create serviceaccount datavirt-service-account

serviceaccount "datavirt-service-account" created


jboss@rhtapimgmt / $  oc policy add-role-to-user view system:serviceaccount:stock-api:datavirt-service-account

role "view" added: "system:serviceaccount:stock-api:datavirt-service-account"


接下来,部署应用:

oc new-app --template=stock-api --param HOSTNAME_HTTP=stock-api-$OCP_PROJECT_PREFIX.$OCP_WILDCARD_DOMAIN


创建成功以后:

一旦API和数据库窗格正在运行,通过向端点发出请求来测试odata服务:

{"@odata.context":"$metadata#stock","value":[{"productid":1,"amount":20.0,"storeid":1},{"productid":1,"amount":30.0,"storeid":2},{"productid":2,"amount":30.0,"storeid":1},{"productid":2,"amount":14.0,"storeid":2},{"productid":3,"amount":1.0,"storeid":1},{"productid":3,"amount":40.0,"storeid":2},{"productid":4,"amount":14.0,"storeid":1},{"productid":4,"amount":100.0,"storeid":2},{"productid":5,"amount":22.0,"storeid":1},{"productid":5,"amount":2.0,"storeid":2},{"productid":6,"amount":880.0,"storeid":1},{"productid":6,"amount":10.0,"storeid":2},{"productid":7,"amount":1200.0,"storeid":1},{"productid":7,"amount":32.0,"storeid":2},{"productid":8,"amount":532.0,"storeid":1},{"productid":8,"amount":1.0,"storeid":2},{"productid":9,"amount":10.0,"storeid":1},{"productid":9,"amount":123.0,"storeid":2},{"productid":10,"amount":1.0,"storeid":1},{"productid":10,"amount":730.0,"storeid":2}]}


接下来,我们可以创建路由,将stock-api和APIcast gateway关联:

oc create route edge stock-staging-route \  --service=apicast-staging \  --hostname=stock-staging-apicast-$OCP_PROJECT_PREFIX.$OCP_WILDCARD_DOMAIN$


oc create route edge stock-production-route \  --service=apicast-production \  --hostname=stock-production-apicast-$OCP_PROJECT_PREFIX.$OCP_WILDCARD_DOMAIN


然后再将应用集成到API网关上,这次集成的时候,mapping规则增加:


API Client选择:

然后就可以通过API网关的理由访问API了。


由于操作步骤与之前类似,这里不再详细赘述。




魏新宇

  • "大魏分享"运营者、红帽资深解决方案架构师

  • 专注开源云计算、容器及自动化运维在金融行业的推广

  • 拥有MBA、ITIL V3、Cobit5、C-STAR、TOGAF9.1(鉴定级)等管理认证。

  • 拥有红帽RHCE/RHCA、VMware VCP-DCV、VCP-DT、VCP-Network、VCP-Cloud、AIX、HPUX等技术认证。


文章打赏随意(转发和赞赏都是对作者原创的鼓励):


 
大卫分享 更多文章 后容器时代技术制高点:API管理平台3Scale的架构设计与部署 深度分析:为啥说API是IT的未来? 五大Kubernetes最佳实践 API经济学的落地:API Gateway的技术探讨.第一篇 Istio如何同时实现Hytrix|Ribbon|Zuul|微服务安全的功能?:为微服务引入Istio服务网格(下)
猜您喜欢 Android网络编程概述 WatchOS 2: Hello, World 《一句话证明你懂linux》的有趣评论 【20130509】LinkedIn:2亿用户的大数据分析 多元线性回归——OLS回归模型拟合(三)