apitest 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b0633ebdeafbf793f850ec77c572c6e10687c1aa
4
- data.tar.gz: c8a24eb02574bf285718e4b2a1ea651168e11193
3
+ metadata.gz: 573eef6c4af633b41ade5cf70edc2abb18676367
4
+ data.tar.gz: d128c020fe260b55e550d90b2e4c59089db4e63d
5
5
  SHA512:
6
- metadata.gz: 4f9234362ef3cb83cc44be3368aee0a21c8d6c82bbf1d1d2d5a67b28ffb010090372e4858aab9749071d7b719de690bfab6a3c36e7d60279200d386fc0a2f994
7
- data.tar.gz: b96dc2f3036ffd72dec49ab2744cd491ffab60b8f92e059b361e268801c35e78588ba419248d1b71a197029fc75ba7d8b0f9235ecff95239070255642414ba5f
6
+ metadata.gz: d1b50589b5877b6f1c96d8bfc00d86962a96e3954d7da75e5667a34eb514d7e872a49372f25607b146a5d2cf430837575148f02585fd0e0c1bd7efbc8a0dc265
7
+ data.tar.gz: fcb4faabaad7d12e54d5ffb56320f721b3214a5b92ae35da169b25dbb6a9ad35f986dca6bfb6ab171460ee130cbd77b4790174e9f4e04b65dc12d89602b0053a
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # Apitest
2
- - 通过在API controller里的常量,配置API文档
2
+ - 通过在API controller里配置常量,生成API文档
3
3
  - 并附带一个测试界面,辅助API开发。
4
4
  - 适用与API开发人员,客户端/前端开发人员交流验证文档。
5
- - 目前无出参,需要提交后,得到无法完全替代API文档
5
+ - 目前无出参,需要提交后,得到。无法完全替代API文档
6
6
 
7
7
  ## Version
8
- 0.1.9
8
+ 0.2.0
9
9
 
10
10
  ## Installation
11
11
  添加如下代码到 Gemfile:
@@ -137,14 +137,71 @@ Rails.application.routes.draw do
137
137
  end
138
138
  ```
139
139
 
140
+ 如果所有API有公共必填项,例如token,version,可如下配置
141
+
142
+ ```ruby
143
+ Rails.application.routes.draw do
144
+
145
+ apitest_for '/apitest' do
146
+ Apitest::public_required [ 'token' , 'version' ]
147
+ end
148
+
149
+ end
150
+ ```
151
+
152
+ 可以在指定APITEST中关闭公共必填项,比如登录API,可在具体方法的APIDOC中使用false设定
153
+
154
+ ```ruby
155
+ token:false
156
+ ```
157
+
158
+ 完整配置方法如下
159
+ ```ruby
160
+ class Api::V1::LoginController < ApplicationController
161
+
162
+ APIDOC = {
163
+ type: '业务API' ,
164
+ group_name: '用户登录' ,
165
+ sort: 1 ,
166
+ apis: {
167
+ create: {
168
+ api_name: '登录' ,
169
+ path: '/api/v1/login' ,
170
+ method: 'post' ,
171
+ token: false , # 这里可关闭该API的token选项
172
+ params: {
173
+ mobile: {
174
+ required: true ,
175
+ } ,
176
+ password: {
177
+ required: true
178
+ }
179
+ }
180
+ }
181
+ }
182
+ }
183
+ def create
184
+ ...
185
+ end
186
+
187
+ ```
188
+
189
+
190
+
191
+
192
+
193
+
140
194
 
141
195
 
142
196
  ## TODO
143
197
  - [x] 可自定义api目录
144
198
  - [x] 可自定义theme
145
199
  - [x] 可配置分类
146
- - [ ] 可设定所有API都有的必填项,比如token、客户端类型、客户端版本号
200
+ - [x] 可设定公共必填项,比如token、客户端类型、客户端版本号
201
+ - [x] 公共必填项可在指定API中关闭
202
+ - [x] 支持header token和params token
147
203
  - [ ] ERROR类工具
204
+ - [ ] 出参example
148
205
  - [ ] Apitest Example 网站
149
206
  - [ ] 使用前端route
150
207
  - [ ] 生成前端mock数据
@@ -5,6 +5,7 @@
5
5
  #= require jquery3
6
6
  #= require jquery_ujs
7
7
  #= require turbolinks
8
+ #= require lodash
8
9
  #= require bootstrap
9
10
  #= require adminlte/adminlte
10
11
  #= require vue
@@ -17,6 +18,7 @@ $(document).on "turbolinks:load" , ->
17
18
  vm = new Vue
18
19
  el : '#apitest_show'
19
20
  data :
21
+ apitest_tab_show : 'api_test'
20
22
  root_url : null
21
23
  apis : null
22
24
  ws : null
@@ -24,21 +26,39 @@ $(document).on "turbolinks:load" , ->
24
26
  current_group : ''
25
27
  current_api : ''
26
28
  token : ''
27
- apitest_tab_show : 'api_test'
29
+ token_type : ''
30
+ token_set : {}
31
+ token_get : []
32
+ headers : {}
28
33
  mounted : ->
29
34
  @apis = $('#data').data('apis')
30
- @token = $('#data').data('token')
35
+ @token_set = $('#data').data('token-set')
36
+ @token_get = $('#data').data('token-get')
37
+ @token_type = @token_set[0]
31
38
  @output_area = $('#server-logs-output')
32
39
  @root_url = $('#data').data('root-url')
33
40
  @get_log()
41
+ @set_token(localStorage.apitest_token)
42
+ # @token_set()
34
43
 
35
44
  methods :
36
-
45
+ set_token : (token) ->
46
+ @token = token
47
+ localStorage.apitest_token = token
48
+ @set_header_token() if @token_set[0] == 'header'
49
+
50
+ set_header_token : ->
51
+ @headers[@token_set[1]] = @token
52
+
53
+ fetch_token : (params) ->
54
+ token = eval 'params["' + @token_get.join('"]["') + '"]'
55
+ @set_token(token) if token
56
+
37
57
  group_select : (name) ->
38
58
  @current_group = name
39
59
  @current_api = ''
40
60
 
41
- api_select : (name ) ->
61
+ api_select : (name) ->
42
62
  @current_api = name
43
63
 
44
64
  api_submit : (e) ->
@@ -50,17 +70,23 @@ $(document).on "turbolinks:load" , ->
50
70
  postData = {}
51
71
 
52
72
  elm.find('.params').each ->
53
-
54
73
  postData[$(this).attr('name')] = $(this).val() unless $(this).attr('name').indexOf(':id') >= 0
55
-
74
+
56
75
  $.ajax
57
76
  url : path
58
77
  type : method
59
78
  data : postData
79
+ headers : @headers
60
80
  success : (data) =>
61
81
  result_pre.jsonViewer(data)
82
+ @fetch_token(data)
62
83
  error : (data) =>
63
- result.val data.responseText
84
+ try
85
+ result_pre.jsonViewer(JSON.parse(data.responseText))
86
+ catch e
87
+ result_pre.text(data.responseText)
88
+
89
+
64
90
 
65
91
  clear_result : (e) ->
66
92
  $(e.target).parents('.api').find('.result_pre').html('')
@@ -24,6 +24,8 @@
24
24
  background-color: #fff;
25
25
  height: 514px;
26
26
  border-radius: 0px;
27
+ white-space: pre-wrap;
28
+ word-wrap: break-word;
27
29
  padding: 15px 30px 15px 30px;
28
30
  }
29
31
  .nav-pills.nav-stacked{
@@ -5,7 +5,10 @@ module Apitest
5
5
  before_action :get_doc ,:root_url
6
6
  def initialize
7
7
  super
8
- @apidocs = {}
8
+ @apidocs = {}
9
+ @headers = Apitest::set_headers
10
+ @token_set = Apitest::token_setting[:set]
11
+ @token_get = Apitest::token_setting[:get]
9
12
  end
10
13
  def index
11
14
  respond_to do |format|
@@ -29,24 +32,24 @@ module Apitest
29
32
  def get_doc(path_root = nil)
30
33
  path_root ||= "app/controllers/#{Apitest.api_dir}/"
31
34
  Dir.glob("#{path_root}*").each do |path|
32
- @apidocs[path.gsub("#{path_root}" , '')] = get_version_doc "#{path}/" if File.directory?(path) && !path.gsub("#{path_root}" , '').blank?
35
+ @apidocs[path.gsub("#{path_root}" , '')] = get_version_doc "#{path}" if File.directory?(path) && !path.gsub("#{path_root}" , '').blank?
33
36
  end
34
37
  end
35
38
 
36
- def get_version_doc(path_root)
37
- docs = Apitest::default_types.clone
39
+ def get_version_doc(path_root , docs = {})
40
+ docs = Apitest::default_types.clone if docs.blank?
38
41
  Dir.glob("#{path_root}/*").each do |path|
39
42
  if File.directory?(path)
40
- docs = docs.merge get_version_doc(path)
43
+ docs = docs.merge get_version_doc(path , docs)
41
44
  else
42
45
  class_match = File.open(path).read.match(/class (.*) </)
43
46
  controller_class = class_match[1].constantize if class_match && class_match[1]
44
47
  if defined? controller_class::APIDOC
45
- doc = controller_class::APIDOC
46
- doc[:sort] = 99 if doc[:sort].blank?
48
+ doc = controller_class::APIDOC
49
+ doc[:sort] = 99 if doc[:sort].blank?
47
50
  doc[:apis].each do |k,v|
48
51
  d = doc[:apis][k]
49
- d = public_required d unless Apitest::public_required.blank?
52
+ d = public_required d unless Apitest::public_required.blank?
50
53
  d[:params] = {':id' => { required: true }}.merge d[:params] if d[:path].include? ':id'
51
54
  end
52
55
 
@@ -55,13 +58,13 @@ module Apitest
55
58
  end
56
59
  end
57
60
  end
58
- docs
61
+ return docs
59
62
  end
60
63
  def public_required(api)
61
64
  Apitest::public_required.reverse.each do |need|
62
65
  api[:params] = need.merge api[:params] if api[need.keys.first.to_sym] != false
63
66
  end
64
- api
67
+ return api
65
68
  end
66
69
  end
67
70
  end
@@ -66,24 +66,44 @@ section.content
66
66
  td 参数
67
67
  td
68
68
  table.table.table-hover.table-bordered
69
+ tr v-if="token_type == 'params'"
70
+ td
71
+ span style="color:red;width:10px;display:inline-block"
72
+ span *
73
+ span token
74
+ td
75
+ input.form-control.params name="token" :value="token"
69
76
  tr v-for="(value , name , index) in api.params"
70
- td.col-md-2 v-bind:class="{'border-top-none': (index == 0)}"
77
+ td.col-md-2
71
78
  span style="color:red;width:10px;display:inline-block"
72
79
  span v-if="value.required" *
73
80
  span ="{{name}}"
74
- td v-if="name == 'token'" v-bind:class="{'border-top-none': index == 0}"
75
- input.form-control.params :name="name" :value="token"
76
- span style="line-height:25px" = "{{value.text}}"
77
- td v-if="name != 'token'" v-bind:class="{'border-top-none': index == 0}"
81
+ td v-if="value.nested == true"
82
+ table.table.table-hover
83
+ tr v-for="(v , n , i) in value" v-if="n != 'nested'"
84
+ td.col-md-3
85
+ span style="color:red;width:10px;display:inline-block"
86
+ span v-if="v.required" *
87
+ span ="{{name}}[{{n}}]"
88
+ td
89
+ input.form-control.params :name="name + '[' + n + ']'"
90
+ span style="line-height:25px" = "{{v.text}}"
91
+ td v-else=""
78
92
  input.form-control.params :name="name"
79
93
  span style="line-height:25px" = "{{value.text}}"
94
+ / td v-if="name == 'token'" v-bind:class="{'border-top-none': index == 0}"
95
+ / input.form-control.params :name="name" :value="token"
96
+ / span style="line-height:25px" = "{{value.text}}"
97
+ / td v-if="name != 'token'" v-bind:class="{'border-top-none': index == 0}"
98
+ / input.form-control.params :name="name"
99
+ / span style="line-height:25px" = "{{value.text}}"
80
100
  tr
81
101
  td
82
102
  td
83
103
  button.btn.bg-olive.btn-flat @click="api_submit" 提交
84
- button.btn.bg-orange.btn-flat style="margin-left:10px;margin-right:10px" @click="clear_result" 清空结果
85
- button.btn.bg-purple.btn-flat style="margin-left:10px;margin-right:10px" @click="show_server_log" 查看server log
86
- button.btn.btn-warning.btn-flat style="margin-right:10px" @click="clear_log" 清空log
104
+ button.btn.bg-orange.btn-flat style="margin-left:10px;margin-right:10px" @click="clear_result" 清空结果
105
+ button.btn.bg-purple.btn-flat style="margin-left:10px;margin-right:10px" @click="show_server_log" 查看server log
106
+ button.btn.btn-warning.btn-flat style="margin-right:10px" @click="clear_log" 清空log
87
107
  tr
88
108
  td
89
109
  td
@@ -31,6 +31,6 @@ html
31
31
  =yield
32
32
  footer.main-footer
33
33
  -if params[:action] == 'show'
34
- #data data-root-url="#{@root_url}" data-ws-url="ws://#{request.host}:9527" data-apis="#{@apidocs[params[:id]].to_json}" data-token="#{session[:token]}"
34
+ #data data-root-url="#{@root_url}" data-ws-url="ws://#{request.host}:9527" data-apis="#{@apidocs[params[:id]].to_json}" data-headers="#{@headers.to_json}" data-token-set="#{@token_set.to_json}" data-token-get="#{@token_get.to_json}"
35
35
 
36
36
 
@@ -7,6 +7,7 @@ require "font-awesome-rails"
7
7
  require "ionicons-rails"
8
8
  require 'eventmachine'
9
9
  require 'eventmachine-tail'
10
+ require 'lodash-rails'
10
11
  require 'websocket-eventmachine-server'
11
12
 
12
13
  module Apitest
@@ -14,6 +15,8 @@ module Apitest
14
15
  @theme
15
16
  @default_types
16
17
  @public_required
18
+ @token_setting
19
+
17
20
  class << self
18
21
  def api_dir(dir = nil)
19
22
  @api_dir = dir if dir
@@ -44,6 +47,15 @@ module Apitest
44
47
  @public_required
45
48
  end
46
49
 
50
+ def token_setting(setting = nil)
51
+ @token_setting = setting if setting
52
+ @token_setting
53
+ end
54
+
55
+ def set_headers
56
+ @token_setting[:set] && @token_setting[:set][1] ? {@token_setting[:set][1] => ''} : {}
57
+ end
58
+
47
59
  def start_server_log_listen
48
60
  Process.detach(
49
61
  fork do
@@ -68,18 +80,6 @@ module Apitest
68
80
  )
69
81
  end
70
82
  end
71
-
72
- class Reader < EventMachine::FileTail
73
- def initialize(path, startpos=-1, &block)
74
- super(path, startpos)
75
- @buffer = BufferedTokenizer.new
76
- @block = block
77
- end
78
-
79
- def receive_data(data)
80
- @buffer.extract(data).each { |line| @block.call(line) }
81
- end
82
- end
83
83
  end
84
84
 
85
85
  module ActionDispatch::Routing
@@ -0,0 +1,35 @@
1
+ module Apitest
2
+ module Error
3
+ def error(error_code = nil , data = nil,message = nil)
4
+ hash = {
5
+ status: 'error' ,
6
+ error_code: error_code ,
7
+ message: message.nil? ? self::ERROR[error_code] : message ,
8
+ data: data ,
9
+ }
10
+ raise "#{self.to_s}::Error".constantize.new hash
11
+ end
12
+
13
+ def success(message = nil , data = nil)
14
+ hash = {}
15
+ hash[:status] = 'ok'
16
+ if message.is_a? Hash
17
+ hash[:message] = message[:message] ? message[:message] : ''
18
+ hash[:data] = message[:data] ? message[:data] : message
19
+ else
20
+ hash[:message] = message ? message : ''
21
+ hash[:data] = data ? data : {}
22
+ end
23
+ return hash
24
+ end
25
+
26
+ class Error < StandardError
27
+ def error
28
+ eval(message)
29
+ end
30
+ def error_code
31
+ error[:error_code]
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module Apitest
2
+ module ModelError
3
+ include Apitest::Error
4
+ def self.include(klass)
5
+ klass.class_eval do
6
+ include ServiceError
7
+ extend ServiceError
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module Apitest
2
+ class Reader < EventMachine::FileTail
3
+ def initialize(path, startpos=-1, &block)
4
+ super(path, startpos)
5
+ @buffer = BufferedTokenizer.new
6
+ @block = block
7
+ end
8
+
9
+ def receive_data(data)
10
+ @buffer.extract(data).each { |line| @block.call(line) }
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,41 @@
1
+ module Apitest
2
+ module ServiceError
3
+ # include Apitest::Error
4
+ def self.include(klass)
5
+ klass.class_eval do
6
+ include ServiceError
7
+ extend ServiceError
8
+ end
9
+ end
10
+ def self.error(error_code = nil , data = nil,message = nil)
11
+ hash = {
12
+ status: 'error' ,
13
+ error_code: error_code ,
14
+ message: message.nil? ? self::ERROR[error_code] : message ,
15
+ data: data ,
16
+ }
17
+ raise "#{self.to_s}::Error".constantize.new hash
18
+ end
19
+
20
+ def success(message = nil , data = nil)
21
+ hash = {}
22
+ hash[:status] = 'ok'
23
+ if message.is_a? Hash
24
+ hash[:message] = message[:message] ? message[:message] : ''
25
+ hash[:data] = message[:data] ? message[:data] : message
26
+ else
27
+ hash[:message] = message ? message : ''
28
+ hash[:data] = data ? data : {}
29
+ end
30
+ return hash
31
+ end
32
+ class Error < StandardError
33
+ def error
34
+ eval(message)
35
+ end
36
+ def error_code
37
+ error[:error_code]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,3 +1,3 @@
1
1
  module Apitest
2
- VERSION = '0.1.9'
2
+ VERSION = '0.2.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apitest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kyuubi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-30 00:00:00.000000000 Z
11
+ date: 2017-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: lodash-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: eventmachine-tail
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -179,6 +193,10 @@ files:
179
193
  - config/routes.rb
180
194
  - lib/apitest.rb
181
195
  - lib/apitest/engine.rb
196
+ - lib/apitest/error.rb
197
+ - lib/apitest/module_error.rb
198
+ - lib/apitest/reader.rb
199
+ - lib/apitest/service_error.rb
182
200
  - lib/apitest/version.rb
183
201
  - lib/tasks/apitest_tasks.rake
184
202
  homepage: https://github.com/kyuubi9/apitest