spark_api 1.0.1 → 1.0.2

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.
data/README.md CHANGED
@@ -15,6 +15,49 @@ Installation
15
15
  Usage Examples
16
16
  ------------------------
17
17
 
18
+ #### Ruby Script: OAuth 2
19
+ # initialize the gem with your OAuth 2 key/secret.
20
+ # See also: script/oauth2_example.rb
21
+ # api_key, api_secret, and callback are all required.
22
+ # The following options are required:
23
+ # - api_key: Your OAuth 2 client key
24
+ # - api-secret: Your OAuth 2 client secret
25
+ # - callback: Your OAuth 2 redirect_uri, which the end user will be redirected
26
+ # to after authorizing your application to access their data.
27
+ # - auth_endpoint: The URI to redirect the user's web browser to, in order for them to
28
+ # authorize your application to access their data.
29
+ # other options and their defaults:
30
+ # - endpoint: 'https://api.sparkapi.com'
31
+ # - version: 'v1'
32
+ # - ssl: true
33
+ # - user_agent: 'Spark API Ruby Gem'
34
+ SparkApi.configure do |config|
35
+ config.authentication_mode = SparkApi::Authentication::OAuth2
36
+ config.api_key = "YOUR_CLIENT_ID"
37
+ config.api_secret = "YOUR_CLIENT_SECRET"
38
+ config.callback = "YOUR_REDIRECT_URI"
39
+ config.auth_endpoint = "https://developers.sparkplatform.com/oauth2"
40
+ config.endpoint = 'https://developers.sparkapi.com'
41
+ end
42
+
43
+ # Code is retrieved from the method. client.authenticator.authorization_url
44
+ # See script/oauth2_example.rb for more details.
45
+
46
+
47
+ SparkApi.client.oauth2_provider.code = "CODE_FROM_ABOVE_URI"
48
+ SparkApi.client.authenticate
49
+
50
+ # Alternatively, if you've already received an access token, you may
51
+ # do the following instead of the above two lines:
52
+ #SparkApi.client.session = SparkApi::Authentication::OAuthSession.new "access_token"=> "ACCESS_TOKEN",
53
+ # "refresh_token" => "REFRESH_TOKEN", "expires_in" => 86400
54
+
55
+ # mixin the models so you can use them without prefix
56
+ include SparkApi::Models
57
+
58
+ # Grab your listings!
59
+ my_listings = Listing.my()
60
+
18
61
  #### Ruby Script
19
62
  # initialize the gem with your key/secret
20
63
  # api_key and _api_secret are the only required settings
@@ -62,8 +105,10 @@ Authentication is handled transparently by the request framework in the gem, so
62
105
  #### API Authentication (Default)
63
106
  Usually supplied for a single user, this authentication mode is the simplest, and is setup as the default. The example usage above demonstrates how to get started using this authentication mode.
64
107
 
65
- #### OAuth2 Authentication
66
- Authentication mode the separates application and user authentication. This mode requires further setup which is described in _lib/spark_api/authentication/oauth2.rb_
108
+ #### OAuth2 Authorization (Preferred)
109
+ Authorization mode the separates application and user authentication. This mode requires the end user to be redirected to Spark Platform's auth endpoint. See "script/oauth2_example.rb" for an example.
110
+
111
+ Read more about Spark Platform's OAuth 2 flow <a href="http://sparkplatform.com/docs/authentication/oauth2_authentication">here</a>.
67
112
 
68
113
  Error Codes
69
114
  ---------------------
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.1
1
+ 1.0.2
@@ -182,6 +182,7 @@ module SparkApi
182
182
  require 'spark_api/authentication/oauth2_impl/grant_type_code'
183
183
  require 'spark_api/authentication/oauth2_impl/grant_type_password'
184
184
  require 'spark_api/authentication/oauth2_impl/password_provider'
185
+ require 'spark_api/authentication/oauth2_impl/simple_provider'
185
186
 
186
187
  # Loads a provider class from a string
187
188
  def self.load_provider(string, args={})
@@ -0,0 +1,22 @@
1
+ module SparkApi
2
+ module Authentication
3
+ class SimpleProvider < BaseOAuth2Provider
4
+ def initialize(credentials)
5
+ super(credentials)
6
+ @grant_type = :authorization_code
7
+ end
8
+
9
+ def load_session
10
+ @session
11
+ end
12
+
13
+ def save_session session
14
+ @session = session
15
+ end
16
+
17
+ def destroy_session
18
+ @session = nil
19
+ end
20
+ end
21
+ end
22
+ end
@@ -7,6 +7,9 @@ module SparkApi
7
7
  include Connection
8
8
  include Authentication
9
9
  include Request
10
+
11
+ require File.expand_path('../configuration/oauth2_configurable', __FILE__)
12
+ include Configuration::OAuth2Configurable
10
13
 
11
14
  attr_accessor :authenticator
12
15
  attr_accessor *Configuration::VALID_OPTION_KEYS
@@ -0,0 +1,30 @@
1
+ module SparkApi
2
+ module Configuration
3
+ module OAuth2Configurable
4
+ def convert_to_oauth2?
5
+ self.authentication_mode == SparkApi::Authentication::OAuth2 &&
6
+ self.oauth2_provider.nil?
7
+ end
8
+
9
+ def oauth2_enabled?
10
+ self.authentication_mode == SparkApi::Authentication::OAuth2
11
+ end
12
+
13
+ def oauthify!
14
+ self.oauth2_provider = SparkApi::Authentication::SimpleProvider.new(
15
+ :access_uri => grant_uri,
16
+ :client_id => self.api_key,
17
+ :client_secret => self.api_secret,
18
+ :authorization_uri => self.auth_endpoint,
19
+ :redirect_uri => self.callback
20
+ )
21
+ end
22
+
23
+ def grant_uri
24
+ e = self.endpoint.gsub(/\/+$/,"")
25
+ v = self.version.gsub(/\/+/,"/")
26
+ "#{e}/#{v}/oauth2/grant"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -2,7 +2,9 @@ module SparkApi
2
2
  module Configuration
3
3
 
4
4
  # valid configuration options
5
- VALID_OPTION_KEYS = [:api_key, :api_secret, :api_user, :endpoint, :user_agent, :version, :ssl, :oauth2_provider, :authentication_mode].freeze
5
+ VALID_OPTION_KEYS = [:api_key, :api_secret, :api_user, :endpoint,
6
+ :user_agent, :version, :ssl, :oauth2_provider, :authentication_mode,
7
+ :auth_endpoint, :callback].freeze
6
8
  OAUTH2_KEYS = [:authorization_uri, :access_uri, :client_id, :client_secret,
7
9
  # Requirements for authorization_code grant type
8
10
  :redirect_uri,
@@ -11,11 +13,15 @@ module SparkApi
11
13
  ]
12
14
 
13
15
  require File.expand_path('../configuration/yaml', __FILE__)
16
+ require File.expand_path('../configuration/oauth2_configurable', __FILE__)
17
+
18
+ include OAuth2Configurable
14
19
 
15
20
  DEFAULT_API_KEY = nil
16
21
  DEFAULT_API_SECRET = nil
17
22
  DEFAULT_API_USER = nil
18
23
  DEFAULT_ENDPOINT = 'https://api.sparkapi.com'
24
+ DEFAULT_AUTH_ENDPOINT = 'https://sparkplatform.com/openid' # Ignored for Spark API Auth
19
25
  DEFAULT_VERSION = 'v1'
20
26
  DEFAULT_USER_AGENT = "Spark API Ruby Gem #{VERSION}"
21
27
  DEFAULT_SSL = true
@@ -25,7 +31,8 @@ module SparkApi
25
31
 
26
32
  attr_accessor *VALID_OPTION_KEYS
27
33
  def configure
28
- yield self
34
+ yield(self)
35
+ oauthify! if convert_to_oauth2?
29
36
  end
30
37
 
31
38
  def self.extended(base)
@@ -43,6 +50,7 @@ module SparkApi
43
50
  self.api_secret = DEFAULT_API_SECRET
44
51
  self.api_user = DEFAULT_API_USER
45
52
  self.authentication_mode = SparkApi::Authentication::ApiAuth
53
+ self.auth_endpoint = DEFAULT_AUTH_ENDPOINT
46
54
  self.endpoint = DEFAULT_ENDPOINT
47
55
  self.oauth2_provider = DEFAULT_OAUTH2
48
56
  self.user_agent = DEFAULT_USER_AGENT
@@ -2,7 +2,7 @@ module SparkApi
2
2
  module Models
3
3
  class Listing < Base
4
4
  extend Finders
5
- attr_accessor :photos, :videos, :virtual_tours, :documents
5
+ attr_accessor :photos, :videos, :virtual_tours, :documents, :open_houses, :tour_of_homes
6
6
  attr_accessor :constraints
7
7
  self.element_name="listings"
8
8
  DATA_MASK = "********"
@@ -14,9 +14,10 @@ module SparkApi
14
14
  @virtual_tours = []
15
15
  @documents = []
16
16
  @constraints = []
17
+ #@tour_of_homes = []
17
18
 
18
19
  if attributes.has_key?('StandardFields')
19
- pics, vids, tours, docs = attributes['StandardFields'].values_at('Photos','Videos', 'VirtualTours', 'Documents')
20
+ pics, vids, tours, docs, ohouses, tourhomes = attributes['StandardFields'].values_at('Photos','Videos', 'VirtualTours', 'Documents', 'OpenHouses', 'TourOfHomes')
20
21
  end
21
22
 
22
23
  if pics != nil
@@ -39,6 +40,18 @@ module SparkApi
39
40
  attributes['StandardFields'].delete('Documents')
40
41
  end
41
42
 
43
+ if ohouses != nil
44
+ @open_houses = []
45
+ ohouses.collect { |ohouse| @open_houses.push(OpenHouse.new(ohouse)) }
46
+ attributes['StandardFields'].delete('OpenHouses')
47
+ end
48
+
49
+ if tourhomes != nil
50
+ @tour_of_homes = []
51
+ tourhomes.collect { |tourhome| @tour_of_homes.push(TourOfHome.new(tourhome)) }
52
+ attributes['StandardFields'].delete('TourOfHomes')
53
+ end
54
+
42
55
  super(attributes)
43
56
  end
44
57
 
@@ -60,18 +73,18 @@ module SparkApi
60
73
  end
61
74
 
62
75
  def self.nearby(latitude, longitude, arguments={})
63
- nearby_args = {:Lat => latitude, :Lon => longitude}.merge(arguments)
76
+ nearby_args = {:_lat => latitude, :_lon => longitude}.merge(arguments)
64
77
  collect(connection.get("/listings/nearby", nearby_args))
65
78
  end
66
79
 
67
80
  def tour_of_homes(arguments={})
81
+ @tour_of_homes ||= TourOfHome.find_by_listing_key(self.Id, arguments)
68
82
  return @tour_of_homes unless @tour_of_homes.nil?
69
- @tour_of_homes = TourOfHome.find_by_listing_key(self.Id, arguments)
70
83
  end
71
84
 
72
85
  def open_houses(arguments={})
86
+ @open_houses ||= OpenHouse.find_by_listing_key(self.Id, arguments)
73
87
  return @open_houses unless @open_houses.nil?
74
- @open_houses = OpenHouse.find_by_listing_key(self.Id, arguments)
75
88
  end
76
89
 
77
90
  def my_notes
@@ -16,6 +16,11 @@ module SparkApi
16
16
  attributes['StartTime'] = Time.parse("#{date}T#{attributes['StartTime']}") unless attributes['StartTime'].nil?
17
17
  attributes['EndTime'] = Time.parse("#{date}T#{attributes['EndTime']}") unless attributes['EndTime'].nil?
18
18
  end
19
+
20
+ if attributes["Comments"].nil?
21
+ attributes["Comments"] = ""
22
+ end
23
+
19
24
  super(attributes)
20
25
  end
21
26
 
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ require "rubygems"
3
+
4
+ Bundler.require(:default, "development") if defined?(Bundler)
5
+
6
+ path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
7
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
8
+ require path + '/spark_api'
9
+
10
+ SparkApi.logger.info("Hello!")
11
+
12
+ SparkApi.configure do |config|
13
+ config.authentication_mode = SparkApi::Authentication::OAuth2
14
+ config.api_key = "YOUR_CLIENT_ID"
15
+ config.api_secret = "YOUR_CLIENT_SECRET"
16
+ config.callback = "YOUR_REDIRECT_URI"
17
+ config.version = "v1"
18
+ config.endpoint = "https://developers.sparkapi.com"
19
+ config.auth_endpoint = "https://developers.sparkplatform.com/oauth2"
20
+ end
21
+
22
+ client = SparkApi.client
23
+
24
+
25
+ # Step 1:
26
+ # To get your code to post to /v1/oauth2/grant, send the end user to this URI, replacing the all-capped strings with
27
+ # the CGI-escaped credentials for your key:
28
+ # https://developers.sparkplatform.com/oauth2?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI
29
+ # When the user has finished, they will land at:
30
+ # YOUR_REDIRECT_URI?code=CODE.
31
+ puts "Go here and log in to get your code: #{client.authenticator.authorization_url}"
32
+
33
+ # Step 2: Uncomment the following, and add your code in place of CODE_FROM_ABOVE_URI
34
+ # Hold on to the tokens. Unless you lose them, you can now pass in these
35
+ # values until the access_token expires.
36
+ #client.oauth2_provider.code = "CODE_FROM_ABOVE_URI"
37
+ #client.authenticate
38
+ #puts "Access Token: #{client.session.access_token}, Refresh Token: #{client.session.refresh_token}"
39
+
40
+
41
+ # Step 4: Comment out Step 3, and uncomment the following.
42
+ # Pass in your access_token and refresh_token to make authenticated requests to the API
43
+ #client.session = SparkApi::Authentication::OAuthSession.new "access_token"=> "ACCESS_TOKEN",
44
+ # "refresh_token" => "REFRESH_TOKEN", "expires_in" => 86400
45
+
46
+
47
+ # Step 3a and 4a: Uncomment with Step 3 and 4.
48
+ # Make requests for authorized listing data
49
+ #list = client.get '/contacts'
50
+ #puts "client: #{list.inspect}"
51
+ #list = SparkApi::Models::Contact.get
52
+ #puts "model: #{list.inspect}"
53
+
54
+
55
+
56
+
@@ -10,6 +10,7 @@ describe SparkApi::Client, "Client config" do
10
10
  SparkApi.api_key.should be_nil
11
11
  SparkApi.api_secret.should be_nil
12
12
  SparkApi.version.should match("v1")
13
+ SparkApi.auth_endpoint.should match("sparkplatform.com/openid")
13
14
  SparkApi.endpoint.should match("api.sparkapi.com")
14
15
  SparkApi.user_agent.should match(/Spark API Ruby Gem .*/)
15
16
  SparkApi.api_key = "my_api_key"
@@ -20,18 +21,53 @@ describe SparkApi::Client, "Client config" do
20
21
  describe "instance config" do
21
22
  it "should return a properly configured client" do
22
23
  client = SparkApi::Client.new(:api_key => "key_of_wade",
23
- :api_secret => "TopSecret",
24
- :api_user => "1234",
25
- :endpoint => "http://api.wade.dev.fbsdata.com")
24
+ :api_secret => "TopSecret",
25
+ :api_user => "1234",
26
+ :auth_endpoint => "https://login.wade.dev.fbsdata.com",
27
+ :endpoint => "http://api.wade.dev.fbsdata.com")
26
28
 
27
29
  client.api_key.should match("key_of_wade")
28
30
  client.api_secret.should match("TopSecret")
29
31
  client.api_user.should match("1234")
32
+ client.auth_endpoint.should match("https://login.wade.dev.fbsdata.com")
30
33
  client.endpoint.should match("http://api.wade.dev.fbsdata.com")
31
34
  client.version.should match("v1")
32
35
  end
33
36
  end
34
37
 
38
+ describe "oauth2 instance configuration" do
39
+ let(:oauth2_client) do
40
+ SparkApi::Client.new(:api_key => "key_of_wade",
41
+ :api_secret => "TopSecret",
42
+ :callback => "http://wade.dev.fbsdata.com/callback",
43
+ :auth_endpoint => "https://login.wade.dev.fbsdata.com",
44
+ :endpoint => "http://api.wade.dev.fbsdata.com",
45
+ :authentication_mode => SparkApi::Authentication::OAuth2)
46
+ end
47
+
48
+ it "should convert the configuration to oauth2 when specified" do
49
+ oauth2_client.oauthify!
50
+ oauth2_client.oauth2_provider.should be_a(SparkApi::Authentication::SimpleProvider)
51
+ end
52
+
53
+ it "should say oauth2_enabled? when it is" do
54
+ oauth2_client.oauth2_enabled?().should be_true
55
+ end
56
+
57
+ it "should say oauth2_enabled? is false" do
58
+ client = SparkApi::Client.new(:api_key => "key_of_wade",
59
+ :api_secret => "TopSecret",
60
+ :callback => "http://wade.dev.fbsdata.com/callback",
61
+ :auth_endpoint => "https://login.wade.dev.fbsdata.com",
62
+ :endpoint => "http://api.wade.dev.fbsdata.com")
63
+ client.oauth2_enabled?().should be_false
64
+ end
65
+
66
+ it "should properly build a grant_uri from the endpoint" do
67
+ oauth2_client.grant_uri.should eq("http://api.wade.dev.fbsdata.com/v1/oauth2/grant")
68
+ end
69
+ end
70
+
35
71
  describe "block config" do
36
72
  it "should correctly set up the client" do
37
73
  SparkApi.configure do |config|
@@ -49,7 +85,20 @@ describe SparkApi::Client, "Client config" do
49
85
  SparkApi.version.should match("veleventy")
50
86
  SparkApi.endpoint.should match("test.api.sparkapi.com")
51
87
  SparkApi.user_agent.should match("my useragent")
88
+ SparkApi.oauth2_enabled?().should be_false
89
+ end
52
90
 
91
+ it "should correctly set up the client for oauth2" do
92
+ SparkApi.configure do |config|
93
+ config.api_key = "my_key"
94
+ config.api_secret = "my_secret"
95
+ config.callback = "http://wade.dev.fbsdata.com/callback",
96
+ config.auth_endpoint = "https://login.wade.dev.fbsdata.com",
97
+ config.endpoint = "test.api.sparkapi.com"
98
+ config.user_agent = "my useragent"
99
+ config.authentication_mode = SparkApi::Authentication::OAuth2
100
+ end
101
+ SparkApi.oauth2_enabled?().should be_true
53
102
  end
54
103
 
55
104
  it "should reset" do
@@ -44,6 +44,13 @@ describe Listing do
44
44
  "Uri1280"=>"http=>//devresize.flexmls.com/fgo/1280x1024/true/20101115201631519737000000-o.jpg",
45
45
  "UriThumb"=>"http=>//images.dev.fbsdata.com/fgo/20101115201631519737000000-t.jpg",
46
46
  "Uri640"=>"http=>//devresize.flexmls.com/fgo/640x480/true/20101115201631519737000000-o.jpg"
47
+ }],
48
+ "OpenHouses" => [{
49
+ 'ResourceUri'=>"/v1/listings/20060412165917817933000000/openhouses/20101127153422574618000000",
50
+ 'Id'=>"20060412165917817933000000",
51
+ 'Date'=>"10/01/2010",
52
+ 'StartTime'=>"09:00:00-07:00",
53
+ 'EndTime'=>"12:00:00-07:00"
47
54
  }]
48
55
  },
49
56
  "Id"=>"20080619000032866372000000"
@@ -250,17 +257,18 @@ describe Listing do
250
257
  l.photos.length.should == 0
251
258
  l.documents.length.should == 0
252
259
  end
253
-
254
- on_get_it "should return tour of homes" do
255
- stub_api_get("/listings/20060725224713296297000000", 'listings/no_subresources.json')
256
- stub_api_get("/listings/20060725224713296297000000/tourofhomes", 'listings/tour_of_homes.json')
257
-
258
- l = Listing.find('20060725224713296297000000')
259
- l.tour_of_homes().length.should == 2
260
- l.videos.length.should == 0
261
- l.photos.length.should == 0
262
- l.documents.length.should == 0
263
- end
260
+
261
+ ## TourOfHomes: Not implemented yet ##
262
+ #on_get_it "should return tour of homes" do
263
+ #stub_api_get("/listings/20060725224713296297000000", 'listings/no_subresources.json')
264
+ #stub_api_get("/listings/20060725224713296297000000/tourofhomes", 'listings/tour_of_homes.json')
265
+
266
+ #l = Listing.find('20060725224713296297000000')
267
+ #l.tour_of_homes().length.should == 2
268
+ #l.videos.length.should == 0
269
+ #l.photos.length.should == 0
270
+ #l.documents.length.should == 0
271
+ #end
264
272
 
265
273
  on_get_it "should return permissions" do
266
274
  stub_api_get("/listings/20060725224713296297000000", 'listings/with_permissions.json', { :_expand => "Permissions" })
@@ -306,7 +314,7 @@ describe Listing do
306
314
  context "/listings/nearby", :support do
307
315
  on_get_it "should return nearby homes" do
308
316
  stub_api_get("/listings/nearby",
309
- 'listings/no_subresources.json', {:Lat => "45.45", :Lon => "-93.98"})
317
+ 'listings/no_subresources.json', {:_lat => "45.45", :_lon => "-93.98"})
310
318
  l = Listing.nearby(45.45, -93.98)
311
319
  l.length.should == 1
312
320
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spark_api
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 1
10
- version: 1.0.1
9
+ - 2
10
+ version: 1.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Brandon Hornseth
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2012-04-30 00:00:00 Z
19
+ date: 2012-07-11 00:00:00 Z
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
22
  version_requirements: &id001 !ruby/object:Gem::Requirement
@@ -195,22 +195,14 @@ dependencies:
195
195
  version_requirements: &id011 !ruby/object:Gem::Requirement
196
196
  none: false
197
197
  requirements:
198
- - - ">="
198
+ - - "="
199
199
  - !ruby/object:Gem::Version
200
- hash: 11
200
+ hash: 1
201
201
  segments:
202
202
  - 1
203
203
  - 7
204
- - 0
205
- version: 1.7.0
206
- - - <
207
- - !ruby/object:Gem::Version
208
- hash: 55
209
- segments:
210
- - 1
211
- - 8
212
- - 0
213
- version: 1.8.0
204
+ - 5
205
+ version: 1.7.5
214
206
  requirement: *id011
215
207
  prerelease: false
216
208
  name: webmock
@@ -307,6 +299,7 @@ files:
307
299
  - lib/spark_api/authentication/oauth2_impl/grant_type_code.rb
308
300
  - lib/spark_api/authentication/oauth2_impl/grant_type_code.rb~
309
301
  - lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb
302
+ - lib/spark_api/authentication/oauth2_impl/simple_provider.rb
310
303
  - lib/spark_api/authentication/oauth2_impl/grant_type_password.rb~
311
304
  - lib/spark_api/authentication/oauth2_impl/grant_type_password.rb
312
305
  - lib/spark_api/authentication/oauth2_impl/grant_type_refresh.rb~
@@ -396,12 +389,14 @@ files:
396
389
  - lib/spark_api/configuration.rb~
397
390
  - lib/spark_api/configuration.rb
398
391
  - lib/spark_api/configuration/yaml.rb~
392
+ - lib/spark_api/configuration/oauth2_configurable.rb
399
393
  - lib/spark_api/configuration/yaml.rb
400
394
  - lib/spark_api.rb
401
395
  - script/console~
402
396
  - script/console
403
397
  - script/example.rb
404
398
  - script/example.rb~
399
+ - script/oauth2_example.rb
405
400
  - spec/fixtures/oauth2_error.json
406
401
  - spec/fixtures/errors/failure_with_constraint.json
407
402
  - spec/fixtures/errors/expired.json