(1)需要将swagger json转换成amazon api gateway 所需要的格式(根据Method Request中

Request Paths
URL Query String Parameters
HTTP Request Headers

--->  Integration Request

中对应的:

URL Path Parameters
URL Query String Parameters
HTTP Headers

)并在Integration Request中填写接口的相对应的信息:

Integration type
HTTP method
Endpoint URL
Content Handling

相关说明:

ams只是遵守了swagger2的规范,并没有完全支持aws api gateway的扩展

aws api gateway 的json数据,
You can fully define an API Gateway API in Swagger using the x-amazon-apigateway-auth and x-amazon-apigateway-integration extensions-------------这个说法是错误的。因为Spring fox2.6.1中的@Extension doesn't allow child @Extension.

"x-amazon-apigateway-auth" : {
"type" : "aws_iam"
},
"x-amazon-apigateway-integration" : {
"type" : "aws",
"uri" : "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/arn:aws:lambda:us-east-1:MY_ACCT_ID:function:helloWorld/invocations",
"httpMethod" : "POST",
"credentials" : "arn:aws:iam::MY_ACCT_ID:role/lambda_exec_role",
"requestTemplates" : {
"application/json" : "json request template 2",
"application/xml" : "xml request template 2"
},
"requestParameters" : {
"integration.request.path.integrationPathParam" : "method.request.querystring.latitude",
"integration.request.querystring.integrationQueryParam" : "method.request.querystring.longitude"
},
"cacheNamespace" : "cache-namespace",
"cacheKeyParameters" : [],
"responses" : {
"2\\d{2}" : {
"statusCode" : "200",
"responseParameters" : {
"method.response.header.test-method-response-header" : "integration.response.header.integrationResponseHeaderParam1"
},
"responseTemplates" : {
"application/json" : "json 200 response template",
"application/xml" : "xml 200 response template"
}
},
"default" : {
"statusCode" : "400",
"responseParameters" : {
"method.response.header.test-method-response-header" : "'static value'"
},
"responseTemplates" : {
"application/json" : "json 400 response template",
"application/xml" : "xml 400 response template"
}
}
}
}

@Extension/@ExtensionProperty usage for Api Gateway Extension json

https://github.com/springfox/springfox/issues/1212

However, I am currently stuck at using the @Extension/@ExtenstionProperty to reflect the correct json for requestTemplates and requestParameters attributes.
Both of them contain multiple name/value attributes rather than a simple name/value pair.
@Extension doesn't allow child @Extension.

转换的过程使用了Swagger2.0内置的数据结构:

import io.swagger.models.Operation;
import io.swagger.models.Path;
import io.swagger.models.Swagger;
import io.swagger.models.parameters.HeaderParameter;
import io.swagger.models.parameters.Parameter;
import io.swagger.models.parameters.QueryParameter;
import io.swagger.parser.SwaggerParser;
import io.swagger.util.Json;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map; import static java.lang.String.format; @Component
public class AwsConverterUtils {
private static final Logger LOGGER = LoggerFactory.getLogger(AwsConverterUtils.class); private static final String EXTENSION_INTEGRATION = "x-amazon-apigateway-integration"; public String fillApiGatewayIntegration(String filePath) throws IOException {
LOGGER.info("Attempting to create API from Swagger definition.Swagger file: {}", filePath); Swagger swagger = parse(filePath);
Map<String, Path> originalPaths = swagger.getPaths();
Map<String, Path> newPaths = new HashMap<>(originalPaths);
swagger.setPaths(newPaths);
Iterator<Map.Entry<String, Path>> iterator = originalPaths.entrySet().iterator(); while (iterator.hasNext()) {
Map.Entry<String, Path> next = iterator.next();
//path的Key是RequestPath,value path是各种Operation(get,post等相关操作的集合)
Path path = next.getValue();
String appRequestPath = next.getKey();
LOGGER.info("requestPath:" + appRequestPath); //处理每个path中的数据,根据规则把aws需要的数据 填充上去
// x-amazon-apigateway-integration
String finalAppRequestPath = appRequestPath;
Map<String, Operation> ops = getOperations(path);
ops.entrySet().forEach(x -> {
generateXAmazon(finalAppRequestPath, x.getKey(), x.getValue());
LOGGER.info(format("with method %s", x.getKey()));
});
}
String data = Json.pretty(swagger); String parent = Paths.get(filePath).getParent().toString();
LOGGER.info("The file directory:" + parent);
File awsSwaggerJson = new File(parent, "awsApiGatewaySwagger.json");
FileUtils.write(awsSwaggerJson, data, "UTF-8");
return awsSwaggerJson.getAbsolutePath();
} private Map<String, Operation> getOperations(Path path) {
final Map<String, Operation> ops = new HashMap<>(); addOp(ops, "get", path.getGet());
addOp(ops, "post", path.getPost());
addOp(ops, "put", path.getPut());
addOp(ops, "delete", path.getDelete());
addOp(ops, "options", path.getOptions());
addOp(ops, "patch", path.getPatch()); return ops;
} private void addOp(Map<String, Operation> ops, String method, Operation operation) {
if (operation != null) {
ops.put(method, operation);
}
} private Swagger parse(String filePath) {
final Swagger swagger = new SwaggerParser().read(filePath); if (swagger != null && swagger.getPaths() != null) {
LOGGER.info("Parsed Swagger with " + swagger.getPaths().size() + " paths");
}
return swagger;
} private void generateXAmazon(String appRequestPath, String requestMethod, Operation op) {
//检查是否需要v参数,项目中需要包含v的输入,有些接口入参没有入参,因此就没有这个参数
List<Parameter> opParameters = op.getParameters();
Map<String, Object> vendorExtensions = op.getVendorExtensions();
Map<String, Object> integ;
if (vendorExtensions.containsKey(EXTENSION_INTEGRATION)) {
integ = Json.mapper().convertValue(vendorExtensions.get(EXTENSION_INTEGRATION), Map.class);
} else {
//如果没有包含x-amazon-apigateway-integration节点,则设置type,httpMethod,uri
// "x-amazon-apigateway-integration" : {
// "type" : "http",
// "httpMethod" : "POST",
// "uri" : "http://apiId.ap-southeast-1.elb.amazonaws.com/subject/{subjectId}",
integ = new HashMap<>();
integ.put("type", Constants.IntegrationType);
integ.put("httpMethod", requestMethod);
integ.put("uri", Constants.ALB_DNS + appRequestPath);
} //处理responses节点
// "responses" : {
// "default" : {
// "statusCode" : "200"
// }
// },
String keyResponses = "responses";
if (!integ.containsKey(keyResponses)) {
Map<String, String> responseData = new HashMap<>();
responseData.put("statusCode", "200");
Map<String, Map> defaultRes = new HashMap<>();
defaultRes.put("default", responseData);
integ.put(keyResponses, defaultRes);
} // 处理requestParameters节点
// "requestParameters" : {
// "integration.request.path.bizId" : "method.request.path.bizId",
// "integration.request.querystring.content" : "method.request.querystring.content"
// }
String keyRequestParameters = "requestParameters";
if (integ.containsKey(keyRequestParameters)) {
LOGGER.info("requestParameters had defined ");
return;
} String keyPrefix = "integration.request.";
String valuePrefix = "method.request."; Map<String, String> requestParameters = new HashMap<>();
for (Parameter parameter : opParameters) {
String in = parameter.getIn();
String paramType = in;
if (in.equals("query")) {
paramType = "querystring";
}
String name = parameter.getName();
requestParameters.put(keyPrefix + paramType + "." + name, valuePrefix + paramType + "." + name);
}
Parameter authorization = new HeaderParameter();
authorization.setIn("header");
authorization.setName("Authorization");
opParameters.add(authorization);
op.setParameters(opParameters); requestParameters.put(keyPrefix + "header.Authorization", valuePrefix + "header.Authorization");
LOGGER.info("automatically generate:" + requestParameters);
integ.put(keyRequestParameters, requestParameters);
vendorExtensions.put(EXTENSION_INTEGRATION, integ);
} }

参考的代码:

What's Swagger?

The goal of Swagger™ is to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection. When properly defined via Swagger, a consumer can understand and interact with the remote service with a minimal amount of implementation logic. Similar to what interfaces have done for lower-level programming, Swagger removes the guesswork in calling the service.

Check out Swagger-Spec for additional information about the Swagger project, including additional libraries with support for other languages and more.

Usage

Using the swagger-parser is simple. Once included in your project, you can read a OpenAPI Specification from any location:

import io.swagger.parser.SwaggerParser;
import io.swagger.models.Swagger;

// ... your code

// read a swagger description from the petstore

Swagger swagger = new SwaggerParser().read("http://petstore.swagger.io/v2/swagger.json");

You can read from a file location as well:

Swagger swagger = new SwaggerParser().read("./path/to/swagger.json");

And with the swagger-compat-spec-parser module, you can read older formats, and convert them into swagger 2.0:

Swagger swagger = new SwaggerCompatConverter().read("http://petstore.swagger.io/api/api-docs");

If your swagger resource is protected, you can pass headers in the request:

import io.swagger.models.auth.AuthorizationValue;

// ... your code

// build a authorization value
AuthorizationValue mySpecialHeader = new AuthorizationValue()
.keyName("x-special-access") // the name of the authorization to pass
.value("i-am-special") // the value of the authorization
.type("header"); // the location, as either `header` or `query` // or in a single constructor
AuthorizationValue apiKey = new AuthorizationValue("api_key", "special-key", "header");
Swagger swagger = new SwaggerParser().read(
"http://petstore.swagger.io/v2/swagger.json",
Arrays.asList(mySpecialHeader, apiKey)
);

And, if your intent is to read in a Swagger 1.2 spec so that you can then output a Swagger 2 spec to string/file then you are in luck - you have the spec in pojo form, now pass it to pretty() and you're good to go.

String swaggerString = Json.pretty(swagger);

https://github.com/helloworldtang/swagger-parser

第二个坑:
Swagger定义的definitions类型的json数据,aws不识别,需要使用@org.springframework.web.bind.annotation.ModelAttribute注解。path类型的URL,如果使用对象接收,需要使用@ApiImplicitParam单独定义一个paramType字段为“path"的

不然类型为用queryString,aws上会解析错误
definitions节点:

  },
"definitions": {
"Empty": {
"type": "object"
}
},
"x-amazon-apigateway-documentation": {

第三个坑:

"paths": {
"/subject/{bizId}/complaint": {
.....
,
"/subject/{subjectId}/profile": {
"get": { Import the format of the data above, will cause the wrong below: Your API was not imported due to errors in the Swagger file.
Unable to create resource at path '/subject/{subjectId}/profile': A sibling ({bizId}) of this resource already has a variable path part -- only one is allowed
Additionally, these warnings were found:
No responses specified for 'POST /subject/{bizId}/complaint'

这个只能改结构了。因为中间部分是相同但,但request和integation部分又是不同的,aws无法处理,只能改api了,不会让两个接口出现类似的结构

https://github.com/awslabs/aws-apigateway-importer/issues/202

(2)aws-api-import.sh整合到应用中。使用java -jar 的方法
整合过程的难点:
工具想做成独立程度比较高,因此AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY需要通过在代码中传入,而不是通过aws configure配置到The default credential profiles file – typically located at ~/.aws/credentials (this location may vary per platform)

http://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html

解决方案:

    public void importApi(String filePath, String region, String stage) throws FileNotFoundException {
ArrayList<String> commandList = newArrayList("java", "-jar");
String absolutePath = ResourceUtils.getFile(ResourceUtils.CLASSPATH_URL_PREFIX).getAbsolutePath();
LOGGER.info("absolutePath:{}",absolutePath);
File awsImporterFile = ResourceUtils.getFile("classpath:lib/aws-apigateway-importer-1.0.3-SNAPSHOT-jar-with-dependencies.jar");
commandList.add(awsImporterFile.getAbsolutePath());
commandList.add("--create");
commandList.add(filePath);
commandList.add("--region"); if (StringUtils.isBlank(region)) {//region 必须有
region = Regions.AP_SOUTHEAST_1.getName();
}
commandList.add(region); if (StringUtils.isNotBlank(stage)) {//deploy optional
commandList.add(" --deploy ");
commandList.add(stage);
} LOGGER.info(" {}", commandList);
execCmd(commandList);
LOGGER.info("success to do import ");
} public boolean execCmd(ArrayList<String> commandList) {//List中第个元素是按空格分隔的命令的各部分组成
try {
ProcessBuilder pb = new ProcessBuilder(commandList);
pb.redirectErrorStream(true);
Map<String, String> env = pb.environment();//设置环境变量,重要
env.put("AWS_ACCESS_KEY_ID", s3AccessProperty.getAccessKeyId());
env.put("AWS_SECRET_ACCESS_KEY", s3AccessProperty.getSecretAccessKey());
LOGGER.info("env:{}", env);
Process process = pb.start(); OutputProcessor error = new OutputProcessor(process.getErrorStream());
OutputProcessor input = new OutputProcessor(process.getInputStream());
error.start();
input.start();
int exitCode = process.waitFor();//阻塞,直到命令执行结束(成功 or 失败)
if (exitCode == 0) {
return true;
}
LOGGER.info("Failed to perform the command.{}", exitCode);
return false;
} catch (Exception e) {
LOGGER.info("{}", e.getMessage(), e);
return false;
}
}

上例中环境变量名:

使用Runtime.getRuntime.exec(String command, String[] envp),accessKeyId和secretAccessId 导入程序获取不到。这种方式就舍弃掉了

    /**
* Executes the specified string command in a separate process with the
* specified environment.
*
* <p>This is a convenience method. An invocation of the form
* <tt>exec(command, envp)</tt>
* behaves in exactly the same way as the invocation
* <tt>{@link #exec(String, String[], File) exec}(command, envp, null)</tt>.
*
* @param command a specified system command.
*
* @param envp array of strings, each element of which
* has environment variable settings in the format
* <i>name</i>=<i>value</i>, or
* <tt>null</tt> if the subprocess should inherit
* the environment of the current process.
*
* @return A new {@link Process} object for managing the subprocess
*
* @throws SecurityException
* If a security manager exists and its
* {@link SecurityManager#checkExec checkExec}
* method doesn't allow creation of the subprocess
*
* @throws IOException
* If an I/O error occurs
*
* @throws NullPointerException
* If <code>command</code> is <code>null</code>,
* or one of the elements of <code>envp</code> is <code>null</code>
*
* @throws IllegalArgumentException
* If <code>command</code> is empty
*
* @see #exec(String[], String[], File)
* @see ProcessBuilder
*/
public Process exec(String command, String[] envp) throws IOException {
return exec(command, envp, null);
}

相关示例代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; public class LinuxTimeSetter {
public void runLinuxScript() throws IOException {
//通过exec 来运行Linux shell脚本:在这个demo中 setDate.sh 是和 LinuxTimeSetter 在同一个文件夹中
String[] command = new String[]{"sudo","./setDate.sh","2010-10-10","12:12:12"};
Process proc = Runtime.getRuntime().exec(command);
BufferedReader br = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String text = null;
//输出操作结果
while ((text = br.readLine()) != null) {
System.out.println(text);
}
} public void runWindosScript() throws IOException {
// Process proc = Runtime.getRuntime().exec("cmd /c dir");
Process proc = Runtime.getRuntime().exec("cmd /c date /t");
BufferedReader br = new BufferedReader(new InputStreamReader(proc
.getInputStream()));
// BufferedInputStream bis = new
// BufferedInputStream(proc.getInputStream());
String text = null;
while ((text = br.readLine()) != null) {
System.out.println(text);
}
} public static void main(String[] args) {
String osName = System.getProperty("os.name").toLowerCase();
System.out.println(osName);
LinuxTimeSetter runner = new LinuxTimeSetter();
try {
if (osName.contains("linux")) {
runner.runLinuxScript();
} else if (osName.matches("^(?i)Windows.*$")) {
runner.runWindosScript();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

Runtime.getRuntime()返回当前应用程序的Runtime对象,单例的。
Process Runtime.getRuntime.exec(String command);
command:要运行的命令,如:windows:”cmd /c dir”;Linux:”ls -a”。
直接运行字符串命令

Process Runtime.getRuntime.exec(String [] cmdArray);
cmdarray是要执行的本地命令集合。
运行这个本地命令集合。应用场景:用来动态的向已经写好的shell脚本中传递参数。例如:
String[] command = new String[]{"sudo","./setDate.sh","2010-10-10","12:12:12"};
Process proc = Runtime.getRuntime().exec(command);
在Linux普通用户环境中,传入时间参数"2010-10-10","12:12:12"到setDate.sh中,通过setDate.sh将传入的时间设置为Linux系统时间。
当然,还可以用这种方法:将command构建为一个字符串:"sudo ./setDate.sh 2010-10-10 12:12:12",使用exec(String command);实现相同的效果。

Process Runtime.getRuntime.exec(String command, String [] envp);
Process Runtime.getRuntime.exec(String [] cmdArray, String [] envp);
envp:当前的环境变量。如:“-Djava.library.path=/home/file/” (jni编码,将dll/so文件注册当前的环境变量中。Java -Djava.library.path=/home/file/ TestJni)
例如:
Process test = rt.exec(new String[] { "cmd /c", "TestShell.bat", "1stArg=alpha", "2ndArg=beta ", "3rdArg=/"333 echo/"" });
envp会被识别为:
1stArg=alpha
2ndArg=beta
echo
因为Java标准库给“=“右边的参数的头尾加了引号。也就是说原本给进去的参数是:name="value"的话,被处理了之后就变成:"name=""value"",所以编码的时候不可以写成"3rdArg=/"333 echo/""样式,否则从echo前面被截断了,而且引号也不见了

Process Runtime.getRuntime.exec(String cmdArray, String [] envp, File dir);
Process Runtime.getRuntime.exec(String [] cmdArray, String [] envp, File dir);
Runtime类中有很多exec方法,参数不同,但是最后都会调用exec(String[] cmdarray, String[] envp, File dir) 这个方法.
cmdarray是要执行的本地命令集合,envp是环境变量,如果envp is null,那么它会集成它的父进程的环境变量,dir是exec返回的Process的工作目录

http://blog.csdn.net/liu251/article/details/4263266

文档中该有信息都有了。但是需要仔细看。多看几遍,多读几遍。需要的信息就找到了

Amazon API Gateway Importer整合过程小结的更多相关文章

  1. Using Amazon API Gateway with microservices deployed on Amazon ECS

    One convenient way to run microservices is to deploy them as Docker containers. Docker containers ar ...

  2. 【设计模式 7】从公司的目前框架和API Gateway,谈谈对外观模式的理解

    我,第一次用到外观模式,应该是3年多以前.那时候是做一个收费系统,在当时的U层和B层之间,加了一层Facade.当时,在一些复杂的业务逻辑处理时,感受到了加入外观层的好处,但对于一些简单的(我指的是, ...

  3. Qwiklab'实验-API Gateway, AWS Lambda'

    title: AWS之Qwiklab subtitle: 2. Qwiklab'实验-API Gateway, AWS Lambda' date: 2018-09-20 17:29:20 --- In ...

  4. 谈谈微服务中的 API 网关(API Gateway)

    前言 又是很久没写博客了,最近一段时间换了新工作,比较忙,所以没有抽出来太多的时间写给关注我的粉丝写一些干货了,就有人问我怎么最近没有更新博客了,在这里给大家抱歉. 那么,在本篇文章中,我们就一起来探 ...

  5. 微服务中的 API 网关(API Gateway)

    API 网关(API Gateway)提供高性能.高可用的 API 托管服务,帮助用户对外开放其部署在 ECS.容器服务等云产品上的应用,提供完整的 API 发布.管理.维护生命周期管理.用户只需进行 ...

  6. API Gateway微服务

    微服务中的 API 网关(API Gateway)   前言 又是很久没写博客了,最近一段时间换了新工作,比较忙,所以没有抽出来太多的时间写给关注我的粉丝写一些干货了,就有人问我怎么最近没有更新博客了 ...

  7. 服务中的 API 网关(API Gateway)

    我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api ...

  8. 如何更快理解和运用服务编排?(使用Goku API Gateway实现)

    上一篇博客 未来实现API管理系统的几个关键词 发布后,有不少读者私信我,让我写一篇实际运用的文章,我周末趁着有空写了这篇有关“服务编排”的文章.用的是Goku API Gateway进行演示, 希望 ...

  9. 【springcloud】API Gateway 的路由和过滤(Zuul--1)

    转自:https://blog.csdn.net/pengjunlee/article/details/87084646 Zuul是什么? API Gateway 是随着微服务(Microservic ...

随机推荐

  1. IOS UIColor 自定义颜色

    使用 UIColor定义颜色 和 同 CIColor 与  CGColor 之间的联系.转换 1. 利用UIColor展现 #F6F6F6 这个传统的颜色 #F6F6F6 为一个 16 进制表示的RP ...

  2. iOS支付 IPAPayment demo iTunes Conection里面添加测试帐号,添加商品,实现购买过程

    https://github.com/ccguo/IAPPaymentDemo 发一个demo

  3. IOI1994 北京2008的挂钟 迭代加深

    总的来讲,这是一道很⑨的题,因为: (1)题目中有⑨个挂钟 (2)有⑨种操作方案 (3)这题因为解空间太小所以可以直接⑨重循环!! 这题可以用迭代加深搜索高效求解,剪枝的策略也很显然: >所求的 ...

  4. Java学习----对象与对象之间的关系

    1.依赖 对象之间最弱的一种关联方式,是临时性的关联.代码中一般指由局部变量,函数参数,返回值建立的对于其他对象的调用关系. public class A { // 方法一 public void t ...

  5. C#DataTable操作

    ] 在DataSet中添加DataTable DataSet.Tables.Add(DataTable) 实例: DataSet ds=new DataSet(); DataTable table=n ...

  6. js时间戳与日期格式之间的互转

    1. 将时间戳转换成日期格式 // 简单的一句代码 var date = new Date(时间戳); //获取一个时间对象 注意:如果是uinx时间戳记得乘于1000.比如php函数time()获得 ...

  7. [原创]用python写了一个简单的markdown编辑器

    以前我常用openoffice记录东西,最喜欢它的当然是在linux上能用了,还有里面的公式输入,前几天才了解markdown这个东东,初步了解发现它正是我需要的东西,可以用它随心所欲地记录些东西,而 ...

  8. Webservices-1.web服务定义简介

    一.WEB服务定义(摘自维基百科)详情:http://zh.wikipedia.org/wiki/Web%E6%9C%8D%E5%8A%A1 Web服务是一种服务导向架构的技术,通过标准的Web协议提 ...

  9. 《学习OpenCV》 第四章 习题六

    实现的是一个图像标签编辑器,其间遇到了些问题还未解决或者可能解决方法上不是最优,若你有更好的思路可以提供给我,大恩不言谢啦!!☆⌒(*^-゜)v. #include "stdafx.h&qu ...

  10. 为什么要用专业的ETL

    这两天一直在思考一个问题,为什么要用专业的etl工具进行数据清洗,原因如下: ETL负责将分布的.异构数据源中的数据如关系数据.平面数据文件等抽取到临时中间层后进行清洗.转换.集成,最后加载到数据仓库 ...