Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
- Add new request: Update a job's cell.
- Add new request: Delete a collection's item.
- Fetch the details for the given user.
- Add `KazeClient.configure` to centrally set headers added to every request.
- Send a default `User-Agent` header (`kaze_client/<version>`) on every request.
- Allow passing `headers:` to `KazeClient::Client.new` to add headers to every request from that client.

## [0.4.0] - 2023-09-12

Expand Down
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ gem 'rake', '~> 13.0'

gem 'rspec', '~> 3.0'

gem 'webmock', '~> 3.0'

gem 'rubocop', '~> 1.30'

gem 'rubocop-rake', '~> 0.6.0'
Expand Down
14 changes: 14 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@ PATH
GEM
remote: https://rubygems.org/
specs:
addressable (2.9.0)
public_suffix (>= 2.0.2, < 8.0)
ast (2.4.2)
base64 (0.1.1)
bigdecimal (4.1.2)
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
crack (1.0.1)
bigdecimal
rexml
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
diff-lcs (1.5.0)
hashdiff (1.2.1)
httparty (0.21.0)
mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2)
Expand All @@ -37,6 +44,7 @@ GEM
racc
psych (5.1.0)
stringio
public_suffix (7.0.5)
racc (1.7.1)
rainbow (3.1.1)
rake (13.0.6)
Expand Down Expand Up @@ -81,11 +89,16 @@ GEM
stringio (3.0.8)
thor (1.2.2)
unicode-display_width (2.4.2)
webmock (3.26.2)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
yard (0.9.36)

PLATFORMS
aarch64-linux
arm64-darwin-22
arm64-darwin-24
x86_64-darwin-20

DEPENDENCIES
Expand All @@ -97,6 +110,7 @@ DEPENDENCIES
rubocop (~> 1.30)
rubocop-rake (~> 0.6.0)
rubocop-rspec (~> 2.11.1)
webmock (~> 3.0)
yard (~> 0.9.36)

BUNDLED WITH
Expand Down
1 change: 1 addition & 0 deletions lib/kaze_client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require_relative 'kaze_client/version'

# Require the different parts of the gem
require_relative 'kaze_client/configuration'
require_relative 'kaze_client/json_utils'
require_relative 'kaze_client/data_utils'
require_relative 'kaze_client/errors'
Expand Down
9 changes: 8 additions & 1 deletion lib/kaze_client/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ class Client
# @return [String,nil] The last authentication token
# @see KazeClient::Client#login
attr_reader :token
# @return [Hash] Headers added to every request executed by this client
attr_reader :headers

# @param base_url [String] The server's base URL (e.g. https://app.kaze.so)
# @param token [String] The authentication token
def initialize(base_url, token: nil)
# @param headers [Hash] Headers added to every request executed by this client.
# They override the default and globally configured headers but are overridden by
# per-request headers.
def initialize(base_url, token: nil, headers: {})
@base_url = base_url
@token = token
@headers = headers || {}
@login = nil
@password = nil
end
Expand Down Expand Up @@ -98,6 +104,7 @@ def do_execute(request)
raise Error::NoEndpoint, @base_url if @base_url.blank?

@request = request
@request.with_client_headers(@headers)

request_url = "#{@base_url}/#{request.url}"
@response = HTTParty.send(request.method, request_url, **@request.parameters)
Expand Down
60 changes: 60 additions & 0 deletions lib/kaze_client/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

module KazeClient

# Holds the global configuration shared by every request.
#
# The most common use case is to add custom headers that must be sent on
# every request to the Kaze API (e.g. an API key, a tracing header, ...).
#
# @see KazeClient.configure
# @since 0.4.0
# @example Configure custom headers added to every request
# KazeClient.configure do |config|
# config.headers['X-Api-Key'] = 'my-api-key'
# config.headers['X-Request-Id'] = SecureRandom.uuid
# end
class Configuration

# @return [Hash] The headers added to every request.
# These are merged after +KazeClient::Request::DEFAULT_HEADERS+ but before
# the per-request headers, so a per-request header still takes precedence.
attr_accessor :headers

def initialize
@headers = {}
end

end

class << self

# @return [KazeClient::Configuration] The global configuration object.
def configuration
@configuration ||= Configuration.new
end

# Configure the client globally.
#
# @yieldparam config [KazeClient::Configuration] The configuration to mutate.
# @return [KazeClient::Configuration] The configuration after the block ran.
# @example
# KazeClient.configure do |config|
# config.headers['X-Api-Key'] = 'my-api-key'
# end
def configure
yield(configuration) if block_given?

configuration
end

# Reset the global configuration back to its defaults.
#
# @return [KazeClient::Configuration] The fresh configuration object.
def reset_configuration!
@configuration = Configuration.new
end

end

end
39 changes: 29 additions & 10 deletions lib/kaze_client/request/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ class Request
# Those headers are added on all requests by default
DEFAULT_HEADERS = {
'Content-Type' => 'application/json',
'Accept' => 'application/json'
'Accept' => 'application/json',
'User-Agent' => "kaze_client/#{KazeClient::VERSION}"
}.freeze

# @return [String, Symbol] The HTTP verb to use for the request
Expand Down Expand Up @@ -44,11 +45,24 @@ class Request
# @param method [Symbol] The HTTP verb to use for the request (e.g. :get)
# @param url [String] The API endpoint (e.g. /jobs)
def initialize(method, url)
@method = method
@url = url
@query = nil
@body = nil
@headers = {}
@method = method
@url = url
@query = nil
@body = nil
@headers = {}
@client_headers = {}
end

# Store the headers configured on the executing client so they can be merged
# into the request. Called by KazeClient::Client at execution time.
#
# @param headers [Hash, nil] The client-level headers
# @return [KazeClient::Request] self (to chain methods)
# @see KazeClient::Client
def with_client_headers(headers)
@client_headers = headers.is_a?(Hash) ? headers : {}

self
end

# @return [Hash] The arguments to give to the HTTParty call
Expand Down Expand Up @@ -77,12 +91,17 @@ def error_for(response)
protected

# @return [Hash] The headers for the request
# If +@headers+ is blank or is not a Hash, it returns the +DEFAULT_HEADERS+. Else it merges
# the +DEFAULT_HEADERS+ with +@headers+ allowing +@headers+ to override +DEFAULT_HEADERS+.
# Headers are merged with the following precedence (later overrides earlier):
# +DEFAULT_HEADERS+, the globally configured headers (+KazeClient.configuration.headers+),
# the client-level headers (+KazeClient::Client.new(headers:)+), then the per-request +@headers+.
# @see KazeClient.configure
# @see KazeClient::Client
def make_headers
return DEFAULT_HEADERS if @headers.blank? || !@headers.is_a?(Hash)
base = DEFAULT_HEADERS.merge(KazeClient.configuration.headers).merge(@client_headers)

return base if @headers.blank? || !@headers.is_a?(Hash)

DEFAULT_HEADERS.merge(@headers)
base.merge(@headers)
end

# @return [nil, String] The body for the request
Expand Down
92 changes: 92 additions & 0 deletions spec/fixtures/job.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"id": "c616f8de-7d7e-4a35-96c9-41c1345a6234",
"title": "Test with widget",
"reference": "",
"owner_id": "0b0cc46c-03b6-4033-91ab-6da31f1a403b",
"target_id": "0b0cc46c-03b6-4033-91ab-6da31f1a403b",
"job_workflow_id": "03e70f4d-e9bf-4e14-a9a1-d45aff5832ff",
"status": "assigned",
"current_step_id": "41c569e7-16ea-4207-852d-f66203dcd163",
"first_not_completed_step_id": null,
"watcher_ids": [],
"owner_name": "Test",
"target_name": "Test",
"own": false,
"annex": false,
"annex_performers": [],
"supervisors": [],
"status_name": "Assigned",
"restrict_completed_update": false,
"restrict_cancelled_update": false,
"assigned_tag_ids": [],
"tags": [],
"workflow": {
"type": "workflow",
"id": "caaa82de-7240-4214-8ca4-b43df00a5d49",
"children": [
{
"type": "template_job_info",
"id": "41c569e7-16ea-4207-852d-f66203dcd163",
"label": "Job Summary",
"access": 133,
"sms_link": true,
"sms_sender": "Kaze",
"display_expanded": true,
"generate_documents": [],
"city": "Issy-les-Moulineaux",
"state": "IDF",
"country_code": "fr",
"zip_code": 92130,
"job_title": "Test with widget",
"job_due_date": 1654106520000,
"job_address": "2 Rue Michelet, 92130 Issy-les-Moulineaux, France",
"job_location": "48.8279341,2.2818154",
"performer_estimation": 60,
"files": [],
"rules": []
},
{
"type": "template_blank",
"id": "test_template_blank",
"label": "Template blank",
"access": 133,
"sms_link": true,
"sms_sender": "Kaze",
"display_expanded": true,
"generate_documents": [],
"children": [
{
"type": "section",
"id": "33934fe4-480f-4949-988d-9bd6ab63d0ab",
"access": 111,
"direction": "col",
"children": [
{
"type": "widget_text",
"id": "test_widget_text",
"label": "Test widget text",
"access": 133,
"data_type": "string",
"data": "this is a test."
}
]
}
]
}
],
"access": 0
},
"white_label_id": null,
"due_date": 1654106520000,
"start_date": 1654106520000,
"end_date": 1654110120000,
"job_notes_updated_at": null,
"job_data_updated_at": null,
"created_at": 1654099359647,
"updated_at": 1654099451343,
"bwa_link": "https://staging.kaze.so/b/j/0-kNNEHG1NnwNcdD_rGVIQ",
"work_order_address": {
"address": "2 Rue Michelet, 92130 Issy-les-Moulineaux, France",
"location": "48.827934,2.281815"
}
}
Loading
Loading