strutta-api 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2d72692a864ae1a19c3bf8761741a79dd505d751
4
+ data.tar.gz: b0989b6d0d993f3396d2d7f2d59791dd267d5b63
5
+ SHA512:
6
+ metadata.gz: bac95bc6eaa7f7a19a7d2824ccd2a4a1602b9369b2b5a65fadc64700a6a335b982ce3be9a4cc5ea58936c32588ccb033d386d5579ed8eb9784b04f85d204dec1
7
+ data.tar.gz: a863c2ec69241f28e429bd3a0279ca3e0aeb03ffd18ada8c7a7b4992af8bf1b43f1b97478098bad2243e27525612d0dfcb04c7821b33711df90d50258d6888e9
@@ -0,0 +1,18 @@
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
+ .rubocop.yml
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in strutta-api.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 BlakeTurner
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.
@@ -0,0 +1,55 @@
1
+ [![Code Climate](https://codeclimate.com/repos/53d81d1de30ba01f16012d2a/badges/5a6842ba6fe26d49d83b/gpa.png)](https://codeclimate.com/repos/53d81d1de30ba01f16012d2a/feed)
2
+ [![Test Coverage](https://codeclimate.com/repos/53d81d1de30ba01f16012d2a/badges/5a6842ba6fe26d49d83b/coverage.png)](https://codeclimate.com/repos/53d81d1de30ba01f16012d2a/feed)
3
+
4
+ # Strutta::Api
5
+
6
+ Official wrapper for the Strutta API
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ gem 'strutta-api'
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install strutta-api
21
+
22
+ ## Usage
23
+
24
+ This Gem is designed to have is calls resemble actual API URIs.
25
+
26
+ For example, if we want to get Rounds in Game 333, we would GET the following URI:
27
+
28
+ ```
29
+ http://api.strutta.com/v2/games/333/rounds
30
+ ```
31
+
32
+ The Gem copies this pattern:
33
+
34
+ ```
35
+ # Initialize
36
+ strutta = Strutta::API.new 'mystruttatoken'
37
+
38
+ # Get Rounds in Game 333
39
+ strutta.games(333).rounds.get
40
+ ```
41
+
42
+ There are detailed examples for each endpoint found in the Strutta API docs.
43
+
44
+ ## Errors
45
+
46
+ This Gem Raises exceptions whenever anything other than a `200`, `201` or `204` is returned.
47
+ The errors are defined in lib/strutta/api/errors and generated Strutta::Api#error_map.
48
+
49
+ ## Contributing
50
+
51
+ 1. Fork it ( http://github.com/<my-github-username>/strutta-api/fork )
52
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
53
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
54
+ 4. Push to the branch (`git push origin my-new-feature`)
55
+ 5. Create new Pull Request
@@ -0,0 +1,7 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task default: :spec
7
+ task test: :spec
@@ -0,0 +1,109 @@
1
+ require 'excon'
2
+ require 'json'
3
+
4
+ require 'strutta-api/api_object.rb'
5
+ require 'strutta-api/entries.rb'
6
+ require 'strutta-api/errors.rb'
7
+ require 'strutta-api/flow.rb'
8
+ require 'strutta-api/games.rb'
9
+ require 'strutta-api/participants.rb'
10
+ require 'strutta-api/points.rb'
11
+ require 'strutta-api/moderation.rb'
12
+ require 'strutta-api/judging.rb'
13
+ require 'strutta-api/rounds.rb'
14
+ require 'strutta-api/version.rb'
15
+
16
+ module Strutta
17
+ # Strutta API engine
18
+ # Handles API requests and errors
19
+ class API
20
+ include Strutta::Version
21
+ attr_accessor :host, :path, :token, :debug, :session
22
+
23
+ # Initializes the Strutta API wrapper
24
+ #
25
+ # @param token [String] your Strutta API token
26
+ # @param host [String] Strutta API host URL - used to switched between prod/staging
27
+ # @param path [String] Strutta API host path - used to switched between versions
28
+ # @return [Strutta::API] instantiated Strutta API object
29
+ def initialize(token, host = 'http://strutta-api.herokuapp.com/', path = Version::VERSION_PATH)
30
+ fail Error, 'You must provide a Strutta API key' unless token
31
+
32
+ @host = host
33
+ @path = path
34
+ @token = token
35
+ @session = Excon.new @host
36
+ @debug = debug
37
+ end
38
+
39
+ # Makes an API call
40
+ #
41
+ # @param method [String] the required HTTP method
42
+ # @param url [String] URL for the call
43
+ # @param params [Hash] Parameters for the call
44
+ # @return [Hash] Parsed body of the response
45
+ def call(method, url, params = {})
46
+ params = JSON.generate(params)
47
+ r = @session.send(method, path: "#{@path}#{url}", headers: api_headers, body: params)
48
+
49
+ # Delete calls have no JSON return
50
+ return true if r.status == 204
51
+
52
+ # Raise exceptions on error response codes
53
+ cast_error(r.status, r.body) if r.status >= 400
54
+
55
+ JSON.parse(r.body)
56
+ end
57
+
58
+ # Instantiates a Strutta::Games object
59
+ #
60
+ # @param id [Integer, nil] the ID of the Strutta game
61
+ # @return [Strutta::Games] The instantiated Strutta::Games object
62
+ def games(id = nil)
63
+ Games.new id, self
64
+ end
65
+
66
+ private
67
+
68
+ # Utility: build the Headers hash
69
+ # @return [Hash] Headers for an API call
70
+ def api_headers
71
+ {
72
+ 'Content-Type' => 'application/json',
73
+ 'Authorization' => "Token token=#{@token}"
74
+ }
75
+ end
76
+
77
+ # Throws exceptions based on HTTP responses
78
+ #
79
+ # @param status [Integer] the HTTP response status
80
+ # @param body [JSON] the HTTP response body
81
+ # @return [Error] An appropriate exception
82
+ def cast_error(status, body)
83
+ error_info = JSON.parse(body)
84
+ msg = error_info['error'] && error_info['message'] ? "#{error_info['error']} - #{error_info['message']}" : "We received an unexpected error: #{body}"
85
+ fail error_map(status), msg
86
+ rescue JSON::ParserError
87
+ raise Errors::Error, "We received an unexpected error: #{body}"
88
+ end
89
+
90
+ # Map errors to HTTP statuses
91
+ #
92
+ # @param status [Integer] the HTTP response status
93
+ # @return [Error] The associated exception
94
+ def error_map(status)
95
+ case status
96
+ when 401
97
+ Errors::Unauthorized
98
+ when 400
99
+ Errors::BadRequestError
100
+ when 404
101
+ Errors::ObjectNotFoundError
102
+ when 422
103
+ Errors::UnprocessableEntityError
104
+ else
105
+ Errors::Error
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,58 @@
1
+ # Strutta Container
2
+ module Strutta
3
+ # @abstract
4
+ # APIObject contains all the HTTP request methods
5
+ class APIObject
6
+ attr_accessor :game
7
+
8
+ # GET index request
9
+ # (Uses instance vars of child object to generate resource path)
10
+ #
11
+ # @return [Hash] Parsed body of the API response
12
+ def all(params = {})
13
+ @game.verify_no_id(@id)
14
+ @game.all(params, "#{@game.id}/#{@root_path}")
15
+ end
16
+
17
+ # POST request
18
+ # (Uses instance vars of child object to generate resource path)
19
+ #
20
+ # @return [Hash] Parsed body of the API response
21
+ def create(params = {})
22
+ @game.verify_no_id(@id)
23
+ @game.create(params, "#{@game.id}/#{@root_path}")
24
+ end
25
+
26
+ # GET request
27
+ # (Uses instance vars of child object to generate resource path)
28
+ #
29
+ # @return [Hash] Parsed body of the API response
30
+ def get(params = {})
31
+ @game.verify_id(@id, Errors::ROUND_ID_REQUIRED)
32
+ @game.get(params, @root_path)
33
+ end
34
+
35
+ # PATCH request
36
+ # (Uses instance vars of child object to generate resource path)
37
+ #
38
+ # @return [Hash] Parsed body of the API response
39
+ def update(params = {})
40
+ @game.verify_id(@id, Errors::ROUND_ID_REQUIRED)
41
+ @game.update(params, @root_path)
42
+ end
43
+
44
+ # DELETE request
45
+ # (Uses instance vars of child object to generate resource path)
46
+ #
47
+ # @return [Hash] Parsed body of the API response
48
+ def delete
49
+ @game.verify_id(@id, Errors::ROUND_ID_REQUIRED)
50
+ @game.delete(@root_path)
51
+ end
52
+
53
+ # Manually disable a method in child classed
54
+ def method_disabled(*_)
55
+ fail Errors::DisabledEndpointError, Errors::METHOD_DISABLED
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,35 @@
1
+ module Strutta
2
+ # Entries belong to a Strutta::Games object
3
+ # Instance methods found in Strutta::APIObject
4
+ class Entries < APIObject
5
+ # Initializes the Strutta::Entries object
6
+ #
7
+ # @param id [Integer, nil] Entry id
8
+ # @param game [Strutta::Games] Master Strutta::Games object
9
+ # @return [Strutta::Entries] instantiated Strutta::Entries object
10
+ def initialize(id = nil, game)
11
+ @id = id
12
+ @game = game
13
+ @root_path = "entries/#{@id}"
14
+ @no_id_error = Errors::ENTRY_ID_REQUIRED
15
+ end
16
+
17
+ # GET transition history for Entry (no ID required)
18
+ # games/:game_id/entries/:id/transitions
19
+ #
20
+ # @return [Hash] Parsed body of the API response
21
+ def transitions(params = {})
22
+ @game.verify_id(@id, Errors::ENTRY_ID_REQUIRED)
23
+ @game.get(params, "entries/#{@id}/transitions")
24
+ end
25
+
26
+ # GET leaderboard history for Entries in Points Rounds (no ID required)
27
+ # games/:game_id/entries/leaderboard
28
+ #
29
+ # @return [Hash] Parsed body of the API response
30
+ def leaderboard(params = {})
31
+ @game.verify_no_id(@id)
32
+ @game.get(params, 'entries/leaderboard')
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,47 @@
1
+ module Strutta
2
+ # Strutta Wrapper Errors
3
+ module Errors
4
+ # Game ID is required for .get, .update, .delete
5
+ GAME_ID_REQUIRED = 'Game ID required'
6
+ # Round ID is required for .get, .update, .delete
7
+ ROUND_ID_REQUIRED = 'Round ID required'
8
+ # Participant ID is required for .get, .update, .delete
9
+ PARTICIPANT_ID_REQUIRED = 'Participant ID required'
10
+ # Entry ID is required for .get, .update, .delete
11
+ ENTRY_ID_REQUIRED = 'Entry ID required'
12
+ # ID is not allowed for some methods
13
+ OBJECT_NOT_ALLOWED = 'This method may not have an ID associated with it. Example: strutta.games.entries.all instead of strutta.games.entries(ENTRY_ID).all'
14
+ # ID is not allowed for some methods
15
+ INVALID_SEARCH = 'This version of the API only support searching by email'
16
+ # Some http verbs are disabled for object, tell the user nicely
17
+ METHOD_DISABLED = 'This method is disabled for this object type'
18
+
19
+ # Generic Errors
20
+ class Error < StandardError
21
+ end
22
+ # 400 Errors
23
+ class BadRequestError < Error
24
+ end
25
+ # 401 Errors
26
+ class Unauthorized < Error
27
+ end
28
+ # 404 Errors
29
+ class ObjectNotFoundError < Error
30
+ end
31
+ # 422 Errors
32
+ class UnprocessableEntityError < Error
33
+ end
34
+ # .get, .update, .delete requests require an object ID
35
+ class ObjectIDRequired < Error
36
+ end
37
+ # .all, .create do not allow an abject ID
38
+ class ObjectIDNotAllowed < Error
39
+ end
40
+ # Enforce searching only by email
41
+ class InvalidSearchParameters < Error
42
+ end
43
+ # Enforce disabled endpoints
44
+ class DisabledEndpointError < Error
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,35 @@
1
+ module Strutta
2
+ # Flow belongs to a Strutta::Games object
3
+ # Other Instance methods found in Strutta::APIObject
4
+ class Flow < APIObject
5
+ # Initializes the Strutta::Flow object
6
+ #
7
+ # @param game [Strutta::Games] Master Strutta::Games object
8
+ # @return [Strutta::Flow] instantiated Strutta::Flow object
9
+ def initialize(id = nil, game)
10
+ @id = id
11
+ @game = game
12
+ @root_path = 'flow'
13
+ end
14
+
15
+ # GET request for Flow (no ID required)
16
+ #
17
+ # @return [Hash] Parsed body of the API response
18
+ def get
19
+ @game.verify_no_id(@id)
20
+ @game.get({}, @root_path)
21
+ end
22
+
23
+ # DELETE request for Flow (no ID required)
24
+ #
25
+ # @return [Hash] Parsed body of the API response
26
+ def delete
27
+ @game.verify_no_id(@id)
28
+ @game.delete(@root_path)
29
+ end
30
+
31
+ # Disbled methods
32
+ alias_method :update, :method_disabled
33
+ alias_method :all, :method_disabled
34
+ end
35
+ end
@@ -0,0 +1,159 @@
1
+ module Strutta
2
+ # The Strutta Games object is the master of all other API objects (Rounds, Flow, Entries, Participants)
3
+ # The above objects are instantiated in association with a Games object, as each belong to a Game in the Strutta API
4
+ # The above objects also have all their API requests forwarded through this object to Strutta::API
5
+ class Games
6
+ attr_accessor :master, :id
7
+
8
+ # Initializes the Strutta::Games object
9
+ #
10
+ # @param id [Integer, nil] Game id
11
+ # @param master [Strutta::API] Master Strutta::API object
12
+ # @return [Strutta::Games] instantiated Strutta::Games object
13
+ def initialize(id = nil, master)
14
+ @id = id
15
+ @root_path = 'games'
16
+ @master = master
17
+ end
18
+
19
+ # Forwards an API call to @master
20
+ #
21
+ # @param method [String] the required HTTP method
22
+ # @param url [String] URL for the call
23
+ # @param params [Hash] Parameters for the call
24
+ # @return [Hash] Parsed body of the response
25
+ def call(method, url, params = {})
26
+ @master.call(method, url, params)
27
+ end
28
+
29
+ # Polymorphic GET Index request
30
+ #
31
+ # @param resource_path [String, nil] the GET index path for the requesting object
32
+ # See Strutta::APIObject#all
33
+ # @return [Hash] Parsed body of the response
34
+ def all(params = {}, resource_path = nil)
35
+ verify_no_id(@id) unless resource_path
36
+ call('get', "#{@root_path}/#{resource_path}", params)
37
+ end
38
+
39
+ # Polymorphic GET single object request
40
+ #
41
+ # @param resource_path [String, nil] the GET path for the requesting object
42
+ # See Strutta::APIObject#get
43
+ # @return [Hash] Parsed body of the response
44
+ def get(params = {}, resource_path = '')
45
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
46
+ call('get', "#{@root_path}/#{@id}/#{resource_path}", params)
47
+ end
48
+
49
+ # Polymorphic POST request
50
+ #
51
+ # @param resource_path [String, nil] the POST path for the requesting object
52
+ # See Strutta::APIObject#create
53
+ # @return [Hash] Parsed body of the response
54
+ def create(params = {}, resource_path = nil)
55
+ verify_no_id(@id) unless resource_path
56
+ call('post', "#{@root_path}/#{resource_path}", params)
57
+ end
58
+
59
+ # Polymorphic PATCH request
60
+ #
61
+ # @param resource_path [String, nil] the PATCH path for the requesting object
62
+ # See Strutta::APIObject#update
63
+ # @return [Hash] Parsed body of the response
64
+ def update(params, resource_path = nil)
65
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
66
+ call('patch', "#{@root_path}/#{@id}/#{resource_path}", params)
67
+ end
68
+
69
+ # Polymorphic DELETE request
70
+ #
71
+ # @param resource_path [String, nil] the DELETE path for the requesting object
72
+ # See Strutta::APIObject#delete
73
+ # @return [Hash] Parsed body of the response
74
+ def delete(resource_path = nil)
75
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
76
+ call('delete', "#{@root_path}/#{@id}/#{resource_path}", {})
77
+ end
78
+
79
+ # Instantiates a Strutta::Rounds object with reference to this Game
80
+ #
81
+ # @param id [Integer, nil] the ID of the Round
82
+ # @return [Strutta::Rounds] The instantiated Strutta::Rounds object
83
+ def rounds(id = nil)
84
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
85
+ Rounds.new id, self
86
+ end
87
+
88
+ # Instantiates a Strutta::Participants object with reference to this Game
89
+ #
90
+ # @param id [Integer, nil] the ID of the Participant
91
+ # @return [Strutta::Participants] The instantiated Strutta::Participants object
92
+ def participants(id = nil)
93
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
94
+ Participants.new id, self
95
+ end
96
+
97
+ # Instantiates a Strutta::Flow object with reference to this Game
98
+ #
99
+ # @param id [Integer, nil] Flows do not have Ids. This is here simply for consistency, and will result in error of used.
100
+ # @return [Strutta::Flow] The instantiated Strutta::Flow object
101
+ def flow(id = nil)
102
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
103
+ Flow.new id, self
104
+ end
105
+
106
+ # Instantiates a Strutta::Entries object with reference to this Game
107
+ #
108
+ # @param id [Integer, nil] the ID of the Entry
109
+ # @return [Strutta::Entries] The instantiated Strutta::Entries object
110
+ def entries(id = nil)
111
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
112
+ Entries.new id, self
113
+ end
114
+
115
+ # Instantiates a Strutta::Points object with reference to this Game
116
+ #
117
+ # @param id [Integer, nil] Point IDs are not used by this API. This is here simply for consistency, and will result in error of used.
118
+ # @return [Strutta::Entries] The instantiated Strutta::Points object
119
+ def points(id = nil)
120
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
121
+ Points.new id, self
122
+ end
123
+
124
+ # Instantiates a Strutta::Moderation object with reference to this Game
125
+ #
126
+ # @param id [Integer, nil] Moderation do not have Ids. This is here simply for consistency, and will result in error of used.
127
+ # @return [Strutta::Entries] The instantiated Strutta::Moderation object
128
+ def moderation(id = nil)
129
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
130
+ Moderation.new id, self
131
+ end
132
+
133
+ # Instantiates a Strutta::Judging object with reference to this Game
134
+ #
135
+ # @param id [Integer, nil] Judging does not have Ids. This is here simply for consistency, and will result in error of used.
136
+ # @return [Strutta::Entries] The instantiated Strutta::Judging object
137
+ def judging(id = nil)
138
+ verify_id(@id, Errors::GAME_ID_REQUIRED)
139
+ Judging.new id, self
140
+ end
141
+
142
+ # Confirm that an id exists for a request
143
+ #
144
+ # @param id [Integer] the ID of the objec
145
+ # @param message [String] Error message if no id exists
146
+ # @return [nil] nil if id exists, Error otherwise
147
+ def verify_id(id, message)
148
+ fail Errors::ObjectIDRequired, message unless id
149
+ end
150
+
151
+ # Confirm that no id exists for a request
152
+ #
153
+ # @param id [Integer] the ID of the objec
154
+ # @return [nil] nil if no id exists, Error otherwise
155
+ def verify_no_id(id)
156
+ fail Errors::ObjectIDNotAllowed, Errors::OBJECT_NOT_ALLOWED if id
157
+ end
158
+ end
159
+ end