快嘉sdkg使用手册(四) 接口定义指南 - fastjrun/sdkg GitHub Wiki

在快嘉sdkg使用手册(一)--小试牛刀中,我们下载了sdkg源码,本地仓库安装了快嘉sdkg-helper插件和快嘉single-sdk-archetype脚手架;接下来用single-sdk-archetype脚手架新建了一个test-sdk工程,并用sdkg-helper插件生成接口sdk代码和接口单元测试代码,然后用命令行直接执行了接口测试,输出测试报告。

在快嘉sdkg使用手册(二)--test-sdk实践指南中,我们演示了如何用eclipse调试test-sdk的testng测试用例,重点介绍了这些测试用例如何在eclipse执行,包括如何修改测试数据,如何在同一个单元测试用例执行多套测试数据;除此之外,我们也介绍了通过命令行复用test-sdk的测试用例对接口系统做轻量的性能测试和自动化测试。

在快嘉sdkg使用手册(三)--test-sdk实践指南中,我们以聚合数据网站的邮编查询的3个接口为例,介绍了如何结合sdkg-helper利用test-sdk对接聚合数据网站的邮编查询的3个接口,形成接口sdk代码,并如何进行调试;另外还给出一个重构优化的sdk版本。

本节我们主要介绍如何维护接口定义文件。

快嘉接口定义文件采用xml格式,其规范请参见:https://fastjrun.github.io/res/fastjrun-schema.xsd ,快嘉sdkg插件会根据接口定义文件生成请求和响应报文对应的JavaBean和接口访问类。

快嘉接口规范分为4部分,其中packets为定义的请求和响应报文对应的JavaBean,apiControllers、appControllers和genericControllers是用来定义接口的,接口规范内置了三种接口定义模板,正好对应以上的3类Controller,可以分别作为开放平台接口选型、移动端接口选型和一般接口选型的参考,其中genericControllers比较灵活,可以适应绝大部分接口场景。

Restful接口规范

对于一个正常的Restful接口风格的接口,一般会至少约定如下几个方面

  • URL命名

URL用于标识资源,因此URL应该以名词进行命名,例如/schools, /schools/teachers等。

一般URL会内嵌参数,例如要获取id为313的school的信息,那么URL应该为/schools/313,前面的school采用复数,如果要列出其所有老师,则URL应为/users/313/teacher,如果要获取其id为499的teacher,则URL应为/schools/313/teachers/499

  • 接口请求方法

如GET、POST、PUT、DELETE之类

  • 接口请求参数及方式

queryString方式,例如/schools?sid=313, /schools/teachers?sid=313&tid=499等或者form表单方式 headVaribale,通过Header传值,通过这种方式传值一般是用来做校验或验证的

  • 请求报文和响应报文

就是请求和响应消息中的entity-body(也称为body),一般采用JSON/XML字符串格式。 除以上内容外,有可能因为安全、流量和并发性质等考虑,还有一些对报文或者具体字段加密、压缩,接口调用限制等要求,这里就不再赘述了。

  • 接口协议默认为http,支持https。

接口定义指南

下面主要以genericController为例介绍如何用快嘉接口规范设计接口。

接口定义

首先看genericController的shema定义如下图 贴一个基于快嘉接口规范定义的Controller示例代码如下,该Controller的name为UserGenericController

public class UserGenericController
    extends BaseController
{
    @Autowired
    private UserServiceRestGeneric userService;
    @RequestMapping(value = "register", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public BaseResponse<BaseDefaultResponseBody> register(
        @RequestBody
        @Valid
        RegistserRestRequestBody request) {
        BaseResponse<BaseDefaultResponseBody> response = this.userService.register(request);
        log.debug(response);
        return response;
    }
    @RequestMapping(value = "login", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public com.apiworld.packet.generic.LoginRestResponseBody login(
        @RequestBody
        @Valid
        com.apiworld.packet.generic.LoginRestRequestBody request) {
        com.apiworld.packet.generic.LoginRestResponseBody response = this.userService.login(request);
        log.debug(response);
        return response;
    }
    @RequestMapping(value = "login/v1_1", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public com.apiworld.packet.generic.LoginRestResponseBody loginv1_1(
        @RequestBody
        @Valid
        com.apiworld.packet.generic.LoginRestRequestBody request) {
        com.apiworld.packet.generic.LoginRestResponseBody response = this.userService.loginv1_1(request);
        log.debug(response);
        return response;
    }
    @RequestMapping(value = "autoLogin", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
    public com.apiworld.packet.generic.LoginRestResponseBody autoLogin(
        @RequestBody
        @Valid
        AutoLoginRestRequestBody request) {
        com.apiworld.packet.generic.LoginRestResponseBody response = this.userService.autoLogin(request);
        log.debug(response);
        return response;
    }
}

对应的接口访问类示例代码如下,该Controller的name为UserGenericClient

public class UserGenericClient extends BaseGenericClient {
	public void register(RegistserRestRequestBody request) {
		StringBuilder sbUrlReq = new StringBuilder(this.genericUrlPre);
		sbUrlReq.append("/generic/user/");
		sbUrlReq.append("register");
		Map<java.lang.String, java.lang.String> requestProperties = new HashMap<java.lang.String, java.lang.String>();
		requestProperties.put("Content-Type", "application/json");
		requestProperties.put("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
		requestProperties.put("Accept", "*/*");
		String requestStr = JSONObject.fromObject(request).toString();
		log.info(requestStr);
		this.process(requestStr, sbUrlReq.toString(), "POST", requestProperties);
	}
	public com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody login(
			com.fastjrun.share.sdk.packet.generic.LoginRestRequestBody request) {
		StringBuilder sbUrlReq = new StringBuilder(this.genericUrlPre);
		sbUrlReq.append("/generic/user/");
		sbUrlReq.append("login");
		Map<java.lang.String, java.lang.String> requestProperties = new HashMap<java.lang.String, java.lang.String>();
		requestProperties.put("Content-Type", "application/json");
		requestProperties.put("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
		requestProperties.put("Accept", "*/*");
		String requestStr = JSONObject.fromObject(request).toString();
		log.info(requestStr);
		JSONObject response = this.process(requestStr, sbUrlReq.toString(), "POST", requestProperties);
		com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody loginRestResponseBody = new com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody();
		String loginRestResponseBodynickName = response.getString("nickName");
		if ((!(loginRestResponseBodynickName == null)) && (!loginRestResponseBodynickName.equals(""))) {
			loginRestResponseBody.setNickName(loginRestResponseBodynickName);
		}
		String loginRestResponseBodysex = response.getString("sex");
		if ((!(loginRestResponseBodysex == null)) && (!loginRestResponseBodysex.equals(""))) {
			loginRestResponseBody.setSex(loginRestResponseBodysex);
		}
		String loginRestResponseBodymobileNo = response.getString("mobileNo");
		if ((!(loginRestResponseBodymobileNo == null)) && (!loginRestResponseBodymobileNo.equals(""))) {
			loginRestResponseBody.setMobileNo(loginRestResponseBodymobileNo);
		}
		String loginRestResponseBodyuuid = response.getString("uuid");
		if ((!(loginRestResponseBodyuuid == null)) && (!loginRestResponseBodyuuid.equals(""))) {
			loginRestResponseBody.setUuid(loginRestResponseBodyuuid);
		}
		String loginRestResponseBodyemail = response.getString("email");
		if ((!(loginRestResponseBodyemail == null)) && (!loginRestResponseBodyemail.equals(""))) {
			loginRestResponseBody.setEmail(loginRestResponseBodyemail);
		}
		return loginRestResponseBody;
	}
	public com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody loginv1_1(
			com.fastjrun.share.sdk.packet.generic.LoginRestRequestBody request) {
		StringBuilder sbUrlReq = new StringBuilder(this.genericUrlPre);
		sbUrlReq.append("/generic/user/");
		sbUrlReq.append("login/v1_1");
		Map<java.lang.String, java.lang.String> requestProperties = new HashMap<java.lang.String, java.lang.String>();
		requestProperties.put("Content-Type", "application/json");
		requestProperties.put("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
		requestProperties.put("Accept", "*/*");
		String requestStr = JSONObject.fromObject(request).toString();
		log.info(requestStr);
		JSONObject response = this.process(requestStr, sbUrlReq.toString(), "POST", requestProperties);
		com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody loginRestResponseBody = new com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody();
		String loginRestResponseBodynickName = response.getString("nickName");
		if ((!(loginRestResponseBodynickName == null)) && (!loginRestResponseBodynickName.equals(""))) {
			loginRestResponseBody.setNickName(loginRestResponseBodynickName);
		}
		String loginRestResponseBodysex = response.getString("sex");
		if ((!(loginRestResponseBodysex == null)) && (!loginRestResponseBodysex.equals(""))) {
			loginRestResponseBody.setSex(loginRestResponseBodysex);
		}
		String loginRestResponseBodymobileNo = response.getString("mobileNo");
		if ((!(loginRestResponseBodymobileNo == null)) && (!loginRestResponseBodymobileNo.equals(""))) {
			loginRestResponseBody.setMobileNo(loginRestResponseBodymobileNo);
		}
		String loginRestResponseBodyuuid = response.getString("uuid");
		if ((!(loginRestResponseBodyuuid == null)) && (!loginRestResponseBodyuuid.equals(""))) {
			loginRestResponseBody.setUuid(loginRestResponseBodyuuid);
		}
		String loginRestResponseBodyemail = response.getString("email");
		if ((!(loginRestResponseBodyemail == null)) && (!loginRestResponseBodyemail.equals(""))) {
			loginRestResponseBody.setEmail(loginRestResponseBodyemail);
		}
		return loginRestResponseBody;
	}
	public com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody autoLogin(AutoLoginRestRequestBody request) {
		StringBuilder sbUrlReq = new StringBuilder(this.genericUrlPre);
		sbUrlReq.append("/generic/user/");
		sbUrlReq.append("autoLogin");
		Map<java.lang.String, java.lang.String> requestProperties = new HashMap<java.lang.String, java.lang.String>();
		requestProperties.put("Content-Type", "application/json");
		requestProperties.put("User-Agent",
				"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36");
		requestProperties.put("Accept", "*/*");
		String requestStr = JSONObject.fromObject(request).toString();
		log.info(requestStr);
		JSONObject response = this.process(requestStr, sbUrlReq.toString(), "POST", requestProperties);
		com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody loginRestResponseBody = new com.fastjrun.share.sdk.packet.generic.LoginRestResponseBody();
		String loginRestResponseBodynickName = response.getString("nickName");
		if ((!(loginRestResponseBodynickName == null)) && (!loginRestResponseBodynickName.equals(""))) {
			loginRestResponseBody.setNickName(loginRestResponseBodynickName);
		}
		String loginRestResponseBodysex = response.getString("sex");
		if ((!(loginRestResponseBodysex == null)) && (!loginRestResponseBodysex.equals(""))) {
			loginRestResponseBody.setSex(loginRestResponseBodysex);
		}
		String loginRestResponseBodymobileNo = response.getString("mobileNo");
		if ((!(loginRestResponseBodymobileNo == null)) && (!loginRestResponseBodymobileNo.equals(""))) {
			loginRestResponseBody.setMobileNo(loginRestResponseBodymobileNo);
		}
		String loginRestResponseBodyuuid = response.getString("uuid");
		if ((!(loginRestResponseBodyuuid == null)) && (!loginRestResponseBodyuuid.equals(""))) {
			loginRestResponseBody.setUuid(loginRestResponseBodyuuid);
		}
		String loginRestResponseBodyemail = response.getString("email");
		if ((!(loginRestResponseBodyemail == null)) && (!loginRestResponseBodyemail.equals(""))) {
			loginRestResponseBody.setEmail(loginRestResponseBodyemail);
		}
		return loginRestResponseBody;
	}
}

以上代码中出现的BaseGenericClient代码可以在sdkg-common模板查阅

接口报文定义

快嘉接口中出现的请求报文JavaBean和响应报文JavaBean定义可以用快嘉接口规范的packet实现。

packet的shema定义如下图

对应的接口访问类示例代码可结合示例接口定义文件generic-client.xml查看sdkg-sdk/src/main/com/fastjrun/share/sdk/packet/下文件。

待改进

  • 默认通过快嘉接口规范实现的接口接入类代码只支持http/https协议,后期会通过扩展接口规范的方式支持tcp、coap、mqtt等协议
  • 默认通过快嘉接口规范实现的接口接入类代码只支持请求和响应报文为json格式,后期会通过扩展接口规范的方式支持请求请求和响应报文既可支持json也可以支持xml
  • 优化接口测试用例代码模板,使它更符合QA的使用规范
  • 扩展接口测试用例代码模板,使它可以不经修改直接支持jmeter
  • 当前通过快嘉接口规范实现的接口接入类代码只支持使用maven插件生成java代码,后期会考虑使用合适的方式生成php、python、nodejs等代码