webservice 0.4.0 → 0.5.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: b43248423b9aeba87a88f63b6a708167bbf7d723
4
- data.tar.gz: 35b9cd86f34c708a4d55f7f61a08a878f4e19d12
3
+ metadata.gz: fca9552fa4818068271c81022e7ab9a4ec277d30
4
+ data.tar.gz: 23e2d0051213a5834cafff2762df4324c6907935
5
5
  SHA512:
6
- metadata.gz: def6d86899d29ca10acb0c70af15de8887005fc47dc9f1d5586103eb98033d7e68d5c44744c51b30493cbcef344a565f9dbcc21c6681aa55257e42c772c0f307
7
- data.tar.gz: 2417ece5303df96025515574a343e2b21eaa1e08015ff7cfe11822a9d9d757c918a798e149d1d03f24b74a7574e0ef6e4625778b6b63b6b42fa0f403c31adb19
6
+ metadata.gz: 6b53f3b4ea61aed918b16b5b73ad3be4e162131599d6cb1222607097d5cff3f8757222458373a2a3e30dbea91d47f32c092f6557e274bebcbdaf0ae8c121f992
7
+ data.tar.gz: b32faf56e9286e1b4283d900f59f7b1af4bfd89b70366e849200c014540c8e80c45a9110a1d51239372eb414aec5f5f308149960786d6d32f254a942fd404a85
data/README.md CHANGED
@@ -10,11 +10,151 @@ webservice gem - yet another HTTP JSON API (web service) builder
10
10
 
11
11
  ## Usage
12
12
 
13
- TBD
13
+ [Dynamic Example](#dynamic-example) •
14
+ [Classic Example](#classic-example) •
15
+ [Rackup Example](#rackup-example)
16
+
17
+
18
+ ### Dynamic Example
19
+
20
+ You can load services at-runtime from files using `Webservice.load_file`.
21
+ Example:
22
+
23
+ ```ruby
24
+ # service.rb
25
+
26
+ get '/' do
27
+ 'Hello, world!'
28
+ end
29
+ ```
30
+
31
+ and
32
+
33
+ ```ruby
34
+ # server.rb
35
+
36
+ require 'webservice'
37
+
38
+ App = Webservice.load_file( './service.rb' )
39
+ App.run!
40
+ ```
41
+
42
+ and to run type
43
+
44
+ ```
45
+ $ ruby ./server.rb
46
+ ```
47
+
48
+
49
+ ### Classic Example
50
+
51
+ ```ruby
52
+ # server.rb
53
+
54
+ require 'webservice'
55
+
56
+ class App < Webservice::Base
57
+ get '/' do
58
+ 'Hello, world!'
59
+ end
60
+ end
61
+
62
+ App.run!
63
+ ```
64
+ and to run type
65
+
66
+ ```
67
+ $ ruby ./server.rb
68
+ ```
69
+
70
+
71
+ ### Rackup Example
72
+
73
+ Use `config.ru` and `rackup`. Example:
74
+
75
+ ```ruby
76
+ # config.ru
77
+
78
+ require `webservice`
79
+
80
+ class App < Webservice::Base
81
+ get '/' do
82
+ 'Hello, world!'
83
+ end
84
+ end
85
+
86
+ run App
87
+ ```
88
+
89
+ and to run type
90
+
91
+ ```
92
+ $ rackup # will (auto-)load config.ru
93
+ ```
94
+
95
+ Note: `config.ru` is a shortcut (inline)
96
+ version of `Rack::Builder.new do ... end`:
97
+
98
+ ```ruby
99
+ # server.rb
100
+
101
+ require 'webservice'
102
+
103
+ class App < Webservice::Base
104
+ get '/' do
105
+ 'Hello, world!'
106
+ end
107
+ end
108
+
109
+ builder = Rack::Builder.new do
110
+ run App
111
+ end
112
+
113
+ Rack::Server.start builder.to_app
114
+ ```
115
+
116
+ and to run type
117
+
118
+ ```
119
+ $ ruby ./server.rb
120
+ ```
121
+
122
+
123
+
124
+ ## "Real World" Examples
125
+
126
+ See
127
+
128
+ [**`beerkit / beer.db.service`**](https://github.com/beerkit/beer.db.service) -
129
+ beer.db HTTP JSON API (web service) scripts e.g.
130
+
131
+ ```ruby
132
+ get '/beer/(r|rnd|rand|random)' do # special keys for random beer
133
+ Beer.rnd
134
+ end
135
+
136
+ get '/beer/:key'
137
+ Beer.find_by! key: params[:key]
138
+ end
139
+
140
+ get '/brewery/(r|rnd|rand|random)' do # special keys for random brewery
141
+ Brewery.rnd
142
+ end
143
+
144
+ get '/brewery/:key'
145
+ Brewery.find_by! key: params[:key]
146
+ end
147
+ ```
148
+
149
+ [**`worlddb / world.db.service`**](https://github.com/worlddb/world.db.service) -
150
+ world.db HTTP JSON API (web service) scripts
151
+
152
+ [**`sportdb / sport.db.service`**](https://github.com/sportdb/sport.db.service) -
153
+ sport.db (football.db) HTTP JSON API (web service) scripts
154
+
14
155
 
15
156
 
16
157
  ## License
17
158
 
18
159
  The `webservice` scripts are dedicated to the public domain.
19
160
  Use it as you please with no restrictions whatsoever.
20
-
@@ -3,6 +3,9 @@
3
3
  ## stdlib
4
4
  require 'json'
5
5
  require 'csv'
6
+ require 'date'
7
+ require 'time'
8
+ require 'uri'
6
9
  require 'pp'
7
10
 
8
11
 
@@ -3,31 +3,50 @@
3
3
 
4
4
  module Webservice
5
5
 
6
+ ## use (an reuse from Rack) some freezed string constants
7
+ ## HTTP verbs
8
+ GET = Rack::GET
9
+ POST = Rack::POST
10
+ PATCH = Rack::PATCH
11
+ PUT = Rack::PUT
12
+ DELETE = Rack::DELETE
13
+ HEAD = Rack::HEAD
14
+ OPTIONS = Rack::OPTIONS
15
+
16
+ ## HTTP headers
17
+ CONTENT_LENGTH = Rack::CONTENT_LENGTH
18
+ CONTENT_TYPE = Rack::CONTENT_TYPE
19
+
20
+ LOCATION = 'Location'.freeze # not available from Rack
21
+
6
22
 
7
23
  module Helpers
8
24
  ## add some more helpers
9
25
  ## "inspired" by sinatra (mostly) - for staying compatible
10
26
  ## see https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb
11
27
 
12
- ## todo -- add redirect/redirect_to
13
- ## add status -- why? why not??
28
+ ## todo -- add status -- why? why not??
14
29
 
15
30
  # Halt processing and return the error status provided.
16
- def error(code, body=nil)
17
- code = 500
18
- body = code.to_str if code.respond_to? :to_str
19
-
31
+ def error( code, body=nil )
20
32
  response.body = body unless body.nil?
21
33
  halt code
22
34
  end
23
35
 
24
36
  # Halt processing and return a 404 Not Found.
25
- def not_found(body=nil)
37
+ def not_found( body=nil )
26
38
  error 404, body
27
39
  end
28
40
 
41
+
42
+ def redirect_to( uri, status=302 ) ## Note: 302 == Found, 301 == Moved Permanently
43
+ halt status, { LOCATION => uri }
44
+ end
45
+ alias_method :redirect, :redirect_to
46
+
47
+
29
48
  # Set multiple response headers with Hash.
30
- def headers(hash=nil)
49
+ def headers( hash=nil )
31
50
  response.headers.merge! hash if hash
32
51
  response.headers
33
52
  end
@@ -36,18 +55,18 @@ module Helpers
36
55
 
37
56
  ## (simple) content_type helper - all "hard-coded" for now; always uses utf-8 too
38
57
  def content_type( type=nil )
39
- return response['Content-Type'] unless type
58
+ return response[ CONTENT_TYPE ] unless type
40
59
 
41
60
  if type.to_sym == :json
42
- response['Content-Type'] = 'application/json; charset=utf-8'
61
+ response[ CONTENT_TYPE ] = 'application/json; charset=utf-8'
43
62
  elsif type.to_sym == :js || type.to_sym == :javascript
44
- response['Content-Type'] = 'application/javascript; charset=utf-8'
63
+ response[ CONTENT_TYPE ] = 'application/javascript; charset=utf-8'
45
64
  ## use 'text/javascript; charset=utf-8' -- why? why not??
46
65
  ## note: ietf recommends application/javascript
47
66
  elsif type.to_sym == :csv || type.to_sym == :text || type.to_sym == :txt
48
- response['Content-Type'] = 'text/plain; charset=utf-8'
67
+ response[ CONTENT_TYPE ] = 'text/plain; charset=utf-8'
49
68
  elsif type.to_sym == :html || type.to_sym == :htm
50
- response['Content-Type'] = 'text/html; charset=utf-8'
69
+ response[ CONTENT_TYPE ] = 'text/html; charset=utf-8'
51
70
  else
52
71
  ### unknown type; do nothing - sorry; issue warning - why? why not??
53
72
  end
@@ -58,24 +77,38 @@ end ## module Helpers
58
77
  class Base
59
78
  include Helpers
60
79
 
80
+
61
81
  class << self
62
82
 
83
+ def call( env ) ## note self.call(env) lets you use => run Base instead of run Base.new
84
+ ## puts "calling #{self.name}.call"
85
+ prototype.call( env )
86
+ end
87
+
88
+ def prototype
89
+ ## puts "calling #{self.name}.prototype"
90
+ @prototype ||= self.new
91
+ ## pp @prototype
92
+ ## @prototype
93
+ end
94
+
95
+
63
96
  ## todo/check: all verbs needed! (supported) - why, why not??
64
97
  ## e.g. add LINK, UNLINK ??
65
98
 
66
99
  # Note: for now defining a `GET` handler also automatically defines
67
100
  # a `HEAD` handler (follows sinatra convention)
68
- def get( pattern, &block)
69
- route( 'GET', pattern, &block )
70
- route( 'HEAD', pattern, &block )
101
+ def get( pattern, &block )
102
+ route( GET, pattern, &block )
103
+ route( HEAD, pattern, &block )
71
104
  end
72
105
 
73
- def post( pattern, &block) route( 'POST', pattern, &block ); end
74
- def patch( pattern, &block) route( 'PATCH', pattern, &block ); end
75
- def put( pattern, &block) route( 'PUT', pattern, &block ); end
76
- def delete( pattern, &block) route( 'DELETE', pattern, &block ); end
77
- def head( pattern, &block) route( 'HEAD', pattern, &block ); end
78
- def options( pattern, &block) route( 'OPTIONS', pattern, &block ); end
106
+ def post( pattern, &block) route( POST, pattern, &block ); end
107
+ def patch( pattern, &block) route( PATCH, pattern, &block ); end
108
+ def put( pattern, &block) route( PUT, pattern, &block ); end
109
+ def delete( pattern, &block) route( DELETE, pattern, &block ); end
110
+ def head( pattern, &block) route( HEAD, pattern, &block ); end
111
+ def options( pattern, &block) route( OPTIONS, pattern, &block ); end
79
112
 
80
113
  def route( method, pattern, &block )
81
114
  puts "[debug] Webservice::Base.#{method.downcase} - add route #{method} '#{pattern}' to #<#{self.name}:#{self.object_id}> : #{self.class.name}"
@@ -93,7 +126,7 @@ class Base
93
126
  def environment
94
127
  ## include APP_ENV why? why not?
95
128
  ## todo -- cache value? why why not? (see/follow sinatara set machinery ??)
96
- (ENV['RACK_ENV'] || :development).to_sym
129
+ (ENV['APP_ENV'] || ENV['RACK_ENV'] || :development).to_sym
97
130
  end
98
131
 
99
132
  def development?() environment == :development; end
@@ -104,9 +137,9 @@ class Base
104
137
  ## convenience method
105
138
  def run!
106
139
  puts "[debug] Webservice::Base.run! - self = #<#{self.name}:#{self.object_id}> : #{self.class.name}" # note: assumes self is class
107
- app = self.new ## note: use self; will be derived class (e.g. App and not Base)
140
+ app = self ## note: use self; will be derived class (e.g. App and not Base)
108
141
  port = 4567
109
- Rack::Handler.get('webrick').run( app, Port:port ) do |server|
142
+ Rack::Handler::WEBrick.run( app, Port:port ) do |server|
110
143
  ## todo: add traps here - why, why not??
111
144
  end
112
145
  end
@@ -119,25 +152,35 @@ class Base
119
152
  attr_reader :params
120
153
  attr_reader :env
121
154
 
122
- def call(env)
123
- dup.call!(env)
155
+ def call( env )
156
+ dup.call!( env )
124
157
  end
125
158
 
126
- def call!(env)
159
+ def call!( env )
127
160
  env['PATH_INFO'] = '/' if env['PATH_INFO'].empty?
128
- @request = Rack::Request.new(env)
161
+
162
+ @request = Rack::Request.new( env )
129
163
  @response = Rack::Response.new
130
164
  @params = request.params
131
165
  @env = env
166
+
167
+
168
+ ## (auto-)add (merge in) cors headers
169
+ ## todo: move into a before filter ?? lets you overwrite headers - needed - why? why not??
170
+ headers 'Access-Control-Allow-Origin' => '*',
171
+ 'Access-Control-Allow-Headers' => 'Authorization,Accepts,Content-Type,X-CSRF-Token,X-Requested-With',
172
+ 'Access-Control-Allow-Methods' => 'GET,POST,PUT,DELETE,OPTIONS'
173
+
132
174
  route_eval
175
+
133
176
  @response.finish
134
177
  end
135
178
 
136
179
 
137
180
  def halt( *args )
138
- response.status = args.detect{|arg| arg.is_a?(Fixnum) } || 200
139
- response.header.merge!(args.detect{|arg| arg.is_a?(Hash) } || {})
140
- response.body = [args.detect{|arg| arg.is_a?(String) } || '']
181
+ response.status = args.detect{ |arg| arg.is_a?(Fixnum) } || 200
182
+ response.header.merge!( args.detect{ |arg| arg.is_a?(Hash) } || {} )
183
+ response.body = [args.detect{ |arg| arg.is_a?(String) } || '']
141
184
  throw :halt, response
142
185
  end
143
186
 
@@ -145,57 +188,98 @@ private
145
188
 
146
189
  def route_eval
147
190
  catch(:halt) do
148
- self.class.routes[request.request_method].each do |pattern, block|
191
+ routes = self.class.routes[ request.request_method ]
192
+ routes.each do |pattern, block|
149
193
  ## puts "trying matching route >#{request.path_info}<..."
150
194
  url_params = pattern.params( request.path_info )
151
195
  if url_params ## note: params returns nil if no match
152
196
  ## puts " BINGO! url_params: #{url_params.inspect}"
153
197
  if !url_params.empty? ## url_params hash NOT empty (e.g. {}) merge with req params
154
198
  ## todo/fix: check merge order - params overwrites url_params - why? why not??
155
- @params = url_params.merge( params )
199
+ @params = url_params.merge( @params )
156
200
  end
157
201
  handle_response( instance_eval( &block ))
158
202
  return
159
203
  end
160
204
  end
205
+ # no match found for route/request
161
206
  halt 404
162
207
  end
163
208
  end
164
209
 
165
210
 
166
211
 
167
-
168
- def handle_response( obj )
212
+ ## todo: add as_json like opts={} why? why not?
213
+ def handle_response( obj, opts={} )
169
214
  puts "[Webservice::Base#handle_response (#{request.path_info}) params: #{params.inspect}] - obj : #{obj.class.name}"
170
215
  pp obj
171
216
 
172
217
  ## "magic" param format; default to json
173
218
  format = params['format'] || 'json'
174
219
 
175
- if format == 'csv' || format == 'txt'
176
- text = generate_csv( obj )
177
- content_type :text
178
- response.write text
179
- elsif format == 'html' || format == 'htm'
180
- text = generate_html_table( obj )
181
- content_type :html
182
- response.write text
220
+ ## note: response.body must be (expects) an array!!!
221
+ ## thus, [json] etc.
222
+
223
+ if format == 'csv' || format == 'txt' ||
224
+ format == 'html' || format == 'htm'
225
+
226
+ data = as_tabular( obj )
227
+
228
+ ## note: array required!!!
229
+ # array => multiple records (array of hashes)
230
+ if data.is_a?( Array )
231
+ if format == 'csv' || format == 'txt'
232
+ content_type :txt ## use csv content type - why? why not??
233
+ response.body = [generate_csv( data )]
234
+ else
235
+ ## asume html
236
+ content_type :html
237
+ response.body = [generate_html_table( data )]
238
+ end
239
+ else
240
+ ## wrong format (expect array of hashes)
241
+ ## todo: issue warning/notice about wrong format - how?
242
+ ## use different http status code - why? why not??
243
+ content_type :txt
244
+ ## todo/check: use just data.to_s for all - why? why not?
245
+ ## for now return as is (convert to string with to_s or inspect)
246
+ response.body = [data.is_a?( String ) ? data.to_s : data.inspect]
247
+ end
183
248
  else
184
- json = generate_json( obj )
249
+ data = as_json( obj )
250
+
251
+ ## note: hash or array required!!! for now for json generation
252
+ # hash => single record
253
+ # array => multiple records (that is, array of hashes)
254
+
255
+ if data.is_a?( Hash ) || data.is_a?( Array )
256
+ json = JSON.pretty_generate( data ) ## use pretty printer
185
257
 
186
- callback = params.delete('callback')
258
+ callback = params.delete( 'callback' )
187
259
 
188
- if callback
189
- content_type :js
190
- response.write "#{callback}(#{json})"
260
+ if callback
261
+ content_type :js
262
+ response.body = ["#{callback}(#{json})"]
263
+ else
264
+ content_type :json
265
+ response.body = [json]
266
+ end
191
267
  else
192
- content_type :json
193
- response.write json
268
+ ## todo/fix/check: change http status to unprocessable entity
269
+ ## or something -- why ??? why not??
270
+ ##
271
+ ## allow "standalone" number, nils, strings - why? why not?
272
+ ## for now valid json must be wrapped in array [] or hash {}
273
+ content_type :txt
274
+ ## todo/check: use just data.to_s for all - why? why not?
275
+ ## for now return as is (convert to string with to_s or inspect)
276
+ response.body = [data.is_a?( String ) ? data.to_s : data.inspect]
194
277
  end
195
278
  end
196
279
  end # method handle_response
197
280
 
198
281
 
282
+
199
283
  def generate_csv( recs )
200
284
  ## note: for now assumes (only works with) array of hash records e.g.:
201
285
  ## [
@@ -243,14 +327,38 @@ private
243
327
  end
244
328
 
245
329
 
246
- def generate_json( obj )
247
- if obj.respond_to? :as_json_v2 ## try (our own) serializer first
330
+ ##########################################
331
+ ## auto-generate/convert "magic"
332
+
333
+ def as_tabular( obj, opts={} )
334
+ ## for now allow
335
+ ## as_tab, as_tabular - others too? e.g. as_table why? why not?
336
+ ## like as_json will return a hash or array of hashes NOT a string!!!!
337
+
338
+ if obj.respond_to? :as_tab
339
+ obj.as_tab
340
+ elsif obj.respond_to? :as_tabular
341
+ obj.as_tabular
342
+ else
343
+ ## note: use as_json will return hash (for record) or array of hashes (for records)
344
+ if obj.respond_to? :as_json
345
+ obj.as_json
346
+ else
347
+ obj ## just try/use as is (assumes array of hashesd)
348
+ end
349
+ end
350
+ end
351
+
352
+
353
+ def as_json( obj, opts={} )
354
+ if obj.respond_to? :as_json_v3 ## try (our own) serializer first
355
+ obj.as_json_v3
356
+ elsif obj.respond_to? :as_json_v2 ## try (our own) serializer first
248
357
  obj.as_json_v2
249
358
  elsif obj.respond_to? :as_json ## try (activerecord) serializer
250
- obj.as_json_v2
359
+ obj.as_json
251
360
  else
252
- ## just try/use to_json
253
- obj.to_json
361
+ obj ## just try/use as is
254
362
  end
255
363
  end
256
364
 
@@ -1,10 +1,16 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Webservice
4
- MAJOR = 0 ## todo: namespace inside version or something - why? why not??
5
- MINOR = 4
6
- PATCH = 0
7
- VERSION = [MAJOR,MINOR,PATCH].join('.')
4
+
5
+ module Version
6
+ MAJOR = 0 ## todo: namespace inside version or something - why? why not??
7
+ MINOR = 5
8
+ PATCH = 0 ## note: if not put in module will overwrite PATCH (HTTP Verb Constant)!!!
9
+ end
10
+
11
+ VERSION = [Version::MAJOR,
12
+ Version::MINOR,
13
+ Version::PATCH].join('.')
8
14
 
9
15
  def self.version
10
16
  VERSION
@@ -13,12 +13,10 @@ end
13
13
 
14
14
  get '/halt/404' do
15
15
  halt 404 # 404 - not found
16
- ## todo: check why log reports 200-OK (for status code)!!
17
16
  end
18
17
 
19
18
  get '/halt_error' do
20
19
  halt 500, "Error fatal" # 500 - internal server error
21
- ## todo: check why log reports 200-OK (for status code)!!
22
20
  end
23
21
 
24
22
 
@@ -24,46 +24,46 @@ class TestApp < MiniTest::Test
24
24
  def test_get
25
25
  get '/'
26
26
  assert last_response.ok?
27
- assert_equal %q{"Hello World"}, last_response.body
27
+ assert_equal "Hello World", last_response.body
28
28
 
29
29
  get '/hello/world'
30
30
  assert last_response.ok?
31
- assert_equal %q{"Hello world"}, last_response.body
31
+ assert_equal "Hello world", last_response.body
32
32
 
33
33
  ##############################
34
34
  ## get '/hello/:name'
35
35
  get '/hello/ruby'
36
36
  assert last_response.ok?
37
- assert_equal %q{"Hello ruby"}, last_response.body
37
+ assert_equal "Hello ruby", last_response.body
38
38
 
39
39
  get '/hello/ruby?test=t' ## try w/ extra query string/params
40
40
  assert last_response.ok?
41
- assert_equal %q{"Hello ruby"}, last_response.body
41
+ assert_equal "Hello ruby", last_response.body
42
42
 
43
43
  ##################################
44
44
  ## get '/:message/:name'
45
45
  get '/servus/wien'
46
46
  assert last_response.ok?
47
- assert_equal %q{"servus wien"}, last_response.body
47
+ assert_equal "servus wien", last_response.body
48
48
 
49
49
  get '/Hallo/Welt'
50
50
  assert last_response.ok?
51
- assert_equal %q{"Hallo Welt"}, last_response.body
51
+ assert_equal "Hallo Welt", last_response.body
52
52
  end
53
53
 
54
54
 
55
55
  def test_format
56
56
  get '/key.format'
57
57
  assert last_response.ok?
58
- assert_equal %q{"key format"}, last_response.body
58
+ assert_equal "key format", last_response.body
59
59
 
60
60
  get '/ottakringer.xxx'
61
61
  assert last_response.ok?
62
- assert_equal %q{"ottakringer xxx"}, last_response.body
62
+ assert_equal "ottakringer xxx", last_response.body
63
63
 
64
64
  get '/ottakringer'
65
65
  assert last_response.ok?
66
- assert_equal %q{"ottakringer "}, last_response.body
66
+ assert_equal "ottakringer ", last_response.body
67
67
  end
68
68
 
69
69
 
@@ -85,25 +85,38 @@ CSV
85
85
  </table>
86
86
  HTML
87
87
 
88
+
89
+ countries_json = <<JSON.strip
90
+ [
91
+ {
92
+ "key": "at",
93
+ "name": "Austria"
94
+ },
95
+ {
96
+ "key": "mx",
97
+ "name": "Mexico"
98
+ }
99
+ ]
100
+ JSON
101
+
88
102
  get '/countries.json'
89
103
  assert last_response.ok?
90
- assert_equal %q<[{"key":"at","name":"Austria"},{"key":"mx","name":"Mexico"}]>, last_response.body
104
+ assert_equal countries_json, last_response.body
91
105
 
92
106
  get '/countries'
93
107
  assert last_response.ok?
94
- assert_equal %q<[{"key":"at","name":"Austria"},{"key":"mx","name":"Mexico"}]>, last_response.body
108
+ assert_equal countries_json, last_response.body
95
109
  end # method test_countries
96
110
 
97
111
 
112
+
98
113
  def test_halt
99
- ## get '/halt/404'
100
114
  get '/halt/404'
115
+ assert_equal 404, last_response.status
101
116
 
102
- ## get '/halt_error' - 500, "Error fatal" # 500 - internal server error
103
- get '/halt_error'
104
-
105
- ## todo: check error codes
106
- assert true
117
+ get '/halt_error' ## 500, "Error fatal" # 500 - internal server error
118
+ assert_equal 500, last_response.status
119
+ assert_equal "Error fatal", last_response.body
107
120
  end
108
121
 
109
122
  end # class TestApp
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webservice
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-20 00:00:00.000000000 Z
11
+ date: 2017-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: logutils