gds-api-adapters 5.5.0 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gds_api/base.rb CHANGED
@@ -2,6 +2,7 @@ require_relative 'json_client'
2
2
  require 'cgi'
3
3
  require 'null_logger'
4
4
  require 'plek'
5
+ require_relative 'list_response'
5
6
 
6
7
  class GdsApi::Base
7
8
  class InvalidAPIURL < StandardError
@@ -21,7 +22,8 @@ class GdsApi::Base
21
22
  :post_json, :post_json!,
22
23
  :put_json, :put_json!,
23
24
  :delete_json!,
24
- :get_raw, :post_multipart
25
+ :get_raw, :get_raw!,
26
+ :post_multipart
25
27
 
26
28
  attr_reader :options
27
29
 
@@ -50,6 +52,12 @@ class GdsApi::Base
50
52
  base = "#{base_url}/#{slug}.json#{query_string(options)}"
51
53
  end
52
54
 
55
+ def get_list!(url)
56
+ get_json!(url) do |r|
57
+ GdsApi::ListResponse.new(r, self)
58
+ end
59
+ end
60
+
53
61
  private
54
62
  attr_accessor :endpoint
55
63
 
@@ -1,7 +1,6 @@
1
1
  require_relative 'base'
2
2
  require_relative 'exceptions'
3
- require 'gds_api/content_api/response'
4
- require 'gds_api/content_api/list_response'
3
+ require_relative 'list_response'
5
4
 
6
5
  class GdsApi::ContentApi < GdsApi::Base
7
6
  include GdsApi::ExceptionHandling
@@ -95,26 +94,26 @@ class GdsApi::ContentApi < GdsApi::Base
95
94
 
96
95
  def get_list!(url)
97
96
  get_json!(url) { |r|
98
- ListResponse.new(r, self, web_urls_relative_to: @web_urls_relative_to)
97
+ GdsApi::ListResponse.new(r, self, web_urls_relative_to: @web_urls_relative_to)
99
98
  }
100
99
  end
101
100
 
102
101
  def get_list(url)
103
102
  get_json(url) { |r|
104
- ListResponse.new(r, self, web_urls_relative_to: @web_urls_relative_to)
103
+ GdsApi::ListResponse.new(r, self, web_urls_relative_to: @web_urls_relative_to)
105
104
  }
106
105
  end
107
106
 
108
107
  def get_json(url, &create_response)
109
108
  create_response = create_response || Proc.new { |r|
110
- GdsApi::ContentApi::Response.new(r, web_urls_relative_to: @web_urls_relative_to)
109
+ GdsApi::Response.new(r, web_urls_relative_to: @web_urls_relative_to)
111
110
  }
112
111
  super(url, &create_response)
113
112
  end
114
113
 
115
114
  def get_json!(url, &create_response)
116
115
  create_response = create_response || Proc.new { |r|
117
- GdsApi::ContentApi::Response.new(r, web_urls_relative_to: @web_urls_relative_to)
116
+ GdsApi::Response.new(r, web_urls_relative_to: @web_urls_relative_to)
118
117
  }
119
118
  super(url, &create_response)
120
119
  end
@@ -4,6 +4,7 @@ require 'gds_api/panopticon'
4
4
  require 'gds_api/content_api'
5
5
  require 'gds_api/licence_application'
6
6
  require 'gds_api/asset_manager'
7
+ require 'gds_api/worldwide'
7
8
 
8
9
  module GdsApi
9
10
  module Helpers
@@ -35,6 +36,10 @@ module GdsApi
35
36
  Object::const_defined?(:PANOPTICON_API_CREDENTIALS) ? PANOPTICON_API_CREDENTIALS : {}
36
37
  end
37
38
 
39
+ def worldwide_api(options = {})
40
+ @worldwide_api ||= GdsApi::Worldwide.new(Plek.current.find("whitehall-admin"), options)
41
+ end
42
+
38
43
  def self.included(klass)
39
44
  if klass.respond_to?(:helper_method)
40
45
  klass.helper_method :publisher_api, :panopticon_api, :imminence_api, :content_api, :licence_application_api
@@ -1,6 +1,7 @@
1
1
  require_relative 'response'
2
2
  require_relative 'exceptions'
3
3
  require_relative 'version'
4
+ require_relative 'null_cache'
4
5
  require 'lrucache'
5
6
  require 'rest-client'
6
7
 
@@ -20,10 +21,19 @@ module GdsApi
20
21
  attr_accessor :logger, :options, :cache
21
22
 
22
23
  def initialize(options = {})
24
+ if options[:disable_timeout] or options[:timeout].to_i < 0
25
+ raise "It is no longer possible to disable the timeout."
26
+ end
27
+
23
28
  @logger = options[:logger] || GdsApi::Base.logger
24
- cache_size = options[:cache_size] || DEFAULT_CACHE_SIZE
25
- cache_ttl = options[:cache_ttl] || DEFAULT_CACHE_TTL
26
- @cache = JsonClient.cache(cache_size, cache_ttl)
29
+
30
+ if options[:disable_cache]
31
+ @cache = NullCache.new
32
+ else
33
+ cache_size = options[:cache_size] || DEFAULT_CACHE_SIZE
34
+ cache_ttl = options[:cache_ttl] || DEFAULT_CACHE_TTL
35
+ @cache = JsonClient.cache(cache_size, cache_ttl)
36
+ end
27
37
  @options = options
28
38
  end
29
39
 
@@ -33,12 +43,16 @@ module GdsApi
33
43
  'User-Agent' => "GDS Api Client v. #{GdsApi::VERSION}"
34
44
  }
35
45
  DEFAULT_TIMEOUT_IN_SECONDS = 4
36
- DEFAULT_CACHE_SIZE = 10
46
+ DEFAULT_CACHE_SIZE = 100
37
47
  DEFAULT_CACHE_TTL = 15 * 60 # 15 minutes
38
48
 
49
+ def get_raw!(url)
50
+ do_raw_request(:get, url)
51
+ end
52
+
39
53
  def get_raw(url)
40
54
  ignoring GdsApi::HTTPNotFound do
41
- do_raw_request(:get, url)
55
+ get_raw!(url)
42
56
  end
43
57
  end
44
58
 
@@ -139,13 +153,9 @@ module GdsApi
139
153
  # Take a hash of parameters for Request#execute; return a hash of
140
154
  # parameters with timeouts included
141
155
  def with_timeout(method_params)
142
- if options[:disable_timeout]
143
- method_params.merge(timeout: -1)
144
- else
145
- method_params.merge(
146
- timeout: options[:timeout] || DEFAULT_TIMEOUT_IN_SECONDS
147
- )
148
- end
156
+ method_params.merge(
157
+ timeout: options[:timeout] || DEFAULT_TIMEOUT_IN_SECONDS
158
+ )
149
159
  end
150
160
 
151
161
  def with_ssl_options(method_params)
@@ -157,11 +167,32 @@ module GdsApi
157
167
 
158
168
  def do_request_with_cache(method, url, params = nil)
159
169
  # Only read GET requests from the cache: any other request methods should
160
- # always be passed through
161
- if method == :get
162
- @cache[url] ||= do_request(method, url, params)
163
- else
164
- do_request(method, url, params)
170
+ # always be passed through. Note that this means HEAD requests won't get
171
+ # cached, but that would involve separating the cache by method and URL.
172
+ # Also, we don't generally make HEAD requests.
173
+ use_cache = (method == :get)
174
+
175
+ if use_cache
176
+ cached_response = @cache[url]
177
+ return cached_response if cached_response
178
+ end
179
+
180
+ response = do_request(method, url, params)
181
+
182
+ if use_cache
183
+ cache_time = response_cache_time(response)
184
+ # If cache_time is nil, this will fall back on @cache's default
185
+ @cache.store(url, response, cache_time)
186
+ end
187
+
188
+ response
189
+ end
190
+
191
+ # Return either a Time object representing the expiry time of the response
192
+ # or nil if no cache information is provided
193
+ def response_cache_time(response)
194
+ if response.headers[:expires]
195
+ Time.httpdate response.headers[:expires]
165
196
  end
166
197
  end
167
198
 
@@ -2,13 +2,13 @@ require "json"
2
2
  require "gds_api/response"
3
3
  require "link_header"
4
4
 
5
- class GdsApi::ContentApi < GdsApi::Base
5
+ module GdsApi
6
6
 
7
- # Response class for lists of multiple items from the content API.
7
+ # Response class for lists of multiple items.
8
8
  #
9
- # These responses are in a common format, with the list of results contained
10
- # under the `results` key. The response may also have previous and subsequent
11
- # pages, indicated by entries in the response's `Link` header.
9
+ # This expects responses to be in a common format, with the list of results
10
+ # contained under the `results` key. The response may also have previous and
11
+ # subsequent pages, indicated by entries in the response's `Link` header.
12
12
  class ListResponse < Response
13
13
 
14
14
  # The ListResponse is instantiated with a reference back to the API client,
@@ -0,0 +1,13 @@
1
+ module GdsApi
2
+ class NullCache
3
+ def [](k)
4
+ nil
5
+ end
6
+
7
+ def []=(k, v)
8
+ end
9
+
10
+ def store(k, v, args={})
11
+ end
12
+ end
13
+ end
@@ -3,50 +3,91 @@ require 'ostruct'
3
3
  require_relative 'core-ext/openstruct'
4
4
 
5
5
  module GdsApi
6
+
7
+ # This wraps an HTTP response with a JSON body, and presents this as
8
+ # an object that has the read behaviour of both a Hash and an OpenStruct
9
+ #
10
+ # Responses can be configured to use relative URLs for `web_url` properties.
11
+ # API endpoints should return absolute URLs so that they make sense outside of the
12
+ # GOV.UK context. However on internal systems we want to present relative URLs.
13
+ # By specifying a base URI, this will convert all matching web_urls into relative URLs
14
+ # This is useful on non-canonical frontends, such as those in staging environments.
15
+ # See: https://github.com/alphagov/wiki/wiki/API-conventions for details on the API conventions
16
+ #
17
+ # Example:
18
+ #
19
+ # r = Response.new(response, web_urls_relative_to: "https://www.gov.uk")
20
+ # r.results[0].web_url
21
+ # => "/bank-holidays"
6
22
  class Response
7
23
  extend Forwardable
8
24
  include Enumerable
9
25
 
26
+ WEB_URL_KEYS = ["web_url"]
27
+
10
28
  def_delegators :to_hash, :[], :"<=>", :each
11
29
 
12
- def initialize(http_response)
30
+ def initialize(http_response, options = {})
13
31
  @http_response = http_response
32
+ @web_urls_relative_to = URI.parse(options[:web_urls_relative_to]) if options[:web_urls_relative_to]
14
33
  end
15
34
 
16
35
  def raw_response_body
17
36
  @http_response.body
18
37
  end
19
38
 
20
- def to_hash
21
- @parsed ||= JSON.parse(@http_response.body)
22
- end
23
-
24
39
  def code
25
40
  # Return an integer code for consistency with HTTPErrorResponse
26
41
  @http_response.code
27
42
  end
28
43
 
44
+ def to_hash
45
+ @parsed ||= transform_parsed(JSON.parse(@http_response.body))
46
+ end
47
+
29
48
  def to_ostruct
30
- self.class.build_ostruct_recursively(to_hash)
49
+ @ostruct ||= self.class.build_ostruct_recursively(to_hash)
31
50
  end
32
51
 
33
52
  def method_missing(method)
34
- if to_hash.has_key?(method.to_s)
35
- to_ostruct.send(method)
36
- else
37
- nil
38
- end
53
+ to_ostruct.send(method)
39
54
  end
40
55
 
41
56
  def respond_to_missing?(method, include_private)
42
- to_hash.has_key?(method.to_s)
57
+ to_ostruct.respond_to?(method, include_private)
43
58
  end
44
59
 
45
- def present?; ! blank?; end
60
+ def present?; true; end
46
61
  def blank?; false; end
47
62
 
48
63
  private
49
64
 
65
+ def transform_parsed(value)
66
+ return value if @web_urls_relative_to.nil?
67
+
68
+ case value
69
+ when Hash
70
+ Hash[value.map { |k, v|
71
+ # NOTE: Don't bother transforming if the value is nil
72
+ if WEB_URL_KEYS.include?(k) && v
73
+ # Use relative URLs to route when the web_url value is on the
74
+ # same domain as the site root. Note that we can't just use the
75
+ # `route_to` method, as this would give us technically correct
76
+ # but potentially confusing `//host/path` URLs for URLs with the
77
+ # same scheme but different hosts.
78
+ relative_url = @web_urls_relative_to.route_to(v)
79
+ [k, relative_url.host ? v : relative_url.to_s]
80
+ else
81
+ [k, transform_parsed(v)]
82
+ end
83
+ }]
84
+ when Array
85
+ value.map { |v| transform_parsed(v) }
86
+ else
87
+ value
88
+ end
89
+ end
90
+
50
91
  def self.build_ostruct_recursively(value)
51
92
  case value
52
93
  when Hash
@@ -1,56 +1,35 @@
1
+ require 'gds_api/base'
1
2
  require 'rack/utils'
2
3
 
3
4
  module GdsApi
4
- class Rummager
5
- class SearchUriNotSpecified < RuntimeError; end
6
- class SearchError < RuntimeError; end
7
- class SearchServiceError < SearchError; end
8
- class SearchTimeout < SearchError; end
9
-
10
- attr_accessor :search_uri
11
-
12
- def initialize(search_uri)
13
- raise SearchUriNotSpecified unless search_uri
14
- self.search_uri = search_uri
15
- end
5
+ class Rummager < Base
16
6
 
17
7
  def search(query, format_filter = nil)
18
8
  return [] if query.nil? || query == ""
19
- JSON.parse(search_response(:search, query, format_filter).body)
9
+ get_json!(search_url(:search, query, format_filter))
20
10
  end
21
11
 
22
12
  def autocomplete(query, format_filter = nil)
23
13
  return [] if query.nil? || query == ""
24
- search_response(:autocomplete, query, format_filter).body
14
+ get_raw!(search_url(:autocomplete, query, format_filter)).body
25
15
  end
26
16
 
27
17
  def advanced_search(args)
28
18
  return [] if args.nil? || args.empty?
29
- JSON.parse(advanced_search_response(args).body)
19
+ request_path = "#{base_url}/advanced_search?#{Rack::Utils.build_nested_query(args)}"
20
+ get_json!(request_path)
30
21
  end
31
22
 
32
- private
33
-
34
- def advanced_search_response(args)
35
- request_path = "/advanced_search?#{Rack::Utils.build_nested_query(args)}"
36
- get_response(request_path)
37
- end
23
+ private
38
24
 
39
- def search_response(type, query, format_filter = nil)
40
- request_path = "/#{type}?q=#{CGI.escape(query)}"
25
+ def search_url(type, query, format_filter = nil)
26
+ request_path = "#{base_url}/#{type}?q=#{CGI.escape(query)}"
41
27
  request_path << "&format_filter=#{CGI.escape(format_filter)}" if format_filter
42
- get_response(request_path)
28
+ request_path
43
29
  end
44
30
 
45
- def get_response(request_path)
46
- uri = URI("#{search_uri}#{request_path}")
47
- http = Net::HTTP.new(uri.host, uri.port)
48
- http.use_ssl = true if uri.scheme == 'https'
49
- response = http.get(uri.request_uri, {"Accept" => "application/json"})
50
- raise SearchServiceError.new("#{response.code}: #{response.body}") unless response.code == "200"
51
- response
52
- rescue Timeout::Error
53
- raise SearchTimeout
31
+ def base_url
32
+ endpoint
54
33
  end
55
34
  end
56
35
  end
@@ -0,0 +1,36 @@
1
+ module GdsApi
2
+ module TestHelpers
3
+ module CommonResponses
4
+ def titleize_slug(slug, options = {})
5
+ if options[:title_case]
6
+ slug.gsub("-", " ").gsub(/\b./) {|m| m.upcase }
7
+ else
8
+ slug.gsub("-", " ").capitalize
9
+ end
10
+ end
11
+
12
+ def response_base
13
+ {
14
+ "_response_info" => {
15
+ "status" => "ok"
16
+ }
17
+ }
18
+ end
19
+ alias_method :singular_response_base, :response_base
20
+
21
+ def plural_response_base
22
+ response_base.merge(
23
+ {
24
+ "description" => "Tags!",
25
+ "total" => 100,
26
+ "start_index" => 1,
27
+ "page_size" => 100,
28
+ "current_page" => 1,
29
+ "pages" => 1,
30
+ "results" => []
31
+ }
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,10 +1,11 @@
1
1
  require 'gds_api/test_helpers/json_client_helper'
2
2
  require 'cgi'
3
- require_relative 'content_api/artefact_stub'
3
+ require 'gds_api/test_helpers/common_responses'
4
4
 
5
5
  module GdsApi
6
6
  module TestHelpers
7
7
  module ContentApi
8
+ include GdsApi::TestHelpers::CommonResponses
8
9
  # Generally true. If you are initializing the client differently,
9
10
  # you could redefine/override the constant or stub directly.
10
11
  CONTENT_API_ENDPOINT = Plek.current.find('contentapi')
@@ -295,38 +296,10 @@ module GdsApi
295
296
  raise "Need a licence identifier" if details[:licence_identifier].nil?
296
297
  @stubbed_content_api_licences << details
297
298
  end
298
-
299
- private
300
-
301
- def titleize_slug(slug)
302
- slug.gsub("-", " ").capitalize
303
- end
304
-
305
- def response_base
306
- {
307
- "_response_info" => {
308
- "status" => "ok"
309
- }
310
- }
311
- end
312
-
313
- def singular_response_base
314
- response_base
315
- end
316
-
317
- def plural_response_base
318
- response_base.merge(
319
- {
320
- "description" => "Tags!",
321
- "total" => 100,
322
- "startIndex" => 1,
323
- "pageSize" => 100,
324
- "currentPage" => 1,
325
- "pages" => 1,
326
- "results" => []
327
- }
328
- )
329
- end
330
299
  end
331
300
  end
332
301
  end
302
+
303
+ # This has to be after the definition of TestHelpers::ContentApi, otherwise, this doesn't pick up
304
+ # the include of TestHelpers::CommonResponses
305
+ require_relative 'content_api/artefact_stub'
@@ -1,16 +1,4 @@
1
1
  require 'gds_api/json_client'
2
+ require 'gds_api/null_cache'
2
3
 
3
- module GdsApi
4
- module TestHelpers
5
- class NullCache
6
- def [](k)
7
- nil
8
- end
9
-
10
- def []=(k, v)
11
- end
12
- end
13
- end
14
- end
15
-
16
- GdsApi::JsonClient.cache = GdsApi::TestHelpers::NullCache.new
4
+ GdsApi::JsonClient.cache = GdsApi::NullCache.new
@@ -0,0 +1,116 @@
1
+ require 'gds_api/test_helpers/json_client_helper'
2
+ require 'gds_api/test_helpers/common_responses'
3
+
4
+ module GdsApi
5
+ module TestHelpers
6
+ module Worldwide
7
+ include GdsApi::TestHelpers::CommonResponses
8
+
9
+ WORLDWIDE_API_ENDPOINT = Plek.current.find('whitehall-admin')
10
+
11
+ # Sets up the index endpoints for the given country slugs
12
+ # The stubs are setup to paginate in chunks of 20
13
+ #
14
+ # This also sets up the individual endpoints for each slug
15
+ # by calling worldwide_api_has_location below
16
+ def worldwide_api_has_locations(location_slugs)
17
+ location_slugs.each {|s| worldwide_api_has_location(s) }
18
+ pages = []
19
+ location_slugs.each_slice(20) do |slugs|
20
+ pages << slugs.map {|s| world_location_details_for_slug(s) }
21
+ end
22
+
23
+ pages.each_with_index do |page, i|
24
+ page_details = plural_response_base.merge({
25
+ "results" => page,
26
+ "total" => location_slugs.size,
27
+ "pages" => pages.size,
28
+ "current_page" => i + 1,
29
+ "page_size" => 20,
30
+ "start_index" => i * 20 + 1,
31
+ })
32
+
33
+ links = {:self => "#{WORLDWIDE_API_ENDPOINT}/api/world-locations?page=#{i + 1}" }
34
+ links[:next] = "#{WORLDWIDE_API_ENDPOINT}/api/world-locations?page=#{i + 2}" if pages[i+1]
35
+ links[:previous] = "#{WORLDWIDE_API_ENDPOINT}/api/world-locations?page=#{i}" unless i == 0
36
+ page_details["_response_info"]["links"] = []
37
+ link_headers = []
38
+ links.each do |rel, href|
39
+ page_details["_response_info"]["links"] << {"rel" => rel, "href" => href}
40
+ link_headers << "<#{href}>; rel=\"#{rel}\""
41
+ end
42
+
43
+ stub_request(:get, links[:self]).
44
+ to_return(:status => 200, :body => page_details.to_json, :headers => {"Link" => link_headers.join(", ")})
45
+ if i == 0
46
+ # First page exists at URL with and without page param
47
+ stub_request(:get, links[:self].sub(/\?page=1/, '')).
48
+ to_return(:status => 200, :body => page_details.to_json, :headers => {"Link" => link_headers.join(", ")})
49
+ end
50
+ end
51
+ end
52
+
53
+ def worldwide_api_has_selection_of_locations
54
+ worldwide_api_has_locations %w(
55
+ afghanistan angola australia bahamas belarus brazil brunei cambodia chad
56
+ croatia denmark eritrea france ghana iceland japan laos luxembourg malta
57
+ micronesia mozambique nicaragua panama portugal sao-tome-and-principe singapore
58
+ south-korea sri-lanka uk-delegation-to-council-of-europe
59
+ uk-delegation-to-organization-for-security-and-co-operation-in-europe
60
+ united-kingdom venezuela vietnam
61
+ )
62
+ end
63
+
64
+ def worldwide_api_has_location(location_slug, details=nil)
65
+ details ||= world_location_for_slug(location_slug)
66
+ stub_request(:get, "#{WORLDWIDE_API_ENDPOINT}/api/world-locations/#{location_slug}").
67
+ to_return(:status => 200, :body => details.to_json)
68
+ end
69
+
70
+ def worldwide_api_does_not_have_location(location_slug)
71
+ stub_request(:get, "#{WORLDWIDE_API_ENDPOINT}/api/world-locations/#{location_slug}").to_return(:status => 404)
72
+ end
73
+
74
+ def worldwide_api_has_organisations_for_location(location_slug, json_or_hash)
75
+ json = json_or_hash.is_a?(Hash) ? json_or_hash.to_json : json_or_hash
76
+ url = "#{WORLDWIDE_API_ENDPOINT}/api/world-locations/#{location_slug}/organisations"
77
+ stub_request(:get, url).
78
+ to_return(:status => 200, :body => json, :headers => {"Link" => "<#{url}; rel\"self\""})
79
+ end
80
+
81
+ def worldwide_api_has_no_organisations_for_location(location_slug)
82
+ details = {"results" => [], "total" => 0, "_response_info" => { "status" => "ok" } }
83
+ url = "#{WORLDWIDE_API_ENDPOINT}/api/world-locations/#{location_slug}/organisations"
84
+ stub_request(:get, url).
85
+ to_return(:status => 200, :body => details.to_json, :headers => {"Link" => "<#{url}; rel\"self\""})
86
+ end
87
+
88
+ def world_location_for_slug(slug)
89
+ singular_response_base.merge(world_location_details_for_slug(slug))
90
+ end
91
+
92
+ # Constructs a sample world_location
93
+ #
94
+ # if the slug contains 'delegation' or 'mission' the format will be set to 'International delegation'
95
+ # othersiwe it will be set to 'World location'
96
+ def world_location_details_for_slug(slug)
97
+ {
98
+ "id" => "https://www.gov.uk/api/world-locations/#{slug}",
99
+ "title" => titleize_slug(slug, :title_case => true),
100
+ "format" => (slug =~ /(delegation|mission)/ ? "International delegation" : "World location"),
101
+ "updated_at" => "2013-03-25T13:06:42+00:00",
102
+ "web_url" => "https://www.gov.uk/government/world/#{slug}",
103
+ "details" => {
104
+ "slug" => slug,
105
+ "iso2" => slug[0..1].upcase,
106
+ },
107
+ "organisations" => {
108
+ "id" => "https://www.gov.uk/api/world-locations/#{slug}/organisations",
109
+ "web_url" => "https://www.gov.uk/government/world/#{slug}#organisations"
110
+ },
111
+ }
112
+ end
113
+
114
+ end
115
+ end
116
+ end
@@ -1,3 +1,3 @@
1
1
  module GdsApi
2
- VERSION = '5.5.0'
2
+ VERSION = '6.0.0'
3
3
  end
@@ -0,0 +1,21 @@
1
+ require_relative 'base'
2
+
3
+ class GdsApi::Worldwide < GdsApi::Base
4
+
5
+ def world_locations
6
+ get_list! "#{base_url}/world-locations"
7
+ end
8
+
9
+ def world_location(location_slug)
10
+ get_json "#{base_url}/world-locations/#{location_slug}"
11
+ end
12
+
13
+ def organisations_for_world_location(location_slug)
14
+ get_list! "#{base_url}/world-locations/#{location_slug}/organisations"
15
+ end
16
+
17
+ private
18
+ def base_url
19
+ "#{endpoint}/api"
20
+ end
21
+ end