tfl_api_client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +37 -0
- data/.travis.yml +29 -0
- data/CHANGELOG.md +9 -0
- data/CONTRIBUTING.md +62 -0
- data/GETTING_STARTED.md +161 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +62 -0
- data/Rakefile +30 -0
- data/lib/tfl_api_client/bike_point.rb +105 -0
- data/lib/tfl_api_client/client.rb +235 -0
- data/lib/tfl_api_client/exceptions.rb +91 -0
- data/lib/tfl_api_client/version.rb +28 -0
- data/lib/tfl_api_client.rb +33 -0
- data/spec/cassettes/bike_point/authorised_client_location.yml +83 -0
- data/spec/cassettes/bike_point/authorised_client_locations.yml +8179 -0
- data/spec/cassettes/bike_point/authorised_client_locations_within_bounding_box.yml +402 -0
- data/spec/cassettes/bike_point/authorised_client_locations_within_locus.yml +106 -0
- data/spec/cassettes/bike_point/authorised_client_search.yml +80 -0
- data/spec/cassettes/bike_point/unauthorised_client_location.yml +50 -0
- data/spec/cassettes/bike_point/unauthorised_client_locations.yml +50 -0
- data/spec/cassettes/bike_point/unauthorised_client_locations_within_bounding_box.yml +50 -0
- data/spec/cassettes/bike_point/unauthorised_client_locations_within_locus.yml +50 -0
- data/spec/cassettes/bike_point/unauthorised_client_search.yml +50 -0
- data/spec/integration/bike_point_spec.rb +158 -0
- data/spec/spec_helper.rb +114 -0
- data/spec/support/coverage.rb +36 -0
- data/spec/support/helpers.rb +81 -0
- data/spec/support/vcr.rb +43 -0
- data/spec/unit/bike_point_spec.rb +87 -0
- data/spec/unit/client_spec.rb +199 -0
- data/tfl_api_client.gemspec +36 -0
- metadata +222 -0
@@ -0,0 +1,235 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2015 Luke Hackett
|
3
|
+
#
|
4
|
+
# MIT License
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#
|
25
|
+
|
26
|
+
require 'json'
|
27
|
+
require 'logger'
|
28
|
+
require 'openssl'
|
29
|
+
require 'net/http'
|
30
|
+
require 'tfl_api_client/exceptions'
|
31
|
+
|
32
|
+
module TflApi
|
33
|
+
# This is the client class that allows direct access to the subclasses and to
|
34
|
+
# the TFL API. The class contains methods that perform GET and POST requests
|
35
|
+
# to the API.
|
36
|
+
#
|
37
|
+
class Client
|
38
|
+
|
39
|
+
# Parameters that are permitted as options while initializing the client
|
40
|
+
VALID_PARAMS = %w( app_id app_key host logger log_level log_location ).freeze
|
41
|
+
|
42
|
+
# HTTP verbs supported by the Client
|
43
|
+
VERB_MAP = {
|
44
|
+
get: Net::HTTP::Get
|
45
|
+
}
|
46
|
+
|
47
|
+
# Client accessors
|
48
|
+
attr_reader :app_id, :app_key, :host, :logger, :log_level, :log_location
|
49
|
+
|
50
|
+
# Initialize a Client object with TFL API credentials
|
51
|
+
#
|
52
|
+
# @param args [Hash] Arguments to connect to TFL API
|
53
|
+
#
|
54
|
+
# @option args [String] :app_id the application id generated by registering an app with TFL
|
55
|
+
# @option args [String] :app_key the application key generated by registering an app with TFL
|
56
|
+
# @option args [String] :host the API's host url - defaults to api.tfl.gov.uk
|
57
|
+
#
|
58
|
+
# @return [TflApi::Client] a client object to the TFL API
|
59
|
+
#
|
60
|
+
# @raise [ArgumentError] when required options are not provided.
|
61
|
+
#
|
62
|
+
def initialize(args)
|
63
|
+
args.each do |key, value|
|
64
|
+
if value && VALID_PARAMS.include?(key.to_s)
|
65
|
+
instance_variable_set("@#{key.to_sym}", value)
|
66
|
+
end
|
67
|
+
end if args.is_a? Hash
|
68
|
+
|
69
|
+
# Ensure the Application ID and Key is given
|
70
|
+
raise ArgumentError, "Application ID (app_id) is required to interact with TFL's APIs" unless app_id
|
71
|
+
raise ArgumentError, "Application Key (app_key) is required to interact with TFL's APIs" unless app_key
|
72
|
+
|
73
|
+
# Set client defaults
|
74
|
+
@host ||= 'https://api.tfl.gov.uk'
|
75
|
+
@host = URI.parse(@host)
|
76
|
+
|
77
|
+
# Create a global Net:HTTP instance
|
78
|
+
@http = Net::HTTP.new(@host.host, @host.port)
|
79
|
+
@http.use_ssl = true
|
80
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
81
|
+
|
82
|
+
# Logging
|
83
|
+
if @logger
|
84
|
+
raise ArgumentError, 'logger parameter must be a Logger object' unless @logger.is_a?(Logger)
|
85
|
+
raise ArgumentError, 'log_level cannot be set if using custom logger' if @log_level
|
86
|
+
raise ArgumentError, 'log_location cannot be set if using custom logger' if @log_location
|
87
|
+
else
|
88
|
+
@log_level = Logger::INFO unless @log_level
|
89
|
+
@log_location = STDOUT unless @log_location
|
90
|
+
@logger = Logger.new(@log_location)
|
91
|
+
@logger.level = @log_level
|
92
|
+
@logger.datetime_format = '%F T%T%z'
|
93
|
+
@logger.formatter = proc do |severity, datetime, _progname, msg|
|
94
|
+
"[%s] %-6s %s \r\n" % [datetime, severity, msg]
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Creates an instance to the BikePoint class by passing a reference to self
|
100
|
+
#
|
101
|
+
# @return [TflApi::Client::BikePoint] An object to BikePoint subclass
|
102
|
+
#
|
103
|
+
def bike_point
|
104
|
+
TflApi::Client::BikePoint.new(self)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Performs a HTTP GET request to the api, based upon the given URI resource
|
108
|
+
# and any additional HTTP query parameters. This method will automatically
|
109
|
+
# inject the mandatory application id and application key HTTP query
|
110
|
+
# parameters.
|
111
|
+
#
|
112
|
+
# @return [hash] HTTP response as a hash
|
113
|
+
#
|
114
|
+
def get(path, query={})
|
115
|
+
request_json :get, path, query
|
116
|
+
end
|
117
|
+
|
118
|
+
# Overrides the inspect method to prevent the TFL Application ID and Key
|
119
|
+
# credentials being shown when the `inspect` method is called. The method
|
120
|
+
# will only print the important variables.
|
121
|
+
#
|
122
|
+
# @return [String] String representation of the current object
|
123
|
+
#
|
124
|
+
def inspect
|
125
|
+
"#<#{self.class.name}:0x#{(self.__id__ * 2).to_s(16)} " +
|
126
|
+
"@host=#{host.to_s}, " +
|
127
|
+
"@log_level=#{log_level}, " +
|
128
|
+
"@log_location=#{log_location.inspect}>"
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
|
133
|
+
# This method requests the given path via the given resource with the additional url
|
134
|
+
# params. All successful responses will yield a hash of the response body, whilst
|
135
|
+
# all other response types will raise a child of TflApi::Exceptions::ApiException.
|
136
|
+
# For example a 404 response would raise a TflApi::Exceptions::NotFound exception.
|
137
|
+
#
|
138
|
+
# @param method [Symbol] The type of HTTP request to make, e.g. :get
|
139
|
+
# @param path [String] the path of the resource (not including the base url) to request
|
140
|
+
# @param params [Hash]
|
141
|
+
#
|
142
|
+
# @return [HTTPResponse] HTTP response object
|
143
|
+
#
|
144
|
+
# @raise [TflApi::Exceptions::ApiException] when an error has occurred with TFL's API
|
145
|
+
#
|
146
|
+
def request_json(method, path, params)
|
147
|
+
response = request(method, path, params)
|
148
|
+
|
149
|
+
if response.kind_of? Net::HTTPSuccess
|
150
|
+
parse_response_json(response)
|
151
|
+
else
|
152
|
+
raise_exception(response)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Creates and performs HTTP request by the request medium to the given path
|
157
|
+
# with any additional uri parameters. The method will return the HTTP
|
158
|
+
# response object upon completion.
|
159
|
+
#
|
160
|
+
# @param method [Symbol] The type of HTTP request to make, e.g. :get
|
161
|
+
# @param path [String] the path of the resource (not including the base url) to request
|
162
|
+
# @param params [Hash] Additional url params to be added to the request
|
163
|
+
#
|
164
|
+
# @return [HTTPResponse] HTTP response object
|
165
|
+
#
|
166
|
+
def request(method, path, params)
|
167
|
+
full_path = format_request_uri(path, params)
|
168
|
+
request = VERB_MAP[method.to_sym].new(full_path)
|
169
|
+
# TODO - Enable when supporting other HTTP Verbs
|
170
|
+
# request.set_form_data(params) unless method == :get
|
171
|
+
|
172
|
+
@logger.debug "#{method.to_s.upcase} #{path}"
|
173
|
+
@http.request(request)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Returns a full, well-formatted HTTP request URI that can be used to directly
|
177
|
+
# interact with the TFL API.
|
178
|
+
#
|
179
|
+
# @param path [String] the path of the resource (not including the base url) to request
|
180
|
+
# @param params [Hash] Additional url params to be added to the request
|
181
|
+
#
|
182
|
+
# @return [String] Full HTTP request URI
|
183
|
+
#
|
184
|
+
def format_request_uri(path, params)
|
185
|
+
params.merge!({app_id: app_id, app_key: app_key})
|
186
|
+
params_string = URI.encode_www_form(params)
|
187
|
+
URI::HTTPS.build(host: host.host, path: path, query: params_string)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Parses the given response body as JSON, and returns a hash representation of the
|
191
|
+
# the response. Failure to successfully parse the response will result in an
|
192
|
+
# TflApi::Exceptions::ApiException being raised.
|
193
|
+
#
|
194
|
+
# @param response [HTTPResponse] the HTTP response object
|
195
|
+
#
|
196
|
+
# @return [HTTPResponse] HTTP response object
|
197
|
+
#
|
198
|
+
# @raise [TflApi::Exceptions::ApiException] when trying to parse a malformed JSON response
|
199
|
+
#
|
200
|
+
def parse_response_json(response)
|
201
|
+
begin
|
202
|
+
JSON.parse(response.body)
|
203
|
+
rescue JSON::ParserError
|
204
|
+
raise TflApi::Exceptions::ApiException, logger, "Invalid JSON returned from #{host.host}"
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Raises a child of TflApi::Exceptions::ApiException based upon the response code being
|
209
|
+
# classified as non-successful, i.e. a non 2xx response code. All non-successful
|
210
|
+
# responses will raise an TflApi::Exceptions::ApiException by default. Popular
|
211
|
+
# non-successful response codes are mapped to internal exceptions, for example a 404
|
212
|
+
# response code would raise TflApi::Exceptions::NotFound.
|
213
|
+
#
|
214
|
+
# @param response [HTTPResponse] the HTTP response object
|
215
|
+
#
|
216
|
+
# @raise [TflApi::Exceptions::ApiException] when an error has occurred with TFL's API
|
217
|
+
#
|
218
|
+
def raise_exception(response)
|
219
|
+
case response.code.to_i
|
220
|
+
when 401
|
221
|
+
raise TflApi::Exceptions::Unauthorized, logger
|
222
|
+
when 403
|
223
|
+
raise TflApi::Exceptions::Forbidden, logger
|
224
|
+
when 404
|
225
|
+
raise TflApi::Exceptions::NotFound, logger
|
226
|
+
when 500
|
227
|
+
raise TflApi::Exceptions::InternalServerError, logger
|
228
|
+
when 503
|
229
|
+
raise TflApi::Exceptions::ServiceUnavailable, logger
|
230
|
+
else
|
231
|
+
raise TflApi::Exceptions::ApiException, logger, "non-successful response (#{response.code}) was returned"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2015 Luke Hackett
|
3
|
+
#
|
4
|
+
# MIT License
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#
|
25
|
+
|
26
|
+
module TflApi
|
27
|
+
# This module contains classes that define exceptions for various categories.
|
28
|
+
#
|
29
|
+
module Exceptions
|
30
|
+
# This is the base class for Exceptions that is inherited from
|
31
|
+
# RuntimeError.
|
32
|
+
#
|
33
|
+
class ApiException < RuntimeError
|
34
|
+
def initialize(logger, message = '', log_level = Logger::ERROR)
|
35
|
+
logger.add(log_level) { "#{self.class}: #{message}" }
|
36
|
+
super(message)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# This exception class handles cases where invalid credentials are provided
|
41
|
+
# to connect to the TFL API.
|
42
|
+
#
|
43
|
+
class Unauthorized < ApiException
|
44
|
+
def initialize(logger, message = '')
|
45
|
+
message = 'Access denied. Please ensure you have valid TFL credentials.' if message.nil? || message.empty?
|
46
|
+
super(logger, message)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# This exception class handles cases where valid credentials are provided
|
51
|
+
# to connect to the TFL API, but those credentials do not have the access
|
52
|
+
# level to perform the requested task.
|
53
|
+
#
|
54
|
+
class Forbidden < ApiException
|
55
|
+
def initialize(logger, message = '')
|
56
|
+
message = 'Access denied. Your credentials do not permit this request.' if message.nil? || message.empty?
|
57
|
+
super(logger, message, Logger::FATAL)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# This exception class handles cases where a requested resource is not found
|
62
|
+
# on the remote TFL API.
|
63
|
+
#
|
64
|
+
class NotFound < ApiException
|
65
|
+
def initialize(logger, message = '')
|
66
|
+
message = 'Requested resource was not found on the TFL API.' if message.nil? || message.empty?
|
67
|
+
super(logger, message)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# This exception class handles cases where the TFL API returns with a
|
72
|
+
# 500 Internal Server Error.
|
73
|
+
#
|
74
|
+
class InternalServerError < ApiException
|
75
|
+
def initialize(logger, message = '')
|
76
|
+
message = 'TFL API threw an Internal Server Error. Please try again.' if message.nil? || message.empty?
|
77
|
+
super(logger, message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# This exception class handles cases where the Jenkins is getting restarted
|
82
|
+
# or reloaded where the response code returned is 503
|
83
|
+
#
|
84
|
+
class ServiceUnavailable < ApiException
|
85
|
+
def initialize(logger, message = '')
|
86
|
+
message = 'TFL API is currently unavailable. Please try again.' if message.nil? || message.empty?
|
87
|
+
super(logger, message)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2015 Luke Hackett
|
3
|
+
#
|
4
|
+
# MIT License
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#
|
25
|
+
|
26
|
+
module TflApi
|
27
|
+
VERSION = '0.1.0'
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (c) 2015 Luke Hackett
|
3
|
+
#
|
4
|
+
# MIT License
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
7
|
+
# a copy of this software and associated documentation files (the
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
12
|
+
# the following conditions:
|
13
|
+
#
|
14
|
+
# The above copyright notice and this permission notice shall be
|
15
|
+
# included in all copies or substantial portions of the Software.
|
16
|
+
#
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
24
|
+
#
|
25
|
+
|
26
|
+
require 'tfl_api_client/version'
|
27
|
+
require 'tfl_api_client/client'
|
28
|
+
require 'tfl_api_client/bike_point'
|
29
|
+
require 'tfl_api_client/exceptions'
|
30
|
+
|
31
|
+
module TflApi
|
32
|
+
# Your code goes here...
|
33
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.tfl.gov.uk/BikePoint/BikePoints_10?app_id=TFL_APP_ID&app_key=TFL_APP_KEY
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- "*/*"
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
Host:
|
17
|
+
- api.tfl.gov.uk
|
18
|
+
response:
|
19
|
+
status:
|
20
|
+
code: 200
|
21
|
+
message: OK
|
22
|
+
headers:
|
23
|
+
Access-Control-Allow-Headers:
|
24
|
+
- Content-Type
|
25
|
+
Access-Control-Allow-Methods:
|
26
|
+
- GET,POST,PUT,DELETE,OPTIONS
|
27
|
+
Access-Control-Allow-Origin:
|
28
|
+
- "*"
|
29
|
+
Age:
|
30
|
+
- '0'
|
31
|
+
Api-Entity-Payload:
|
32
|
+
- Place
|
33
|
+
Cache-Control:
|
34
|
+
- public, must-revalidate, max-age=150, s-maxage=300
|
35
|
+
Content-Type:
|
36
|
+
- application/json; charset=utf-8
|
37
|
+
Date:
|
38
|
+
- Tue, 11 Aug 2015 16:52:37 GMT
|
39
|
+
Server:
|
40
|
+
- Microsoft-IIS/8.5
|
41
|
+
Via:
|
42
|
+
- 1.1 varnish
|
43
|
+
X-Aspnet-Version:
|
44
|
+
- 4.0.30319
|
45
|
+
X-Backend:
|
46
|
+
- api
|
47
|
+
X-Backend-Url:
|
48
|
+
- "/BikePoint/BikePoints_10"
|
49
|
+
X-Banning:
|
50
|
+
- ''
|
51
|
+
X-Cache:
|
52
|
+
- MISS
|
53
|
+
X-Cacheable:
|
54
|
+
- Yes. Cacheable
|
55
|
+
X-Hash-Url:
|
56
|
+
- "/bikepoint/bikepoints_10"
|
57
|
+
X-Ttl:
|
58
|
+
- '300.000'
|
59
|
+
X-Ttl-Rule:
|
60
|
+
- '0'
|
61
|
+
X-Varnish:
|
62
|
+
- 10.75.2.208
|
63
|
+
- '478472446'
|
64
|
+
Content-Length:
|
65
|
+
- '406'
|
66
|
+
Connection:
|
67
|
+
- keep-alive
|
68
|
+
body:
|
69
|
+
encoding: ASCII-8BIT
|
70
|
+
string: '{"$type":"Tfl.Api.Presentation.Entities.Place, Tfl.Api.Presentation.Entities","id":"BikePoints_10","url":"https://api-prod5.tfl.gov.uk/Place/BikePoints_10","commonName":"Park
|
71
|
+
Street, Bankside","placeType":"BikePoint","additionalProperties":[{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
72
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"TerminalName","sourceSystemKey":"BikePoints","value":"001024","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
73
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"Installed","sourceSystemKey":"BikePoints","value":"true","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
74
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"Locked","sourceSystemKey":"BikePoints","value":"false","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
75
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"InstallDate","sourceSystemKey":"BikePoints","value":"1278242460000","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
76
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"RemovalDate","sourceSystemKey":"BikePoints","value":"","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
77
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"Temporary","sourceSystemKey":"BikePoints","value":"false","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
78
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"NbBikes","sourceSystemKey":"BikePoints","value":"11","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
79
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"NbEmptyDocks","sourceSystemKey":"BikePoints","value":"7","modified":"2015-08-11T16:47:52.26"},{"$type":"Tfl.Api.Presentation.Entities.AdditionalProperties,
|
80
|
+
Tfl.Api.Presentation.Entities","category":"Description","key":"NbDocks","sourceSystemKey":"BikePoints","value":"18","modified":"2015-08-11T16:47:52.26"}],"children":[],"lat":51.505974,"lon":-0.092754}'
|
81
|
+
http_version:
|
82
|
+
recorded_at: Tue, 11 Aug 2015 16:52:38 GMT
|
83
|
+
recorded_with: VCR 2.9.3
|