一、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}&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了。
由于操作步骤与之前类似,这里不再详细赘述。