synsbasen_api 1.0.13 → 1.0.15

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 565b3bfae169b625688bcb1bb70d1fc3c68abb88d2226b0e796139a25adab9bc
4
- data.tar.gz: fdb44552e927ff505dca9d8a1778ee84fb99ea559d1362518176ebcdb913f1ed
3
+ metadata.gz: 44d24b52fdfe7d02d6ad3b0522c1ee9585ce00a1b492394e3935efc155a448a8
4
+ data.tar.gz: 2228cdd496ca320ac3ff47c6c75241027690dbd0b6e51afe880a5a20ea6b6f1f
5
5
  SHA512:
6
- metadata.gz: 794d7cc6f66ddb9320e706810fd7aa6fcc262b81d1599ec7b92e8f265ea835e08568609ca23b5ae2be000a711a0ad07faadce0cdebd2b55ccf6289a526e48efb
7
- data.tar.gz: e701b46e2c20799a2fd53a4be1baadf650179b5ca5ee4d01377aebe8a39c049a287d688595100e4bca0653edafb0bcfef4d868a94b0643edc44a45e29eb14066
6
+ metadata.gz: 302740a2be98c79359fc6f66edd36e6cb050174213c2ea18df4ccc5f9d76554aefa853e3794fb66f7fffdd037a7af49d3b542471d8b8c6c5316cc2b7800b8979
7
+ data.tar.gz: 691e0059b612ba71835f92d03ae9a88476110b395fe452c0c11c1b8015a6ceb460ef2daeccae2b0b9e43a59be75c46862c3ac60d96c7595ea5931868890d1638
@@ -22,7 +22,7 @@ module SynsbasenApi
22
22
  def get(path, params: {}, expand: [])
23
23
  request = build_request(path, method: Net::HTTP::Get, params: params, expand: expand)
24
24
 
25
- response = connection.request(request)
25
+ response = perform_request(request)
26
26
 
27
27
  raise_errors(response)
28
28
 
@@ -42,7 +42,7 @@ module SynsbasenApi
42
42
  def post(path, params: {}, body: {}, expand: [])
43
43
  request = build_request(path, method: Net::HTTP::Post, params: params, body: body, expand: expand)
44
44
 
45
- response = connection.request(request)
45
+ response = perform_request(request)
46
46
 
47
47
  raise_errors(response)
48
48
 
@@ -61,7 +61,7 @@ module SynsbasenApi
61
61
  def delete(path, params = {}, body = {})
62
62
  request = build_request(path, method: Net::HTTP::Delete, params: params, body: body)
63
63
 
64
- response = connection.request(request)
64
+ response = perform_request(request)
65
65
 
66
66
  raise_errors(response)
67
67
 
@@ -79,6 +79,7 @@ module SynsbasenApi
79
79
  uri = URI.parse(SynsbasenApi.config[:base_url] || DEFAULT_BASE_URL)
80
80
  http = Net::HTTP.new(uri.host, uri.port)
81
81
  http.use_ssl = uri.scheme == "https"
82
+ http.max_retries = 0 # Consumers own the retry policy.
82
83
  http
83
84
  end
84
85
 
@@ -106,29 +107,44 @@ module SynsbasenApi
106
107
  request
107
108
  end
108
109
 
110
+ # Sends a request and translates transport-level timeouts into a public gem error.
111
+ #
112
+ # @param request [Net::HTTPRequest] The request to send.
113
+ # @return [Net::HTTPResponse] The response returned by the API.
114
+ # @raise [RequestTimeoutError] Raised when the request times out before a response is received.
115
+ def perform_request(request)
116
+ connection.request(request)
117
+ rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout => e
118
+ raise RequestTimeoutError.new(e.message)
119
+ end
120
+
109
121
  # Raises specific errors based on the type of Net::HTTP error encountered.
110
122
  #
111
- # @param e [Exception] The exception to handle.
112
- # @raise [ClientError, ServerError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, InternalServerError] Raised for errors.
123
+ # @param response [Net::HTTPResponse] The response to handle.
124
+ # @raise [ClientError, ServerError, BadRequestError, UnauthorizedError, ForbiddenError, NotFoundError, ConflictError, UnprocessableEntityError, RequestTimeoutError, GatewayTimeoutError, InternalServerError] Raised for errors.
113
125
  def raise_errors(response)
114
126
  return unless response.is_a?(Net::HTTPClientError) || response.is_a?(Net::HTTPServerError)
115
127
 
116
- case response
117
- when Net::HTTPUnauthorized
118
- raise ClientError.new(response.message, response.code, {})
119
- else
120
- error_class_name = "#{response.message.split.map(&:capitalize).join}Error"
121
-
122
- error_class =
123
- if SynsbasenApi.const_defined?(error_class_name, false) &&
124
- SynsbasenApi.const_get(error_class_name).is_a?(Class)
125
- SynsbasenApi.const_get(error_class_name)
126
- else
127
- response.is_a?(Net::HTTPClientError) ? ClientError : ServerError
128
- end
128
+ error_class = {
129
+ "400" => BadRequestError,
130
+ "401" => UnauthorizedError,
131
+ "403" => ForbiddenError,
132
+ "404" => NotFoundError,
133
+ "408" => RequestTimeoutError,
134
+ "409" => ConflictError,
135
+ "422" => UnprocessableEntityError,
136
+ "500" => InternalServerError,
137
+ "504" => GatewayTimeoutError
138
+ }[response.code] || (response.is_a?(Net::HTTPClientError) ? ClientError : ServerError)
139
+
140
+ raise error_class.new(response.message, response.code, parse_error_body(response.body))
141
+ end
129
142
 
130
- raise error_class.new(response.message, response.code, parse_json(response.body))
131
- end
143
+ # An HTML/text error page must not hide the HTTP error behind a JSON parser error.
144
+ def parse_error_body(body)
145
+ parse_json(body)
146
+ rescue JSON::ParserError
147
+ {}
132
148
  end
133
149
 
134
150
  # Calls the after_request callback if configured in the SynsbasenApi.
@@ -146,7 +162,7 @@ module SynsbasenApi
146
162
  # @param data [String] The JSON string to parse.
147
163
  # @return [Hash] The parsed JSON string as a hash with symbolized keys.
148
164
  def parse_json(data)
149
- data ||= "{}"
165
+ return {} if data.nil? || data.empty?
150
166
 
151
167
  deep_symbolize_keys(JSON.parse(data))
152
168
  end
@@ -30,6 +30,13 @@ module SynsbasenApi
30
30
  # The `ServerError` class represents errors that occur on the server side (5xx status codes).
31
31
  class ServerError < Error; end
32
32
 
33
+ # The `RequestTimeoutError` class represents requests that did not complete within the
34
+ # configured timeout, including HTTP 408 responses and transport-level timeouts.
35
+ class RequestTimeoutError < Error; end
36
+
37
+ # The `GatewayTimeoutError` class represents an HTTP 504 response from the API.
38
+ class GatewayTimeoutError < RequestTimeoutError; end
39
+
33
40
  %w[BadRequestError UnauthorizedError ForbiddenError NotFoundError
34
41
  ConflictError UnprocessableEntityError].each do |error|
35
42
  klass = Class.new(ClientError)
@@ -2,5 +2,5 @@
2
2
 
3
3
  module SynsbasenApi
4
4
  # The `VERSION` module specifies the version of the SynsbasenApi gem.
5
- VERSION = "1.0.13"
5
+ VERSION = "1.0.15"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synsbasen_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.13
4
+ version: 1.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Poulsen
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2025-09-30 00:00:00.000000000 Z
12
+ date: 2026-09-24 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Synsbasen API is the easiest way to get access to the Danish vehicle
15
15
  registry. See https://api.synsbasen.dk for details.