gds-api-adapters 5.5.0 → 6.0.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.
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