近年微服務盛行,若是沒有進行理性合理的切分服務之間的邊界,很容易致使接口膨脹,這是通病!
基於spring-cloud微服務體系openFeign組件來暴露接口(Restful),說白了就是暴露了一堆又一堆的Http接口(跨語言嘛)前端
Api接口的維護歷程
本人經歷過以下幾個api接口維護的工具vue
說說這幾個的優缺點吧java
Rap | 這特麼就是阿里一個KPI項目 | 手動維護接口,開發完代碼還得本身編寫接口 |
Postman | 強大,很強大 | 測試很強大,但仍是得手動維護接口 |
Swagger | 2.x比1.x改進很多 | 自動生成接口頁面,但不能歸檔和前置腳本,全部參數必須人工錄入,不能複用 |
問題來了
1,前置數據處理怎麼辦?後置數據驗證怎麼辦?
postman能夠作前置參數處理,不能作後置驗證
2,測試結果怎麼歸檔?
swagger自己就是一個網頁版的快捷測試頁面,瀏覽器關掉就沒了
3,每次精心準備了數據只能測試一次?
玩呢?mysql
開發了一個基於golang+vue版原本整合swagger+postman基本功能來解決問題
中國有句古話:是騾子是馬拉出來溜溜,hinny 翻譯:驢騾;公馬和母驢所生的騾子
即接口是好是仍是壞拿出來測測linux
項目地址:
項目:https://github.com/otk-final/hinny(後端)
項目:https://github.com/otk-final/hinny-ui(頁面)webpack
準備環境
數據庫:mysqlgit
建立數據表
執行db.sql文件,三張表(空間,模板,日誌)配置文件見工程config/conf.toml文件es6
運行
由於go能夠直接將應用程序打包成可執行文件,前端頁面沒有采用分離部署,已將前端所需頁面webpack打包至hinny-ops\static目錄下方便統一部署
將hinny-ops目錄下文件拷貝至運行機器,執行便可window下執行hinny.exe便可,linux執行hinny_linux便可(目前只打包了64位系統運行文件)github
相關頁面golang
1工做空間
微服務開發中,不一樣開發人員可能同時並行開發,進行本地測試,在開發人員未提交正式測試環境前,可切換至對方空間進行接口測試,即遠程調用開發者本地機器,接口有變更在平臺上進行接口同步便可(保證目標服務正常運行,即能正常提供接口)
建議:同一項目,項目名稱保持一致,不一樣運行環境保持命名空間不一致
例:請求地址:http://192.168.30.1:8080 是接口調用地址
例:接口地址:http://192.168.30.1:8080/v2/api-docs 是swagger暴露出的接口地址以下圖
每一個空間支持配置默認腳本,在接口調用時會將當前空間默認腳本回填到驗證腳本中
2服務列表
3接口列表
請求參數分爲4個部分
請求頭 | http-header | 自定義報文頭(能夠經過腳本添加自定義頭) |
URI參數 | url路徑上的變量 | http://localhost:8080/{version}/user/{id} http://localhost:8080/v1/user/12345 |
請求參數 | ?para1=¶2= url後續拼接的參數 | http://localhost:8080/v1/user?keyword={keyword} http://localhost:8080/v1/user?keyword=關鍵字 |
報文體 | body中的參數 | json(目前只支持json) |
驗證腳本 | 以js腳本爲準 | init:作前置初始化函數 testing:後置驗證函數 $appendResult 驗證結果工具方法 詳情見示例截圖 |
4接口詳情
腳本編輯
接口測試完成後,能夠對當前記錄進行歸檔操做,下次在執行記錄中進行復用
5執行記錄
spring-boot項目搭建 項目搭建
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>example</groupId> <artifactId>example-parent</artifactId> <version>1.0-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> </parent> <properties> <swagger.version>2.9.2</swagger.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> </dependencies> </project>
啓動類
@SpringBootApplication @EnableSwagger2 public class ExampleApplication { public static void main(String[] args) { SpringApplication.run(ExampleApplication.class, args); } /** * 開啓swagger便於生成文檔 * * @return */ @Bean public Docket docket() { Docket docket = new Docket(DocumentationType.SWAGGER_2) .apiInfo( new ApiInfoBuilder() .title("接口文檔") .description("當前API版本" + "v1") .version("v1") .build()) .select().apis(RequestHandlerSelectors.basePackage("com.example")) .build() .globalOperationParameters(Arrays.asList( new ParameterBuilder().name("tenantId").parameterType("header") .modelRef(new ModelRef("string")).description("租戶ID(全局請求頭)").build(), new ParameterBuilder().name("userId").parameterType("header") .modelRef(new ModelRef("long")).description("用戶ID(全局請求頭)").build(), new ParameterBuilder().name("token").parameterType("header") .modelRef(new ModelRef("string")).description("用戶登陸TOKEN(全局請求頭)").build() )) .enable(true); return docket; } }
RestController暴露接口
@Api(description = "示例接口") @RestController public class ExampleController { @ApiOperation("添加數據") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1,v2", required = true) @PostMapping("{version}/pv/example/post") public Boolean post(@RequestHeader("userId") Long userId, @RequestBody SimpleDto body) { return true; } @ApiOperation("查詢數據") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1,v2", required = true) @GetMapping("{version}/pv/example/{id}") public SimpleDto get(@RequestHeader("userId") Long userId, @PathVariable("id") int id) { SimpleDto out = new SimpleDto(); out.setName("名稱"); out.setTags(Lists.newArrayList("標籤1", "標籤2", "標籤3")); return out; } @ApiOperation("更新數據") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1,v2", required = true) @PutMapping("{version}/pv/example/post") public Boolean put(@RequestHeader("userId") Long userId, @RequestBody SimpleDto body) { return true; } @ApiOperation("刪除數據") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1,v2", required = true) @DeleteMapping("{version}/pv/example/{id}") public Boolean delete(@RequestHeader("userId") Long userId, @PathVariable("id") int id) { return true; } }
@Api(description = "用戶接口") @RestController public class UserController { @ApiOperation("用戶登陸") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1", required = true) @PostMapping("{version}/pv/user/login") public Map<String, String> login(@RequestParam("loginName") String loginName, @RequestParam("passWord") String password) { Map<String, String> out = new HashMap<>(); out.put("loginName", loginName); out.put("passWord", password); return out; } @ApiOperation("查詢-(實體)") @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1", required = true) @GetMapping("{version}/pv/user/get-by-obj") public List<SimpleDto> query(QueryDto query) { return null; } @ApiOperation("查詢-(參數)") @ApiImplicitParams({ @ApiImplicitParam(name = "version", paramType = "path", allowableValues = "v1", required = true), @ApiImplicitParam(name = "keyword", paramType = "query", allowableValues = "*", required = true), @ApiImplicitParam(name = "phone", paramType = "query", allowableValues = "13100000001", required = true) }) @GetMapping("{version}/pv/user/get-by-param") public List<SimpleDto> query(@RequestParam("keyword") String keyword, @RequestParam("phone") String phone) { return null; } }
Feature
本項目不屬於生產項目,只是基於本地開發測試,純屬當作工具使用,望指點~~~