sinatra-rest-base 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b9af7fb5e0df73f24103bb5b39ea04ff158da525
4
+ data.tar.gz: 163aa0d3b19c1602dc156774e8ed3d78068e9471
5
+ SHA512:
6
+ metadata.gz: ad4876e275d150164b2b7deabf58de1b1ee57ada749377740ff861cb3548d02a9944c9c1eddc90960d4e9d890fcd9fb9a93905dcd6ef1a5bf3c5474ab8f21829
7
+ data.tar.gz: 9a912cb5fff19ba832be1bb90bc5e7d9d4346569fe944b7f253e9f862e4940b9bfd61e8de4ff4067f5a7c420b23a009df61b3855138a8908a498053751e244d2
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sintara-rest-base.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 bmills
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Rest
2
+
3
+ Core base classes for quick configuration of Sinatra for RESTful Services
4
+
5
+ #### What Does the Core Cover
6
+
7
+ * Adherence to [API Standards] (https://github.com/RESTful-Forest/Sinatra-Rest-Base/wiki/RESTful-API-Standards)
8
+ * Basic Configuration
9
+ * Storing the IO String Request Body into a global hash 'request_body'
10
+ * Processing the response body into the proper accepted mime type (application/json, text/xml, ect.) depending on the HTTP_ACCEPT header.
11
+ * Defaults to application/json
12
+ * Processing the version of the application being accessed via HTTP_ACCEPT header
13
+ * Basic Error Handeling
14
+ * Handles Authentication Errors, StandardError, Error status codes 400..510
15
+ * Implements Basic Error Classes
16
+ * InvalidRequest
17
+ * More to come soon!
18
+ * Simple authentication setup
19
+ * Provides a base authentication class to inherit from and create a quick authentication process.
20
+ * Provides an easy authentication setup through the configuration setup of Sinatra.
21
+
22
+ ## Installation
23
+
24
+ Add this line to your application's Gemfile:
25
+
26
+ gem 'sinatra-rest-base'
27
+
28
+ And then execute:
29
+
30
+ $ bundle
31
+
32
+ Or install it yourself as:
33
+
34
+ $ gem install sinatra-rest-base
35
+
36
+ ## Usage
37
+
38
+ #### Setting Up the Application
39
+
40
+ Normal Sinatra Appication inherit from either Sinatra::Application or Sinatra::Base. With sinatra-rest-base you just need to inherit from Rest::Application.
41
+
42
+ In your main application file, do the following:
43
+
44
+ ```
45
+ require 'rest'
46
+
47
+ class SinatraApp < Rest::Application
48
+ end
49
+ ```
50
+
51
+ then in any other partial class file of the main application file, you just have to name the class like follow:
52
+
53
+ ```
54
+ require 'rest'
55
+
56
+ class SinatraApp
57
+
58
+ get '/' do
59
+ {
60
+ :result => "This is so easy now!"
61
+ }
62
+ end
63
+
64
+ end
65
+ ```
66
+
67
+ Bam, that easy!
68
+
69
+ ## [Documentation Wiki] (https://github.com/RESTful-Forest/Sinatra-Rest-Base/wiki/Documentation)
70
+
71
+ ## Contributing
72
+
73
+ 1. Fork it ( https://github.com/[my-github-username]/sintara-rest-base/fork )
74
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
75
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
76
+ 4. Push to the branch (`git push origin my-new-feature`)
77
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,42 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+ require 'active_support'
4
+ require 'active_support/core_ext/hash'
5
+ require 'rest/authentication'
6
+
7
+ module Rest
8
+ class Application < Sinatra::Base
9
+ attr_reader :request_body
10
+ attr_reader :request_version
11
+ attr_reader :errored
12
+
13
+ configure do
14
+ disable :raise_errors
15
+ disable :show_exceptions
16
+ set :api_version, 1
17
+ set :authentication, Rest::Authentication::BasicAuthentication.new([])
18
+ disable :header_versioning
19
+ end
20
+
21
+ set(:version) do |value|
22
+ condition do
23
+ has_version?("version=#{value}")
24
+ end
25
+ end
26
+
27
+ before do
28
+ status 200
29
+
30
+ set_api_version if settings.header_versioning
31
+ set_request_body
32
+ error 401 unless authenticated?
33
+ end
34
+
35
+ after do
36
+ response.body = nil if response.body.is_a?(Array) && response.body.length == 1 && response.body[0].empty?
37
+ response.body = create_response()
38
+
39
+ response.headers['Content-Type'] += ";version=#{@request_version}"
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,65 @@
1
+ module Rest
2
+ class Application < Sinatra::Base
3
+ def authenticated?
4
+ authorized = true
5
+ authorized = settings.authentication.authorized?(request, @env['HTTP_AUTHORIZATION']) unless settings.authentication.nil?
6
+ authorized
7
+ end
8
+
9
+ def has_version?(version)
10
+ @env['HTTP_ACCEPT'] = "*/*" if @env['HTTP_ACCEPT'].nil?
11
+ @env['HTTP_ACCEPT'].include?(version)
12
+ end
13
+
14
+ def get_version
15
+ matchdata = @env['HTTP_ACCEPT'].to_s.scan(/(version)=(\d*)/)
16
+ matchdata[0][1].delete(',').to_f
17
+ end
18
+
19
+ def set_api_version
20
+ @env['HTTP_ACCEPT'] += ";version=#{settings.api_version}" unless has_version?("version=")
21
+ @env['sinatra.accept'] = nil
22
+ @request_version = get_version
23
+ end
24
+
25
+ def set_request_body
26
+ read_body = request.body.read
27
+
28
+ if read_body.empty?
29
+ @request_body = {}
30
+ elsif request.media_type.downcase == 'text/xml'
31
+ @request_body = Hash.from_xml(read_body)
32
+ @request_body = Hash[@request_body.map{ |k, v| [k.to_sym, v] }]
33
+ @request_body = @request_body[:request]
34
+ else
35
+ @request_body = JSON.parse(read_body, :symbolize_names => true)
36
+ end
37
+ end
38
+
39
+ def create_response()
40
+ content_type :json
41
+ content_type :xml if !request.accept?('*/*') && request.accept?('text/xml')
42
+
43
+ if (response.status >= 400)
44
+ error_hash = response.body
45
+ error_hash = [error_hash] if error_hash.is_a?(String)
46
+
47
+ response.body = nil
48
+ end
49
+
50
+ response_hash = {
51
+ :errors => error_hash,
52
+ :results => response.body
53
+ }
54
+
55
+ return '' if empty_body_status_code? && (response.body.empty?)
56
+ return response_hash.to_xml(:root => :response) if response.headers['Content-Type'].start_with? 'application/xml;'
57
+ response_hash.to_json
58
+ end
59
+
60
+ def empty_body_status_code?
61
+ empty_body_status_codes = [201, 204, 304]
62
+ response != nil && empty_body_status_codes.include?(response.status)
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,9 @@
1
+ module Rest
2
+ module Authentication
3
+ class AuthenticationBase
4
+ def authorized?(request, key)
5
+ true
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,15 @@
1
+ module Rest
2
+ module Authentication
3
+ class BasicAuthentication < AuthenticationBase
4
+ def initialize(keys)
5
+ @valid_keys = keys
6
+ end
7
+
8
+ def authorized?(request, key)
9
+ authorized = true
10
+ authorized = @valid_keys.include?(key) unless @valid_keys.length == 0
11
+ authorized
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Rest
2
+ module Authentication
3
+
4
+ end
5
+ end
6
+
7
+ Gem.find_files('rest/authentication/*.rb').each { |path| require path }
@@ -0,0 +1,17 @@
1
+ require 'sinatra/base'
2
+ require 'rest/exceptions'
3
+
4
+ module Rest
5
+ class Application < Sinatra::Base
6
+ error Rest::Exceptions::InvalidRequest do
7
+ cur_error = env["sinatra.error"]
8
+ errors = [cur_error.message]
9
+
10
+ cur_error.invalid_params.each { |param, message|
11
+ errors << "#{param.to_s} is not valid: #{message}"
12
+ }
13
+
14
+ errors
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module Rest
2
+ class Application < Sinatra::Base
3
+ not_found do
4
+ response.body = 'Endpoint not found'
5
+ end
6
+
7
+ error 401 do
8
+ response.body = 'Unauthorized Access'
9
+ create_response()
10
+ end
11
+
12
+ error 404 do
13
+ response.body = "Endpoint not found"
14
+ create_response()
15
+ end
16
+
17
+ error 500 do
18
+ return @env['sinatra.error'].message unless @env['sinatra.error'].nil?
19
+ response.body = 'Internal Error'
20
+ create_response()
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,12 @@
1
+ module Rest
2
+ module Exceptions
3
+ class InvalidRequest < StandardError
4
+ attr_reader :invalid_params
5
+
6
+ def initialize(invalid_params)
7
+ @invalid_params = invalid_params
8
+ super "Invalid Request Format"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,6 @@
1
+ module Rest
2
+ module Exceptions
3
+ end
4
+ end
5
+
6
+ Gem.find_files('rest/exceptions/*.rb').each { |path| require path }
@@ -0,0 +1,3 @@
1
+ module Rest
2
+ VERSION = "0.1.0"
3
+ end
data/lib/rest.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Rest
2
+
3
+ end
4
+
5
+ Gem.find_files('rest/*.rb').each { |path| require path }
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rest/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sinatra-rest-base"
8
+ spec.version = Rest::VERSION
9
+ spec.authors = ["bmills"]
10
+ spec.email = ["brandon.mills@careerbuilder.com"]
11
+ spec.summary = %q{Base class for quickly setting up RESTful services through Sinatra.}
12
+ spec.description = %q{Base class for quickly setting up RESTful services through Sinatra.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "json", "~> 1.8"
22
+ spec.add_dependency "sinatra", "~> 1.4"
23
+ spec.add_dependency "thin", "~> 1.6"
24
+ spec.add_dependency "activesupport", "~> 4.1"
25
+ spec.add_dependency "builder", "~> 3.2"
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.6"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rack-test", "~> 0.6"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ spec.add_development_dependency "simplecov", "~> 0.8"
32
+ end
@@ -0,0 +1,11 @@
1
+ module Rest
2
+ module Test
3
+ class TestApplication < Rest::Application
4
+ configure do
5
+ enable :raise_errors
6
+ set :authentication, Rest::Authentication::BasicAuthentication.new(['key1', 'key2'])
7
+ enable :header_versioning
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,60 @@
1
+ module Rest
2
+ module Test
3
+ class TestApplication
4
+ get '/', :version => 1 do
5
+ {
6
+ :gotten => "success"
7
+ }
8
+ end
9
+
10
+ get '/', :version => 2 do
11
+ {
12
+ :gotten => "success 2"
13
+ }
14
+ end
15
+
16
+ get '/empty', :version => 1 do
17
+ ""
18
+ end
19
+
20
+ get '/created', :version => 1 do
21
+ status 201
22
+ end
23
+
24
+ get '/nocontent', :version => 1 do
25
+ status 204
26
+ end
27
+
28
+ get '/notmodified', :version => 1 do
29
+ status 304
30
+ end
31
+
32
+ get '/created_with_body', :version => 1 do
33
+ status 201
34
+ { :created => true }
35
+ end
36
+
37
+ post '/', :version => 1 do
38
+ {
39
+ :posted => request_body
40
+ }
41
+ end
42
+
43
+ put '/', :version => 1 do
44
+ {
45
+ :updated => request_body
46
+ }
47
+ end
48
+
49
+ delete '/', :version => 1 do
50
+ {
51
+ :deleted => request_body
52
+ }
53
+ end
54
+
55
+ delete '/nocontent', :version => 1 do
56
+ status 204
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,34 @@
1
+ module Rest
2
+ module Test
3
+ class TestApplication
4
+ get '/invalid_request', :version => 1 do
5
+ param_errors = {
6
+ :param1 => "Must be a String",
7
+ :param2 => "Must be an Integer"
8
+ }
9
+
10
+ raise Rest::Exceptions::InvalidRequest.new(param_errors)
11
+ end
12
+
13
+ get '/unauthorized', :version => 1 do
14
+ error 401
15
+ end
16
+
17
+ get '/internal_error', :version => 1 do
18
+ error 500
19
+ end
20
+
21
+ get '/internal_error_raised', :version => 1 do
22
+ raise StandardError.new("Raised Internal Error")
23
+ end
24
+
25
+ get '/default_error_handeling', :version => 1 do
26
+ error 400, "This is the default error handler"
27
+ end
28
+
29
+ get '/hashed_error_handeling', :version => 1 do
30
+ error 400, { :error => "This is the hashed error handler" }
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,184 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rest::Application do
4
+ before(:each) do
5
+ @headers = { 'HTTP_AUTHORIZATION' => 'key1' }
6
+ end
7
+
8
+ describe :version do
9
+ it "should set the version to latest when not given" do
10
+ expected_version = "version=1"
11
+
12
+ get '/', {}, @headers
13
+
14
+ expect(last_request.env["HTTP_ACCEPT"].include? expected_version).to be_truthy
15
+ expect(last_response.headers["Content-Type"].include? expected_version).to be_truthy
16
+ end
17
+
18
+ it "should get the version 1 version" do
19
+ expected_version = "version=1"
20
+ @headers['HTTP_ACCEPT'] = "application/json;#{expected_version}"
21
+
22
+ get '/', {}, @headers
23
+
24
+ expect(last_request.env["HTTP_ACCEPT"].include? expected_version).to be_truthy
25
+ expect(last_response.headers["Content-Type"].include? expected_version).to be_truthy
26
+ expect(last_response.body).to eq({:errors => nil, :results => { :gotten => "success" }}.to_json)
27
+ end
28
+
29
+ it "should get the version 2 version" do
30
+ expected_version = "version=2"
31
+ @headers['HTTP_ACCEPT'] = expected_version
32
+
33
+ get '/', {}, @headers
34
+
35
+ expect(last_request.env["HTTP_ACCEPT"].include? expected_version).to be_truthy
36
+ expect(last_response.headers["Content-Type"].include? expected_version).to be_truthy
37
+ expect(last_response.body).to eq({:errors => nil, :results => { :gotten => "success 2" }}.to_json)
38
+ end
39
+ end
40
+
41
+ describe :authorization do
42
+ it "should try to authorize" do
43
+ get '/', {}, @headers
44
+ end
45
+ end
46
+
47
+ describe :status do
48
+ it "should return status code 200" do
49
+ get '/', {}, @headers
50
+
51
+ expect(last_response.status).to eq(200)
52
+ end
53
+ end
54
+
55
+ describe :empty_response do
56
+ it "should return an empty string response" do
57
+ get '/empty', {}, @headers
58
+
59
+ expect(last_response.body).to eq({:errors => nil, :results => nil}.to_json)
60
+ end
61
+ end
62
+
63
+ describe :no_content do
64
+ it "should return a no content response with empty body" do
65
+ get '/nocontent', {}, @headers
66
+
67
+ expect(last_response.status).to eq(204)
68
+ expect(last_response.body).to be_empty
69
+ end
70
+
71
+ it "should return a created response with empty body" do
72
+ get '/created', {}, @headers
73
+
74
+ expect(last_response.status).to eq(201)
75
+ expect(last_response.body).to be_empty
76
+ end
77
+
78
+ it "shoud return a created response with body" do
79
+ get '/created_with_body', {}, @headers
80
+
81
+ expect(last_response.status).to eq(201)
82
+ expect(last_response.body).to eq({:errors => nil, :results => {:created => true}}.to_json)
83
+ end
84
+
85
+ it "should return a not modified response with empty body" do
86
+ get '/notmodified', {}, @headers
87
+
88
+ expect(last_response.status).to eq(304)
89
+ expect(last_response.body).to be_empty
90
+ end
91
+
92
+ it "should delete and return a no content response with empty body" do
93
+ delete '/nocontent', {}, @headers
94
+
95
+ expect(last_response.status).to eq(204)
96
+ expect(last_response.body).to be_empty
97
+ end
98
+ end
99
+
100
+ describe :json do
101
+ before(:each) do
102
+ @posted_body = { :success => true }
103
+
104
+ @expected_hash = {:errors => nil, :results => { :posted => @posted_body }}
105
+ end
106
+
107
+ it "should get json" do
108
+ @expected_hash = {:errors => nil, :results => { :gotten => "success" }}
109
+
110
+ get '/', {}, @headers
111
+
112
+ expect(last_response.body).to eq(@expected_hash.to_json)
113
+ end
114
+
115
+ it "should set the request body to json" do
116
+ @headers['CONTENT_TYPE'] = 'application/json'
117
+
118
+ post '/', @posted_body.to_json, @headers
119
+
120
+ expect(last_response.body).to eq(@expected_hash.to_json)
121
+ end
122
+
123
+ it "should post xml and return json" do
124
+ @headers['CONTENT_TYPE'] = 'text/xml'
125
+ post '/', @posted_body.to_xml(:root => :request), @headers
126
+
127
+ expect(last_response.body).to eq(@expected_hash.to_json)
128
+ end
129
+
130
+ it "should post empty json and return json" do
131
+ post '/', "", @headers
132
+
133
+ @expected_hash[:results][:posted] = {}
134
+ expect(last_response.body).to eq(@expected_hash.to_json)
135
+ end
136
+
137
+ it "should post json with json string as body" do
138
+ post '/', @posted_body.to_json, @headers
139
+
140
+ expect(last_response.body).to eq(@expected_hash.to_json)
141
+ end
142
+ end
143
+
144
+ describe :xml do
145
+ before(:each) do
146
+ @posted_body = { :success => true }
147
+
148
+ @expected_hash = {:errors => nil, :results => { :posted => @posted_body }}
149
+ end
150
+
151
+ it "should get xml" do
152
+ @headers['HTTP_ACCEPT'] = 'text/xml'
153
+ @expected_hash = { :errors => nil, :results => { :gotten => 'success'} }
154
+
155
+ get '/', {}, @headers
156
+
157
+ expect(last_response.body).to eq(@expected_hash.to_xml(:root => :response))
158
+ end
159
+
160
+ it "should set the request body to xml" do
161
+ @headers['CONTENT_TYPE'] = 'text/xml'
162
+ @headers['HTTP_ACCEPT'] = 'text/xml'
163
+ post '/', @posted_body.to_xml(:root => :request), @headers
164
+
165
+ expect(last_response.body).to eq(@expected_hash.to_xml(:root => :response))
166
+ end
167
+
168
+ it "should post json and return xml" do
169
+ @headers['CONTENT_TYPE'] = 'application/json'
170
+ @headers['HTTP_ACCEPT'] = 'text/xml'
171
+ post '/', @posted_body.to_json, @headers
172
+
173
+ expect(last_response.body).to eq(@expected_hash.to_xml(:root => :response))
174
+ end
175
+
176
+ it "should post json with json string as body" do
177
+ @headers['CONTENT_TYPE'] = 'text/xml'
178
+ @headers['HTTP_ACCEPT'] = 'text/xml'
179
+ post '/', @posted_body.to_xml(:root => :request), @headers
180
+
181
+ expect(last_response.body).to eq(@expected_hash.to_xml(:root => :response))
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,11 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rest::Authentication::AuthenticationBase do
4
+ describe :authorized? do
5
+ it "should always be true" do
6
+ target = Rest::Authentication::AuthenticationBase.new
7
+
8
+ expect(target.authorized?(nil, 'key')).to be_truthy
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rest::Authentication::BasicAuthentication do
4
+ describe :initialize do
5
+ it "should initialize with valid keys" do
6
+ expected_keys = ['key1', 'key2']
7
+ target = Rest::Authentication::BasicAuthentication.new(expected_keys)
8
+
9
+ expect(target.instance_variable_get(:@valid_keys)).to eq(expected_keys)
10
+ end
11
+ end
12
+
13
+ describe :authorized? do
14
+ it "should authorized if empty valid array" do
15
+ target = Rest::Authentication::BasicAuthentication.new([])
16
+ expect(target.authorized?(nil, 'key')).to be_truthy
17
+ end
18
+
19
+ it "should authorize the given key" do
20
+ target = Rest::Authentication::BasicAuthentication.new(['key1', 'key2'])
21
+ expect(target.authorized?(nil, 'key1')).to be_truthy
22
+ end
23
+
24
+ it "should authorize the given key" do
25
+ target = Rest::Authentication::BasicAuthentication.new(['key1', 'key2'])
26
+ expect(target.authorized?(nil,'key')).to_not be_truthy
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rest::Application do
4
+ before(:each) do
5
+ @headers = { 'HTTP_AUTHORIZATION' => 'key1' }
6
+ end
7
+
8
+ describe :invalid_request do
9
+ it "should return the invalid param messages" do
10
+ expected_body = {
11
+ :errors => [
12
+ "Invalid Request Format",
13
+ "param1 is not valid: Must be a String",
14
+ "param2 is not valid: Must be an Integer"
15
+ ],
16
+ :results => nil
17
+ }
18
+
19
+ get '/invalid_request', {}, @headers
20
+
21
+ expect(last_response.body).to eq(expected_body.to_json)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rest::Application do
4
+ before(:each) do
5
+ @expected_body = {
6
+ :errors => [],
7
+ :results => nil
8
+ }
9
+
10
+ @headers = { 'HTTP_AUTHORIZATION' => 'key1' }
11
+ end
12
+
13
+ describe :error_default_handler do
14
+ it "should create a error response based on the body" do
15
+ @expected_body[:errors] << "This is the default error handler"
16
+
17
+ get '/default_error_handeling', {}, @headers
18
+
19
+ expect(last_response.status).to eq(400)
20
+ expect(last_response.body).to eq(@expected_body.to_json)
21
+ end
22
+
23
+ it "should create a hashed error response based on the body" do
24
+ @expected_body[:errors] = { :error => "This is the hashed error handler" }
25
+
26
+ get '/hashed_error_handeling', {}, @headers
27
+
28
+ expect(last_response.status).to eq(400)
29
+ expect(last_response.body).to eq(@expected_body.to_json)
30
+ end
31
+ end
32
+
33
+ describe :error_404 do
34
+ it "should provide endpoint not found error" do
35
+ @expected_body[:errors] << "Endpoint not found"
36
+
37
+ get '/not_found', {}, @headers
38
+
39
+ expect(last_response.status).to eq(404)
40
+ expect(last_response.body).to eq(@expected_body.to_json)
41
+ end
42
+ end
43
+
44
+ describe :error_401 do
45
+ before (:each) do
46
+ @expected_body[:errors] << "Unauthorized Access"
47
+ end
48
+
49
+ it "should create an unauthorized error in json" do
50
+ get '/unauthorized', {}, @headers
51
+
52
+ expect(last_response.status).to eq(401)
53
+ expect(last_response.body).to eq(@expected_body.to_json)
54
+ end
55
+
56
+ it "shoud create an unauthorized error in xml" do
57
+ @headers['HTTP_ACCEPT'] = 'text/xml'
58
+ get '/unauthorized', {}, @headers
59
+
60
+ expect(last_response.status).to eq(401)
61
+ expect(last_response.body).to eq(@expected_body.to_xml(:root => :response))
62
+ end
63
+ end
64
+
65
+ describe :error_500 do
66
+ it "should create an array of errors with the error message in json when halted" do
67
+ @expected_body[:errors] << "Internal Error"
68
+
69
+ get '/internal_error', {}, @headers
70
+
71
+ expect(last_response.status).to eq(500)
72
+ expect(last_response.body).to eq(@expected_body.to_json)
73
+ end
74
+
75
+ it "should create an array of errors with the error message in xml when halted" do
76
+ @expected_body[:errors] << "Internal Error"
77
+
78
+ @headers['HTTP_ACCEPT'] = 'text/xml'
79
+ get '/internal_error', {}, @headers
80
+
81
+ expect(last_response.status).to eq(500)
82
+ expect(last_response.body).to eq(@expected_body.to_xml(:root => :response))
83
+ end
84
+
85
+ it "should create an array of errors with the error message in json when raised" do
86
+ @expected_body[:errors] << "Raised Internal Error"
87
+
88
+ get '/internal_error_raised', {}, @headers
89
+
90
+ expect(last_response.status).to eq(500)
91
+ expect(last_response.body).to eq(@expected_body.to_json)
92
+ end
93
+
94
+ it "should create an array of errors with the error message in xml when raised" do
95
+ @expected_body[:errors] << "Raised Internal Error"
96
+
97
+ @headers['HTTP_ACCEPT'] = 'text/xml'
98
+ get '/internal_error_raised', {}, @headers
99
+
100
+ expect(last_response.status).to eq(500)
101
+ expect(last_response.body).to eq(@expected_body.to_xml(:root => :response))
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,21 @@
1
+ require 'simplecov'
2
+ require 'rack/test'
3
+ require 'json'
4
+
5
+ SimpleCov.start do
6
+ add_filter '/spec/'
7
+ end
8
+
9
+ require 'rest'
10
+ Dir[File.dirname(__FILE__) + '/fixtures/**/*.rb'].each {|file| require file }
11
+
12
+ ENV['RACK_ENV'] = 'test'
13
+
14
+ module RSpecMixin
15
+ include Rack::Test::Methods
16
+ def app() Rest::Test::TestApplication end
17
+ end
18
+
19
+ RSpec.configure do |conf|
20
+ conf.include RSpecMixin
21
+ end
metadata ADDED
@@ -0,0 +1,220 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-rest-base
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - bmills
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.4'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thin
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: builder
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.6'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.6'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rack-test
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '0.8'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '0.8'
153
+ description: Base class for quickly setting up RESTful services through Sinatra.
154
+ email:
155
+ - brandon.mills@careerbuilder.com
156
+ executables: []
157
+ extensions: []
158
+ extra_rdoc_files: []
159
+ files:
160
+ - ".gitignore"
161
+ - Gemfile
162
+ - LICENSE.txt
163
+ - README.md
164
+ - Rakefile
165
+ - lib/rest.rb
166
+ - lib/rest/application.rb
167
+ - lib/rest/application_helper.rb
168
+ - lib/rest/authentication.rb
169
+ - lib/rest/authentication/authentication_base.rb
170
+ - lib/rest/authentication/basic_authentication.rb
171
+ - lib/rest/error_handeling.rb
172
+ - lib/rest/error_status_handeling.rb
173
+ - lib/rest/exceptions.rb
174
+ - lib/rest/exceptions/invalid_request.rb
175
+ - lib/rest/version.rb
176
+ - sinatra-rest-base.gemspec
177
+ - spec/fixtures/test_application.rb
178
+ - spec/fixtures/test_end_points.rb
179
+ - spec/fixtures/test_errors_end_points.rb
180
+ - spec/lib/rest/application_spec.rb
181
+ - spec/lib/rest/authentication/authentication_base_spec.rb
182
+ - spec/lib/rest/authentication/basic_authentication_spec.rb
183
+ - spec/lib/rest/error_handeling_spec.rb
184
+ - spec/lib/rest/error_status_handeling_spec.rb
185
+ - spec/spec_helper.rb
186
+ homepage: ''
187
+ licenses:
188
+ - MIT
189
+ metadata: {}
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubyforge_project:
206
+ rubygems_version: 2.4.4
207
+ signing_key:
208
+ specification_version: 4
209
+ summary: Base class for quickly setting up RESTful services through Sinatra.
210
+ test_files:
211
+ - spec/fixtures/test_application.rb
212
+ - spec/fixtures/test_end_points.rb
213
+ - spec/fixtures/test_errors_end_points.rb
214
+ - spec/lib/rest/application_spec.rb
215
+ - spec/lib/rest/authentication/authentication_base_spec.rb
216
+ - spec/lib/rest/authentication/basic_authentication_spec.rb
217
+ - spec/lib/rest/error_handeling_spec.rb
218
+ - spec/lib/rest/error_status_handeling_spec.rb
219
+ - spec/spec_helper.rb
220
+ has_rdoc: