From 45bc9e7e7eac9b862b154861dd562b0fd3088966 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 1 Sep 2026 20:30:39 +0000 Subject: [PATCH] fix: Raise a Seam error for a success response that is malformed Every generated route read its resource straight out of res.body, so a 2xx response with an unexpected envelope, a proxy rewrite, a gateway page with a JSON content type, or a renamed response key surfaced as a bare NoMethodError on nil or String from deep inside the resource loader, or as a silent nil. A 3xx passed through untouched because Faraday's RaiseError only covers 400 through 599. The action attempt poll and the paginator's pagination envelope failed the same way, the latter by silently ending iteration. Add Seam::Http::InvalidResponseError and a Seam::Http::Response helper that reads the response key for an object, a list, or the pagination envelope, naming the endpoint, the expected key, and what arrived instead. Generate every route through it, and route the action attempt poll and the paginator through the same helper. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01SQW83gyXeUG61RDrHEky97 --- README.md | 4 + codegen/layouts/partials/client-method.hbs | 4 +- codegen/lib/layouts/client.ts | 3 + codegen/lib/routes.ts | 16 ++- codegen/lib/ruby-client.ts | 1 + lib/seam/action_attempt_resolver.rb | 4 +- lib/seam/base_resource.rb | 42 ++++++ lib/seam/invalid_response_error.rb | 17 +++ lib/seam/paginator.rb | 29 ++-- lib/seam/routes/access_codes.rb | 12 +- lib/seam/routes/access_codes_simulate.rb | 2 +- lib/seam/routes/access_codes_unmanaged.rb | 4 +- lib/seam/routes/access_grants.rb | 10 +- lib/seam/routes/access_grants_unmanaged.rb | 4 +- lib/seam/routes/access_methods.rb | 12 +- lib/seam/routes/access_methods_unmanaged.rb | 4 +- lib/seam/routes/acs_access_groups.rb | 8 +- lib/seam/routes/acs_credentials.rb | 8 +- lib/seam/routes/acs_encoders.rb | 10 +- lib/seam/routes/acs_entrances.rb | 8 +- lib/seam/routes/acs_systems.rb | 6 +- lib/seam/routes/acs_users.rb | 8 +- lib/seam/routes/action_attempts.rb | 4 +- lib/seam/routes/cameras_live_views.rb | 4 +- lib/seam/routes/client_sessions.rb | 8 +- lib/seam/routes/connect_webviews.rb | 6 +- lib/seam/routes/connected_accounts.rb | 4 +- lib/seam/routes/customers.rb | 2 +- lib/seam/routes/devices.rb | 6 +- lib/seam/routes/devices_unmanaged.rb | 4 +- lib/seam/routes/events.rb | 4 +- lib/seam/routes/instant_keys.rb | 4 +- lib/seam/routes/locks.rb | 10 +- lib/seam/routes/locks_simulate.rb | 4 +- lib/seam/routes/media.rb | 2 +- lib/seam/routes/noise_sensors.rb | 2 +- .../routes/noise_sensors_noise_thresholds.rb | 6 +- lib/seam/routes/phones.rb | 4 +- lib/seam/routes/phones_simulate.rb | 2 +- lib/seam/routes/spaces.rb | 10 +- lib/seam/routes/thermostats.rb | 20 +-- lib/seam/routes/thermostats_daily_programs.rb | 4 +- lib/seam/routes/thermostats_schedules.rb | 6 +- lib/seam/routes/user_identities.rb | 16 +-- lib/seam/routes/user_identities_unmanaged.rb | 4 +- lib/seam/routes/webhooks.rb | 6 +- lib/seam/routes/workspaces.rb | 8 +- spec/seam_client/invalid_response_spec.rb | 132 ++++++++++++++++++ spec/seam_error_spec.rb | 1 + 49 files changed, 356 insertions(+), 143 deletions(-) create mode 100644 lib/seam/invalid_response_error.rb create mode 100644 spec/seam_client/invalid_response_spec.rb diff --git a/README.md b/README.md index c442e7c2..6d69f1cc 100644 --- a/README.md +++ b/README.md @@ -390,6 +390,10 @@ described under [Webhooks](#webhooks). Requests rejected by the Seam API raise a `Seam::Http::ApiError` subclass carrying the HTTP `status_code`, API error `code`, and `request_id`. +A successful response that does not carry the resource the endpoint returns, +for example when a proxy rewrites the body, +raises a `Seam::Http::InvalidResponseError` exposing the request `path` +and the `response_key` the SDK expected. #### Validation errors diff --git a/codegen/layouts/partials/client-method.hbs b/codegen/layouts/partials/client-method.hbs index e7fac82a..d53c7798 100644 --- a/codegen/layouts/partials/client-method.hbs +++ b/codegen/layouts/partials/client-method.hbs @@ -17,13 +17,13 @@ {{/if}} {{#if usesRes}}res = {{/if}}@client.{{httpMethod}}("{{path}}"{{#if hasParams}}, {{bodyParams}}.compact{{/if}}) {{#if isResource}} - Seam::Resources::{{returnResource}}.load_from_response(res.body["{{returnPath}}"]) + Seam::Resources::{{returnResource}}.{{readMethod}}(res, "{{returnPath}}", "{{path}}") {{/if}} {{#if isPoll}} wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["{{returnPath}}"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "{{returnPath}}", "{{path}}"), @client, wait_for_action_attempt) {{/if}} {{#if isNil}} diff --git a/codegen/lib/layouts/client.ts b/codegen/lib/layouts/client.ts index a6bb5b07..7ffc1fca 100644 --- a/codegen/lib/layouts/client.ts +++ b/codegen/lib/layouts/client.ts @@ -29,6 +29,7 @@ export interface ClientMethodLayoutContext { httpMethod: string returnResource: string returnPath: string + readMethod: string } export interface ClientLayoutContext { @@ -47,6 +48,7 @@ const getMethodLayoutContext = ( parameters, returnResource, returnPath, + returnsList, httpMethod, } = method @@ -92,6 +94,7 @@ const getMethodLayoutContext = ( isNil, returnResource: returnResource ?? '', returnPath, + readMethod: returnsList ? 'list_from_http_response' : 'from_http_response', } } diff --git a/codegen/lib/routes.ts b/codegen/lib/routes.ts index 9732b043..af0cfe18 100644 --- a/codegen/lib/routes.ts +++ b/codegen/lib/routes.ts @@ -295,7 +295,9 @@ const getAtLeastOneParameterNames = (endpoint: Endpoint): string[] => : [] const createClientMethod = (endpoint: Endpoint): ClientMethod => { - const { returnPath, returnResource } = getEndpointReturn(endpoint.response) + const { returnPath, returnResource, returnsList } = getEndpointReturn( + endpoint.response, + ) const atLeastOneParameterNames = getAtLeastOneParameterNames(endpoint) return { @@ -322,29 +324,33 @@ const createClientMethod = (endpoint: Endpoint): ClientMethod => { })), returnPath, returnResource, + returnsList, } } const getEndpointReturn = ( response: Response, -): Pick => { +): Pick => { if (response.responseType === 'void') { - return { returnPath: '', returnResource: null } + return { returnPath: '', returnResource: null, returnsList: false } } + const returnsList = response.responseType === 'resource_list' + const { responseKey, resourceType } = response if (resourceType === 'unknown') { // Batch responses hold multiple resource types keyed by batch key, which // the Batch resource models directly. if (responseKey === 'batch') { - return { returnPath: 'batch', returnResource: 'Batch' } + return { returnPath: 'batch', returnResource: 'Batch', returnsList } } - return { returnPath: '', returnResource: null } + return { returnPath: '', returnResource: null, returnsList: false } } return { returnPath: responseKey, returnResource: pascalCase(convertCustomResourceName(resourceType)), + returnsList, } } diff --git a/codegen/lib/ruby-client.ts b/codegen/lib/ruby-client.ts index cd476e99..4027bbb8 100644 --- a/codegen/lib/ruby-client.ts +++ b/codegen/lib/ruby-client.ts @@ -25,6 +25,7 @@ export interface ClientMethod { parameters: ClientMethodParameter[] returnResource: string | null returnPath: string + returnsList: boolean } export interface ChildClientIdentifier { diff --git a/lib/seam/action_attempt_resolver.rb b/lib/seam/action_attempt_resolver.rb index 823987f9..5335fa00 100644 --- a/lib/seam/action_attempt_resolver.rb +++ b/lib/seam/action_attempt_resolver.rb @@ -109,7 +109,9 @@ def self.validate_poll_options(timeout, polling_interval) def self.update_action_attempt(action_attempt, client) response = client.get("/action_attempts/get", {action_attempt_id: action_attempt.action_attempt_id}) - action_attempt.update_from_response(response.body["action_attempt"]) + action_attempt.update_from_response( + Seam::Resources::ActionAttempt.from_http_response(response, "action_attempt", "/action_attempts/get").data + ) action_attempt end diff --git a/lib/seam/base_resource.rb b/lib/seam/base_resource.rb index 7d574615..a45f4428 100644 --- a/lib/seam/base_resource.rb +++ b/lib/seam/base_resource.rb @@ -2,6 +2,7 @@ require "time" require_relative "deep_hash_accessor" +require_relative "invalid_response_error" module Seam module Resources @@ -21,6 +22,47 @@ def update_from_response(data) process_data_attributes(@data) end + def self.from_http_response(response, response_key, path, client = nil) + value = read_http_response_key(response, response_key, path) + + unless value.is_a?(Hash) + raise Http::InvalidResponseError.new(path, response_key, "got #{value.class} instead of an object") + end + + load_from_response(value, client) + end + + def self.list_from_http_response(response, response_key, path, client = nil) + value = read_http_response_key(response, response_key, path) + + unless value.is_a?(Array) + raise Http::InvalidResponseError.new(path, response_key, "got #{value.class} instead of a list") + end + + load_from_response(value, client) + end + + def self.read_http_response_key(response, response_key, path) + unless response.success? + raise Http::InvalidResponseError.new( + path, response_key, "got a #{response.status} response instead of a success response" + ) + end + + body = response.body + + unless body.is_a?(Hash) + raise Http::InvalidResponseError.new(path, response_key, "got #{body.class} instead of a response object") + end + + unless body.key?(response_key) + raise Http::InvalidResponseError.new(path, response_key, "which the response does not contain") + end + + body[response_key] + end + private_class_method :read_http_response_key + def self.load_from_response(data, client = nil) return nil if data.nil? diff --git a/lib/seam/invalid_response_error.rb b/lib/seam/invalid_response_error.rb new file mode 100644 index 00000000..a291b100 --- /dev/null +++ b/lib/seam/invalid_response_error.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require_relative "errors" + +module Seam + module Http + class InvalidResponseError < Seam::Error + attr_reader :path, :response_key + + def initialize(path, response_key, reason) + super("Seam returned an invalid response for #{path}: expected \"#{response_key}\", #{reason}") + @path = path + @response_key = response_key + end + end + end +end diff --git a/lib/seam/paginator.rb b/lib/seam/paginator.rb index f6c1d736..b75d29c5 100644 --- a/lib/seam/paginator.rb +++ b/lib/seam/paginator.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true require "faraday" +require_relative "invalid_response_error" module Seam THREAD_CONTEXT_KEY = :seam_pagination_context - PaginationContext = Struct.new(:pagination) + PaginationContext = Struct.new(:body, :path) class Paginator def initialize(request, params = {}) @@ -60,13 +61,24 @@ def walk end end + def read_pagination(body, path) + unless body.is_a?(Hash) && body.key?("pagination") + raise Http::InvalidResponseError.new(path, "pagination", "which the response does not contain") + end + + pagination = body["pagination"] + return pagination if pagination.is_a?(Hash) + + raise Http::InvalidResponseError.new(path, "pagination", "got #{pagination.class} instead of a pagination object") + end + def fetch_page(params) - context = PaginationContext.new(nil) + context = PaginationContext.new(nil, nil) Thread.current[THREAD_CONTEXT_KEY] = context begin res_data = @request.call(**params) - pagination_result = Pagination.from_hash(context.pagination) + pagination_result = Pagination.from_hash(read_pagination(context.body, context.path)) [res_data, pagination_result] ensure Thread.current[THREAD_CONTEXT_KEY] = nil @@ -95,15 +107,8 @@ def on_complete(env) context = Thread.current[THREAD_CONTEXT_KEY] return unless context.is_a?(PaginationContext) - pagination_hash = extract_pagination(env) - context.pagination = pagination_hash if pagination_hash - end - - private - - def extract_pagination(env) - body = env[:body] - body["pagination"] if body.is_a?(Hash) && body.key?("pagination") + context.body = env[:body] + context.path = env.url.path end end end diff --git a/lib/seam/routes/access_codes.rb b/lib/seam/routes/access_codes.rb index a1ef3624..4c7114fa 100644 --- a/lib/seam/routes/access_codes.rb +++ b/lib/seam/routes/access_codes.rb @@ -44,7 +44,7 @@ def unmanaged def create(device_id:, allow_external_modification: nil, attempt_for_offline_device: nil, code: nil, common_code_key: nil, ends_at: nil, is_external_modification_allowed: nil, is_offline_access_code: nil, is_one_time_use: nil, max_time_rounding: nil, name: nil, prefer_native_scheduling: nil, preferred_code_length: nil, starts_at: nil, use_backup_access_code_pool: nil, use_offline_access_code: nil) res = @client.post("/access_codes/create", {device_id: device_id, allow_external_modification: allow_external_modification, attempt_for_offline_device: attempt_for_offline_device, code: code, common_code_key: common_code_key, ends_at: ends_at, is_external_modification_allowed: is_external_modification_allowed, is_offline_access_code: is_offline_access_code, is_one_time_use: is_one_time_use, max_time_rounding: max_time_rounding, name: name, prefer_native_scheduling: prefer_native_scheduling, preferred_code_length: preferred_code_length, starts_at: starts_at, use_backup_access_code_pool: use_backup_access_code_pool, use_offline_access_code: use_offline_access_code}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["access_code"]) + Seam::Resources::AccessCode.from_http_response(res, "access_code", "/access_codes/create") end # Creates new [access codes](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes) that share a common code across multiple devices. @@ -80,7 +80,7 @@ def create(device_id:, allow_external_modification: nil, attempt_for_offline_dev def create_multiple(device_ids:, allow_external_modification: nil, attempt_for_offline_device: nil, behavior_when_code_cannot_be_shared: nil, code: nil, ends_at: nil, is_external_modification_allowed: nil, name: nil, prefer_native_scheduling: nil, preferred_code_length: nil, starts_at: nil, use_backup_access_code_pool: nil) res = @client.put("/access_codes/create_multiple", {device_ids: device_ids, allow_external_modification: allow_external_modification, attempt_for_offline_device: attempt_for_offline_device, behavior_when_code_cannot_be_shared: behavior_when_code_cannot_be_shared, code: code, ends_at: ends_at, is_external_modification_allowed: is_external_modification_allowed, name: name, prefer_native_scheduling: prefer_native_scheduling, preferred_code_length: preferred_code_length, starts_at: starts_at, use_backup_access_code_pool: use_backup_access_code_pool}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["access_codes"]) + Seam::Resources::AccessCode.list_from_http_response(res, "access_codes", "/access_codes/create_multiple") end # Deletes an [access code](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes). @@ -99,7 +99,7 @@ def delete(access_code_id:, device_id: nil) def generate_code(device_id:) res = @client.get("/access_codes/generate_code", {device_id: device_id}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["generated_code"]) + Seam::Resources::AccessCode.from_http_response(res, "generated_code", "/access_codes/generate_code") end # Returns a specified [access code](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes). @@ -116,7 +116,7 @@ def get(access_code_id: nil, code: nil, device_id: nil) res = @client.get("/access_codes/get", {access_code_id: access_code_id, code: code, device_id: device_id}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["access_code"]) + Seam::Resources::AccessCode.from_http_response(res, "access_code", "/access_codes/get") end # Returns a list of all [access codes](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes). @@ -136,7 +136,7 @@ def get(access_code_id: nil, code: nil, device_id: nil) def list(access_code_ids: nil, access_grant_id: nil, access_grant_key: nil, access_method_id: nil, customer_key: nil, device_id: nil, limit: nil, page_cursor: nil, search: nil, user_identifier_key: nil) res = @client.get("/access_codes/list", {access_code_ids: access_code_ids, access_grant_id: access_grant_id, access_grant_key: access_grant_key, access_method_id: access_method_id, customer_key: customer_key, device_id: device_id, limit: limit, page_cursor: page_cursor, search: search, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["access_codes"]) + Seam::Resources::AccessCode.list_from_http_response(res, "access_codes", "/access_codes/list") end # Retrieves a backup access code for an [access code](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes). See also [Managing Backup Access Codes](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes/backup-access-codes). @@ -153,7 +153,7 @@ def list(access_code_ids: nil, access_grant_id: nil, access_grant_key: nil, acce def pull_backup_access_code(access_code_id:) res = @client.post("/access_codes/pull_backup_access_code", {access_code_id: access_code_id}.compact) - Seam::Resources::AccessCode.load_from_response(res.body["access_code"]) + Seam::Resources::AccessCode.from_http_response(res, "access_code", "/access_codes/pull_backup_access_code") end # Enables you to report access code-related constraints for a device. Currently, supports reporting supported code length constraints for SmartThings devices. diff --git a/lib/seam/routes/access_codes_simulate.rb b/lib/seam/routes/access_codes_simulate.rb index b212ec83..ef2d82c2 100644 --- a/lib/seam/routes/access_codes_simulate.rb +++ b/lib/seam/routes/access_codes_simulate.rb @@ -16,7 +16,7 @@ def initialize(client:, defaults:) def create_unmanaged_access_code(code:, device_id:, name:) res = @client.post("/access_codes/simulate/create_unmanaged_access_code", {code: code, device_id: device_id, name: name}.compact) - Seam::Resources::UnmanagedAccessCode.load_from_response(res.body["access_code"]) + Seam::Resources::UnmanagedAccessCode.from_http_response(res, "access_code", "/access_codes/simulate/create_unmanaged_access_code") end end end diff --git a/lib/seam/routes/access_codes_unmanaged.rb b/lib/seam/routes/access_codes_unmanaged.rb index 50bce702..f905f3eb 100644 --- a/lib/seam/routes/access_codes_unmanaged.rb +++ b/lib/seam/routes/access_codes_unmanaged.rb @@ -47,7 +47,7 @@ def get(access_code_id: nil, code: nil, device_id: nil) res = @client.get("/access_codes/unmanaged/get", {access_code_id: access_code_id, code: code, device_id: device_id}.compact) - Seam::Resources::UnmanagedAccessCode.load_from_response(res.body["access_code"]) + Seam::Resources::UnmanagedAccessCode.from_http_response(res, "access_code", "/access_codes/unmanaged/get") end # Returns a list of all [unmanaged access codes](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes/migrating-existing-access-codes). @@ -60,7 +60,7 @@ def get(access_code_id: nil, code: nil, device_id: nil) def list(device_id:, limit: nil, page_cursor: nil, search: nil, user_identifier_key: nil) res = @client.get("/access_codes/unmanaged/list", {device_id: device_id, limit: limit, page_cursor: page_cursor, search: search, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::UnmanagedAccessCode.load_from_response(res.body["access_codes"]) + Seam::Resources::UnmanagedAccessCode.list_from_http_response(res, "access_codes", "/access_codes/unmanaged/list") end # Updates a specified [unmanaged access code](https://www.seam.co/docs/low-level-apis/smart-locks/access-codes/migrating-existing-access-codes). diff --git a/lib/seam/routes/access_grants.rb b/lib/seam/routes/access_grants.rb index 0e5b3cd5..90957a12 100644 --- a/lib/seam/routes/access_grants.rb +++ b/lib/seam/routes/access_grants.rb @@ -34,7 +34,7 @@ def unmanaged def create(requested_access_methods:, access_grant_key: nil, acs_entrance_ids: nil, customization_profile_id: nil, device_ids: nil, ends_at: nil, location: nil, location_ids: nil, name: nil, reservation_key: nil, space_ids: nil, space_keys: nil, starts_at: nil, user_identity: nil, user_identity_id: nil) res = @client.post("/access_grants/create", {requested_access_methods: requested_access_methods, access_grant_key: access_grant_key, acs_entrance_ids: acs_entrance_ids, customization_profile_id: customization_profile_id, device_ids: device_ids, ends_at: ends_at, location: location, location_ids: location_ids, name: name, reservation_key: reservation_key, space_ids: space_ids, space_keys: space_keys, starts_at: starts_at, user_identity: user_identity, user_identity_id: user_identity_id}.compact) - Seam::Resources::AccessGrant.load_from_response(res.body["access_grant"]) + Seam::Resources::AccessGrant.from_http_response(res, "access_grant", "/access_grants/create") end # Delete an Access Grant. @@ -57,7 +57,7 @@ def get(access_grant_id: nil, access_grant_key: nil) res = @client.get("/access_grants/get", {access_grant_id: access_grant_id, access_grant_key: access_grant_key}.compact) - Seam::Resources::AccessGrant.load_from_response(res.body["access_grant"]) + Seam::Resources::AccessGrant.from_http_response(res, "access_grant", "/access_grants/get") end # Gets all related resources for one or more Access Grants. @@ -73,7 +73,7 @@ def get_related(access_grant_ids: nil, access_grant_keys: nil, exclude: nil, inc res = @client.get("/access_grants/get_related", {access_grant_ids: access_grant_ids, access_grant_keys: access_grant_keys, exclude: exclude, include: include}.compact) - Seam::Resources::Batch.load_from_response(res.body["batch"]) + Seam::Resources::Batch.from_http_response(res, "batch", "/access_grants/get_related") end # Gets an Access Grant. @@ -96,7 +96,7 @@ def get_related(access_grant_ids: nil, access_grant_keys: nil, exclude: nil, inc def list(access_code_id: nil, access_grant_ids: nil, access_grant_key: nil, acs_entrance_id: nil, acs_system_id: nil, customer_key: nil, device_id: nil, limit: nil, location_id: nil, page_cursor: nil, reservation_key: nil, search: nil, space_id: nil, user_identity_id: nil) res = @client.get("/access_grants/list", {access_code_id: access_code_id, access_grant_ids: access_grant_ids, access_grant_key: access_grant_key, acs_entrance_id: acs_entrance_id, acs_system_id: acs_system_id, customer_key: customer_key, device_id: device_id, limit: limit, location_id: location_id, page_cursor: page_cursor, reservation_key: reservation_key, search: search, space_id: space_id, user_identity_id: user_identity_id}.compact) - Seam::Resources::AccessGrant.load_from_response(res.body["access_grants"]) + Seam::Resources::AccessGrant.list_from_http_response(res, "access_grants", "/access_grants/list") end # Adds additional requested access methods to an existing Access Grant. @@ -106,7 +106,7 @@ def list(access_code_id: nil, access_grant_ids: nil, access_grant_key: nil, acs_ def request_access_methods(access_grant_id:, requested_access_methods:) res = @client.post("/access_grants/request_access_methods", {access_grant_id: access_grant_id, requested_access_methods: requested_access_methods}.compact) - Seam::Resources::AccessGrant.load_from_response(res.body["access_grant"]) + Seam::Resources::AccessGrant.from_http_response(res, "access_grant", "/access_grants/request_access_methods") end # Updates an existing Access Grant's time window. diff --git a/lib/seam/routes/access_grants_unmanaged.rb b/lib/seam/routes/access_grants_unmanaged.rb index 89007683..e64484f2 100644 --- a/lib/seam/routes/access_grants_unmanaged.rb +++ b/lib/seam/routes/access_grants_unmanaged.rb @@ -14,7 +14,7 @@ def initialize(client:, defaults:) def get(access_grant_id:) res = @client.get("/access_grants/unmanaged/get", {access_grant_id: access_grant_id}.compact) - Seam::Resources::UnmanagedAccessGrant.load_from_response(res.body["access_grant"]) + Seam::Resources::UnmanagedAccessGrant.from_http_response(res, "access_grant", "/access_grants/unmanaged/get") end # Gets unmanaged Access Grants (where is_managed = false). @@ -29,7 +29,7 @@ def get(access_grant_id:) def list(acs_entrance_id: nil, acs_system_id: nil, customer_key: nil, limit: nil, page_cursor: nil, reservation_key: nil, user_identity_id: nil) res = @client.get("/access_grants/unmanaged/list", {acs_entrance_id: acs_entrance_id, acs_system_id: acs_system_id, customer_key: customer_key, limit: limit, page_cursor: page_cursor, reservation_key: reservation_key, user_identity_id: user_identity_id}.compact) - Seam::Resources::UnmanagedAccessGrant.load_from_response(res.body["access_grants"]) + Seam::Resources::UnmanagedAccessGrant.list_from_http_response(res, "access_grants", "/access_grants/unmanaged/list") end # Updates an unmanaged Access Grant to make it managed. diff --git a/lib/seam/routes/access_methods.rb b/lib/seam/routes/access_methods.rb index d0f7e991..c09a4126 100644 --- a/lib/seam/routes/access_methods.rb +++ b/lib/seam/routes/access_methods.rb @@ -23,7 +23,7 @@ def assign_card(access_method_id:, card_number:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/access_methods/assign_card"), @client, wait_for_action_attempt) end # Deletes an access method. @@ -50,7 +50,7 @@ def encode(access_method_id:, acs_encoder_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/access_methods/encode"), @client, wait_for_action_attempt) end # Gets an access method. @@ -59,7 +59,7 @@ def encode(access_method_id:, acs_encoder_id:, wait_for_action_attempt: nil) def get(access_method_id:) res = @client.get("/access_methods/get", {access_method_id: access_method_id}.compact) - Seam::Resources::AccessMethod.load_from_response(res.body["access_method"]) + Seam::Resources::AccessMethod.from_http_response(res, "access_method", "/access_methods/get") end # Gets all related resources for one or more Access Methods. @@ -70,7 +70,7 @@ def get(access_method_id:) def get_related(access_method_ids:, exclude: nil, include: nil) res = @client.get("/access_methods/get_related", {access_method_ids: access_method_ids, exclude: exclude, include: include}.compact) - Seam::Resources::Batch.load_from_response(res.body["batch"]) + Seam::Resources::Batch.from_http_response(res, "batch", "/access_methods/get_related") end # Lists all access methods, usually filtered by Access Grant. @@ -91,7 +91,7 @@ def list(access_code_id: nil, access_grant_id: nil, access_grant_key: nil, acs_e res = @client.get("/access_methods/list", {access_code_id: access_code_id, access_grant_id: access_grant_id, access_grant_key: access_grant_key, acs_entrance_id: acs_entrance_id, customer_key: customer_key, device_id: device_id, limit: limit, page_cursor: page_cursor, space_id: space_id}.compact) - Seam::Resources::AccessMethod.load_from_response(res.body["access_methods"]) + Seam::Resources::AccessMethod.list_from_http_response(res, "access_methods", "/access_methods/list") end # Remotely unlocks a specified [entrance](https://www.seam.co/docs/low-level-apis/access-systems/retrieving-entrance-details) using the cloud key credential associated with an access method. Returns an action attempt that tracks the progress of the unlock operation. @@ -103,7 +103,7 @@ def unlock_door(access_method_id:, acs_entrance_id:, wait_for_action_attempt: ni wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/access_methods/unlock_door"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/access_methods_unmanaged.rb b/lib/seam/routes/access_methods_unmanaged.rb index b63fc072..a7110a75 100644 --- a/lib/seam/routes/access_methods_unmanaged.rb +++ b/lib/seam/routes/access_methods_unmanaged.rb @@ -14,7 +14,7 @@ def initialize(client:, defaults:) def get(access_method_id:) res = @client.get("/access_methods/unmanaged/get", {access_method_id: access_method_id}.compact) - Seam::Resources::UnmanagedAccessMethod.load_from_response(res.body["access_method"]) + Seam::Resources::UnmanagedAccessMethod.from_http_response(res, "access_method", "/access_methods/unmanaged/get") end # Lists all unmanaged access methods (where is_managed = false), usually filtered by Access Grant. @@ -26,7 +26,7 @@ def get(access_method_id:) def list(access_grant_id:, acs_entrance_id: nil, device_id: nil, space_id: nil) res = @client.get("/access_methods/unmanaged/list", {access_grant_id: access_grant_id, acs_entrance_id: acs_entrance_id, device_id: device_id, space_id: space_id}.compact) - Seam::Resources::UnmanagedAccessMethod.load_from_response(res.body["access_methods"]) + Seam::Resources::UnmanagedAccessMethod.list_from_http_response(res, "access_methods", "/access_methods/unmanaged/list") end end end diff --git a/lib/seam/routes/acs_access_groups.rb b/lib/seam/routes/acs_access_groups.rb index 15efec93..4ce9eb2b 100644 --- a/lib/seam/routes/acs_access_groups.rb +++ b/lib/seam/routes/acs_access_groups.rb @@ -34,7 +34,7 @@ def delete(acs_access_group_id:) def get(acs_access_group_id:) res = @client.get("/acs/access_groups/get", {acs_access_group_id: acs_access_group_id}.compact) - Seam::Resources::AcsAccessGroup.load_from_response(res.body["acs_access_group"]) + Seam::Resources::AcsAccessGroup.from_http_response(res, "acs_access_group", "/acs/access_groups/get") end # Returns a list of all [access groups](https://www.seam.co/docs/low-level-apis/access-systems/user-management/assigning-users-to-access-groups). @@ -46,7 +46,7 @@ def get(acs_access_group_id:) def list(acs_system_id: nil, acs_user_id: nil, search: nil, user_identity_id: nil) res = @client.get("/acs/access_groups/list", {acs_system_id: acs_system_id, acs_user_id: acs_user_id, search: search, user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsAccessGroup.load_from_response(res.body["acs_access_groups"]) + Seam::Resources::AcsAccessGroup.list_from_http_response(res, "acs_access_groups", "/acs/access_groups/list") end # Returns a list of all accessible entrances for a specified [access group](https://www.seam.co/docs/low-level-apis/access-systems/user-management/assigning-users-to-access-groups). @@ -55,7 +55,7 @@ def list(acs_system_id: nil, acs_user_id: nil, search: nil, user_identity_id: ni def list_accessible_entrances(acs_access_group_id:) res = @client.get("/acs/access_groups/list_accessible_entrances", {acs_access_group_id: acs_access_group_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrances"]) + Seam::Resources::AcsEntrance.list_from_http_response(res, "acs_entrances", "/acs/access_groups/list_accessible_entrances") end # Returns a list of all [access system users](https://www.seam.co/docs/low-level-apis/access-systems/user-management) in an [access group](https://www.seam.co/docs/low-level-apis/access-systems/user-management/assigning-users-to-access-groups). @@ -64,7 +64,7 @@ def list_accessible_entrances(acs_access_group_id:) def list_users(acs_access_group_id:) res = @client.get("/acs/access_groups/list_users", {acs_access_group_id: acs_access_group_id}.compact) - Seam::Resources::AcsUser.load_from_response(res.body["acs_users"]) + Seam::Resources::AcsUser.list_from_http_response(res, "acs_users", "/acs/access_groups/list_users") end # Removes a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management) from a specified [access group](https://www.seam.co/docs/low-level-apis/access-systems/user-management/assigning-users-to-access-groups). diff --git a/lib/seam/routes/acs_credentials.rb b/lib/seam/routes/acs_credentials.rb index 160c2e3f..3c455055 100644 --- a/lib/seam/routes/acs_credentials.rb +++ b/lib/seam/routes/acs_credentials.rb @@ -37,7 +37,7 @@ def assign(acs_credential_id:, acs_user_id: nil, user_identity_id: nil) def create(access_method:, acs_system_id: nil, acs_user_id: nil, allowed_acs_entrance_ids: nil, assa_abloy_vostio_metadata: nil, code: nil, credential_manager_acs_system_id: nil, ends_at: nil, is_multi_phone_sync_credential: nil, salto_space_metadata: nil, starts_at: nil, user_identity_id: nil, visionline_metadata: nil) res = @client.post("/acs/credentials/create", {access_method: access_method, acs_system_id: acs_system_id, acs_user_id: acs_user_id, allowed_acs_entrance_ids: allowed_acs_entrance_ids, assa_abloy_vostio_metadata: assa_abloy_vostio_metadata, code: code, credential_manager_acs_system_id: credential_manager_acs_system_id, ends_at: ends_at, is_multi_phone_sync_credential: is_multi_phone_sync_credential, salto_space_metadata: salto_space_metadata, starts_at: starts_at, user_identity_id: user_identity_id, visionline_metadata: visionline_metadata}.compact) - Seam::Resources::AcsCredential.load_from_response(res.body["acs_credential"]) + Seam::Resources::AcsCredential.from_http_response(res, "acs_credential", "/acs/credentials/create") end # Deletes a specified [credential](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials). @@ -55,7 +55,7 @@ def delete(acs_credential_id:) def get(acs_credential_id:) res = @client.get("/acs/credentials/get", {acs_credential_id: acs_credential_id}.compact) - Seam::Resources::AcsCredential.load_from_response(res.body["acs_credential"]) + Seam::Resources::AcsCredential.from_http_response(res, "acs_credential", "/acs/credentials/get") end # Returns a list of all [credentials](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials). @@ -71,7 +71,7 @@ def get(acs_credential_id:) def list(acs_system_id: nil, acs_user_id: nil, created_before: nil, is_multi_phone_sync_credential: nil, limit: nil, page_cursor: nil, search: nil, user_identity_id: nil) res = @client.get("/acs/credentials/list", {acs_system_id: acs_system_id, acs_user_id: acs_user_id, created_before: created_before, is_multi_phone_sync_credential: is_multi_phone_sync_credential, limit: limit, page_cursor: page_cursor, search: search, user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsCredential.load_from_response(res.body["acs_credentials"]) + Seam::Resources::AcsCredential.list_from_http_response(res, "acs_credentials", "/acs/credentials/list") end # Returns a list of all [entrances](https://www.seam.co/docs/api/acs/entrances/object) to which a [credential](https://www.seam.co/docs/api/acs/credentials/object) grants access. @@ -80,7 +80,7 @@ def list(acs_system_id: nil, acs_user_id: nil, created_before: nil, is_multi_pho def list_accessible_entrances(acs_credential_id:) res = @client.get("/acs/credentials/list_accessible_entrances", {acs_credential_id: acs_credential_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrances"]) + Seam::Resources::AcsEntrance.list_from_http_response(res, "acs_entrances", "/acs/credentials/list_accessible_entrances") end # Unassigns a specified [credential](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials) from a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management). diff --git a/lib/seam/routes/acs_encoders.rb b/lib/seam/routes/acs_encoders.rb index 5398c4a5..600b35ef 100644 --- a/lib/seam/routes/acs_encoders.rb +++ b/lib/seam/routes/acs_encoders.rb @@ -24,7 +24,7 @@ def encode_credential(acs_encoder_id:, access_method_id: nil, acs_credential_id: wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/acs/encoders/encode_credential"), @client, wait_for_action_attempt) end # Returns a specified [encoder](https://www.seam.co/docs/low-level-apis/access-systems/working-with-card-encoders-and-scanners). @@ -33,7 +33,7 @@ def encode_credential(acs_encoder_id:, access_method_id: nil, acs_credential_id: def get(acs_encoder_id:) res = @client.get("/acs/encoders/get", {acs_encoder_id: acs_encoder_id}.compact) - Seam::Resources::AcsEncoder.load_from_response(res.body["acs_encoder"]) + Seam::Resources::AcsEncoder.from_http_response(res, "acs_encoder", "/acs/encoders/get") end # Returns a list of all [encoders](https://www.seam.co/docs/low-level-apis/access-systems/working-with-card-encoders-and-scanners). @@ -46,7 +46,7 @@ def get(acs_encoder_id:) def list(acs_encoder_ids: nil, acs_system_id: nil, acs_system_ids: nil, limit: nil, page_cursor: nil) res = @client.get("/acs/encoders/list", {acs_encoder_ids: acs_encoder_ids, acs_system_id: acs_system_id, acs_system_ids: acs_system_ids, limit: limit, page_cursor: page_cursor}.compact) - Seam::Resources::AcsEncoder.load_from_response(res.body["acs_encoders"]) + Seam::Resources::AcsEncoder.list_from_http_response(res, "acs_encoders", "/acs/encoders/list") end # Scans an encoded [acs_credential](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials) from a plastic card placed on the specified [encoder](https://www.seam.co/docs/low-level-apis/access-systems/working-with-card-encoders-and-scanners). @@ -58,7 +58,7 @@ def scan_credential(acs_encoder_id:, salto_ks_metadata: nil, wait_for_action_att wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/acs/encoders/scan_credential"), @client, wait_for_action_attempt) end # Scans a physical card placed on the specified [encoder](https://www.seam.co/docs/low-level-apis/access-systems/working-with-card-encoders-and-scanners) and assigns the scanned credential to an ACS user. Provide either an `acs_user_id` or a `user_identity_id`. @@ -72,7 +72,7 @@ def scan_to_assign_credential(acs_encoder_id:, acs_user_id: nil, salto_ks_metada wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/acs/encoders/scan_to_assign_credential"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/acs_entrances.rb b/lib/seam/routes/acs_entrances.rb index d324c365..2d7ed9b9 100644 --- a/lib/seam/routes/acs_entrances.rb +++ b/lib/seam/routes/acs_entrances.rb @@ -16,7 +16,7 @@ def initialize(client:, defaults:) def get(acs_entrance_id:) res = @client.get("/acs/entrances/get", {acs_entrance_id: acs_entrance_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrance"]) + Seam::Resources::AcsEntrance.from_http_response(res, "acs_entrance", "/acs/entrances/get") end # Grants a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management) access to a specified [access system entrance](https://www.seam.co/docs/low-level-apis/access-systems/retrieving-entrance-details). @@ -47,7 +47,7 @@ def grant_access(acs_entrance_id:, acs_user_id: nil, user_identity_id: nil) def list(access_method_id: nil, acs_credential_id: nil, acs_entrance_ids: nil, acs_system_id: nil, connected_account_id: nil, customer_key: nil, limit: nil, location_id: nil, page_cursor: nil, search: nil, space_id: nil) res = @client.get("/acs/entrances/list", {access_method_id: access_method_id, acs_credential_id: acs_credential_id, acs_entrance_ids: acs_entrance_ids, acs_system_id: acs_system_id, connected_account_id: connected_account_id, customer_key: customer_key, limit: limit, location_id: location_id, page_cursor: page_cursor, search: search, space_id: space_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrances"]) + Seam::Resources::AcsEntrance.list_from_http_response(res, "acs_entrances", "/acs/entrances/list") end # Returns a list of all [credentials](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials) with access to a specified [entrance](https://www.seam.co/docs/low-level-apis/access-systems/retrieving-entrance-details). @@ -57,7 +57,7 @@ def list(access_method_id: nil, acs_credential_id: nil, acs_entrance_ids: nil, a def list_credentials_with_access(acs_entrance_id:, include_if: nil) res = @client.get("/acs/entrances/list_credentials_with_access", {acs_entrance_id: acs_entrance_id, include_if: include_if}.compact) - Seam::Resources::AcsCredential.load_from_response(res.body["acs_credentials"]) + Seam::Resources::AcsCredential.list_from_http_response(res, "acs_credentials", "/acs/entrances/list_credentials_with_access") end # Remotely unlocks a specified [entrance](https://www.seam.co/docs/low-level-apis/access-systems/retrieving-entrance-details) using a cloud_key credential. Returns an action attempt that tracks the progress of the unlock operation. @@ -69,7 +69,7 @@ def unlock(acs_credential_id:, acs_entrance_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/acs/entrances/unlock"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/acs_systems.rb b/lib/seam/routes/acs_systems.rb index 712a1fe3..94974715 100644 --- a/lib/seam/routes/acs_systems.rb +++ b/lib/seam/routes/acs_systems.rb @@ -14,7 +14,7 @@ def initialize(client:, defaults:) def get(acs_system_id:) res = @client.get("/acs/systems/get", {acs_system_id: acs_system_id}.compact) - Seam::Resources::AcsSystem.load_from_response(res.body["acs_system"]) + Seam::Resources::AcsSystem.from_http_response(res, "acs_system", "/acs/systems/get") end # Returns a list of all [access systems](https://www.seam.co/docs/low-level-apis/access-systems). @@ -27,7 +27,7 @@ def get(acs_system_id:) def list(connected_account_id: nil, customer_key: nil, search: nil) res = @client.get("/acs/systems/list", {connected_account_id: connected_account_id, customer_key: customer_key, search: search}.compact) - Seam::Resources::AcsSystem.load_from_response(res.body["acs_systems"]) + Seam::Resources::AcsSystem.list_from_http_response(res, "acs_systems", "/acs/systems/list") end # Returns a list of all credential manager systems that are compatible with a specified [access system](https://www.seam.co/docs/low-level-apis/access-systems). @@ -38,7 +38,7 @@ def list(connected_account_id: nil, customer_key: nil, search: nil) def list_compatible_credential_manager_acs_systems(acs_system_id:) res = @client.get("/acs/systems/list_compatible_credential_manager_acs_systems", {acs_system_id: acs_system_id}.compact) - Seam::Resources::AcsSystem.load_from_response(res.body["acs_systems"]) + Seam::Resources::AcsSystem.list_from_http_response(res, "acs_systems", "/acs/systems/list_compatible_credential_manager_acs_systems") end # Reports ACS system device status including encoders and entrances. diff --git a/lib/seam/routes/acs_users.rb b/lib/seam/routes/acs_users.rb index 814017be..847aa0be 100644 --- a/lib/seam/routes/acs_users.rb +++ b/lib/seam/routes/acs_users.rb @@ -32,7 +32,7 @@ def add_to_access_group(acs_access_group_id:, acs_user_id:) def create(acs_system_id:, full_name:, access_schedule: nil, acs_access_group_ids: nil, email: nil, email_address: nil, phone_number: nil, user_identity_id: nil) res = @client.post("/acs/users/create", {acs_system_id: acs_system_id, full_name: full_name, access_schedule: access_schedule, acs_access_group_ids: acs_access_group_ids, email: email, email_address: email_address, phone_number: phone_number, user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsUser.load_from_response(res.body["acs_user"]) + Seam::Resources::AcsUser.from_http_response(res, "acs_user", "/acs/users/create") end # Deletes a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management) and invalidates the access system user's [credentials](https://www.seam.co/docs/low-level-apis/access-systems/managing-credentials). @@ -62,7 +62,7 @@ def get(acs_user_id: nil, acs_system_id: nil, user_identity_id: nil) res = @client.get("/acs/users/get", {acs_user_id: acs_user_id, acs_system_id: acs_system_id, user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsUser.load_from_response(res.body["acs_user"]) + Seam::Resources::AcsUser.from_http_response(res, "acs_user", "/acs/users/get") end # Returns a list of all [access system users](https://www.seam.co/docs/low-level-apis/access-systems/user-management). @@ -78,7 +78,7 @@ def get(acs_user_id: nil, acs_system_id: nil, user_identity_id: nil) def list(acs_system_id: nil, created_before: nil, limit: nil, page_cursor: nil, search: nil, user_identity_email_address: nil, user_identity_id: nil, user_identity_phone_number: nil) res = @client.get("/acs/users/list", {acs_system_id: acs_system_id, created_before: created_before, limit: limit, page_cursor: page_cursor, search: search, user_identity_email_address: user_identity_email_address, user_identity_id: user_identity_id, user_identity_phone_number: user_identity_phone_number}.compact) - Seam::Resources::AcsUser.load_from_response(res.body["acs_users"]) + Seam::Resources::AcsUser.list_from_http_response(res, "acs_users", "/acs/users/list") end # Lists the [entrances](https://www.seam.co/docs/api/acs/entrances/object) to which a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management) has access. @@ -93,7 +93,7 @@ def list_accessible_entrances(acs_system_id: nil, acs_user_id: nil, user_identit res = @client.get("/acs/users/list_accessible_entrances", {acs_system_id: acs_system_id, acs_user_id: acs_user_id, user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrances"]) + Seam::Resources::AcsEntrance.list_from_http_response(res, "acs_entrances", "/acs/users/list_accessible_entrances") end # Removes a specified [access system user](https://www.seam.co/docs/low-level-apis/access-systems/user-management) from a specified [access group](https://www.seam.co/docs/low-level-apis/access-systems/user-management/assigning-users-to-access-groups). diff --git a/lib/seam/routes/action_attempts.rb b/lib/seam/routes/action_attempts.rb index 54ffc737..b667a145 100644 --- a/lib/seam/routes/action_attempts.rb +++ b/lib/seam/routes/action_attempts.rb @@ -18,7 +18,7 @@ def get(action_attempt_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/action_attempts/get"), @client, wait_for_action_attempt) end # Returns a list of the [action attempts](https://www.seam.co/docs/core-concepts/action-attempts) that you specify as an array of `action_attempt_id`s. @@ -30,7 +30,7 @@ def get(action_attempt_id:, wait_for_action_attempt: nil) def list(action_attempt_ids: nil, device_id: nil, limit: nil, page_cursor: nil) res = @client.get("/action_attempts/list", {action_attempt_ids: action_attempt_ids, device_id: device_id, limit: limit, page_cursor: page_cursor}.compact) - Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempts"]) + Seam::Resources::ActionAttempt.list_from_http_response(res, "action_attempts", "/action_attempts/list") end end end diff --git a/lib/seam/routes/cameras_live_views.rb b/lib/seam/routes/cameras_live_views.rb index 1cf5a592..a07b4138 100644 --- a/lib/seam/routes/cameras_live_views.rb +++ b/lib/seam/routes/cameras_live_views.rb @@ -18,7 +18,7 @@ def initialize(client:, defaults:) def create(device_id:, duration_seconds: nil, include_audio: nil) res = @client.post("/cameras/live_views/create", {device_id: device_id, duration_seconds: duration_seconds, include_audio: include_audio}.compact) - Seam::Resources::CameraLiveViewSession.load_from_response(res.body["camera_live_view_session"]) + Seam::Resources::CameraLiveViewSession.from_http_response(res, "camera_live_view_session", "/cameras/live_views/create") end # Exchanges a WebRTC SDP offer for an SDP answer that starts streaming video from the camera, for a live view session that you created using `/cameras/live_views/create`. @@ -31,7 +31,7 @@ def create(device_id:, duration_seconds: nil, include_audio: nil) def offer(camera_live_view_session_id:, sdp_offer:, token:) res = @client.post("/cameras/live_views/offer", {camera_live_view_session_id: camera_live_view_session_id, sdp_offer: sdp_offer, token: token}.compact) - Seam::Resources::CameraLiveViewAnswer.load_from_response(res.body["camera_live_view_answer"]) + Seam::Resources::CameraLiveViewAnswer.from_http_response(res, "camera_live_view_answer", "/cameras/live_views/offer") end # Stops a camera live view session that the current client session owns. diff --git a/lib/seam/routes/client_sessions.rb b/lib/seam/routes/client_sessions.rb index db5f6a18..fe094c8c 100644 --- a/lib/seam/routes/client_sessions.rb +++ b/lib/seam/routes/client_sessions.rb @@ -22,7 +22,7 @@ def initialize(client:, defaults:) def create(connect_webview_ids: nil, connected_account_ids: nil, customer_id: nil, customer_key: nil, expires_at: nil, user_identifier_key: nil, user_identity_id: nil, user_identity_ids: nil) res = @client.put("/client_sessions/create", {connect_webview_ids: connect_webview_ids, connected_account_ids: connected_account_ids, customer_id: customer_id, customer_key: customer_key, expires_at: expires_at, user_identifier_key: user_identifier_key, user_identity_id: user_identity_id, user_identity_ids: user_identity_ids}.compact) - Seam::Resources::ClientSession.load_from_response(res.body["client_session"]) + Seam::Resources::ClientSession.from_http_response(res, "client_session", "/client_sessions/create") end # Deletes a [client session](https://www.seam.co/docs/core-concepts/authentication/client-session-tokens). @@ -41,7 +41,7 @@ def delete(client_session_id:) def get(client_session_id: nil, user_identifier_key: nil) res = @client.get("/client_sessions/get", {client_session_id: client_session_id, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::ClientSession.load_from_response(res.body["client_session"]) + Seam::Resources::ClientSession.from_http_response(res, "client_session", "/client_sessions/get") end # Returns a [client session](https://www.seam.co/docs/core-concepts/authentication/client-session-tokens) with specific characteristics or creates a new client session with these characteristics if it does not yet exist. @@ -56,7 +56,7 @@ def get(client_session_id: nil, user_identifier_key: nil) def get_or_create(connect_webview_ids: nil, connected_account_ids: nil, expires_at: nil, user_identifier_key: nil, user_identity_id: nil, user_identity_ids: nil) res = @client.post("/client_sessions/get_or_create", {connect_webview_ids: connect_webview_ids, connected_account_ids: connected_account_ids, expires_at: expires_at, user_identifier_key: user_identifier_key, user_identity_id: user_identity_id, user_identity_ids: user_identity_ids}.compact) - Seam::Resources::ClientSession.load_from_response(res.body["client_session"]) + Seam::Resources::ClientSession.from_http_response(res, "client_session", "/client_sessions/get_or_create") end # Grants a [client session](https://www.seam.co/docs/core-concepts/authentication/client-session-tokens) access to one or more resources, such as [Connect Webviews](https://www.seam.co/docs/core-concepts/connect-webviews), [user identities](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity), and so on. @@ -88,7 +88,7 @@ def grant_access(client_session_id: nil, connect_webview_ids: nil, connected_acc def list(client_session_id: nil, connect_webview_id: nil, user_identifier_key: nil, user_identity_id: nil, without_user_identifier_key: nil) res = @client.get("/client_sessions/list", {client_session_id: client_session_id, connect_webview_id: connect_webview_id, user_identifier_key: user_identifier_key, user_identity_id: user_identity_id, without_user_identifier_key: without_user_identifier_key}.compact) - Seam::Resources::ClientSession.load_from_response(res.body["client_sessions"]) + Seam::Resources::ClientSession.list_from_http_response(res, "client_sessions", "/client_sessions/list") end # Revokes a [client session](https://www.seam.co/docs/core-concepts/authentication/client-session-tokens). diff --git a/lib/seam/routes/connect_webviews.rb b/lib/seam/routes/connect_webviews.rb index f67fca2f..bbe030e5 100644 --- a/lib/seam/routes/connect_webviews.rb +++ b/lib/seam/routes/connect_webviews.rb @@ -29,7 +29,7 @@ def initialize(client:, defaults:) def create(accepted_capabilities: nil, accepted_providers: nil, automatically_manage_new_devices: nil, custom_metadata: nil, custom_redirect_failure_url: nil, custom_redirect_url: nil, customer_key: nil, excluded_providers: nil, provider_category: nil, wait_for_device_creation: nil) res = @client.post("/connect_webviews/create", {accepted_capabilities: accepted_capabilities, accepted_providers: accepted_providers, automatically_manage_new_devices: automatically_manage_new_devices, custom_metadata: custom_metadata, custom_redirect_failure_url: custom_redirect_failure_url, custom_redirect_url: custom_redirect_url, customer_key: customer_key, excluded_providers: excluded_providers, provider_category: provider_category, wait_for_device_creation: wait_for_device_creation}.compact) - Seam::Resources::ConnectWebview.load_from_response(res.body["connect_webview"]) + Seam::Resources::ConnectWebview.from_http_response(res, "connect_webview", "/connect_webviews/create") end # Deletes a [Connect Webview](https://www.seam.co/docs/core-concepts/connect-webviews). @@ -51,7 +51,7 @@ def delete(connect_webview_id:) def get(connect_webview_id:) res = @client.get("/connect_webviews/get", {connect_webview_id: connect_webview_id}.compact) - Seam::Resources::ConnectWebview.load_from_response(res.body["connect_webview"]) + Seam::Resources::ConnectWebview.from_http_response(res, "connect_webview", "/connect_webviews/get") end # Returns a list of all [Connect Webviews](https://www.seam.co/docs/core-concepts/connect-webviews). @@ -65,7 +65,7 @@ def get(connect_webview_id:) def list(custom_metadata_has: nil, customer_key: nil, limit: nil, page_cursor: nil, search: nil, user_identifier_key: nil) res = @client.get("/connect_webviews/list", {custom_metadata_has: custom_metadata_has, customer_key: customer_key, limit: limit, page_cursor: page_cursor, search: search, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::ConnectWebview.load_from_response(res.body["connect_webviews"]) + Seam::Resources::ConnectWebview.list_from_http_response(res, "connect_webviews", "/connect_webviews/list") end end end diff --git a/lib/seam/routes/connected_accounts.rb b/lib/seam/routes/connected_accounts.rb index f701c127..e2d7219f 100644 --- a/lib/seam/routes/connected_accounts.rb +++ b/lib/seam/routes/connected_accounts.rb @@ -36,7 +36,7 @@ def get(connected_account_id: nil, email: nil) res = @client.get("/connected_accounts/get", {connected_account_id: connected_account_id, email: email}.compact) - Seam::Resources::ConnectedAccount.load_from_response(res.body["connected_account"]) + Seam::Resources::ConnectedAccount.from_http_response(res, "connected_account", "/connected_accounts/get") end # Returns a list of all [connected accounts](https://www.seam.co/docs/core-concepts/connected-accounts). @@ -51,7 +51,7 @@ def get(connected_account_id: nil, email: nil) def list(custom_metadata_has: nil, customer_key: nil, limit: nil, page_cursor: nil, search: nil, space_id: nil, user_identifier_key: nil) res = @client.get("/connected_accounts/list", {custom_metadata_has: custom_metadata_has, customer_key: customer_key, limit: limit, page_cursor: page_cursor, search: search, space_id: space_id, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::ConnectedAccount.load_from_response(res.body["connected_accounts"]) + Seam::Resources::ConnectedAccount.list_from_http_response(res, "connected_accounts", "/connected_accounts/list") end # Request a [connected account](https://www.seam.co/docs/core-concepts/connected-accounts) sync attempt for the specified `connected_account_id`. diff --git a/lib/seam/routes/customers.rb b/lib/seam/routes/customers.rb index 241790d2..ff459959 100644 --- a/lib/seam/routes/customers.rb +++ b/lib/seam/routes/customers.rb @@ -24,7 +24,7 @@ def initialize(client:, defaults:) def create_portal(customer_data: nil, customer_resources_filters: nil, customization_profile_id: nil, deep_link: nil, exclude_locale_picker: nil, features: nil, is_embedded: nil, landing_page: nil, locale: nil, navigation_mode: nil, read_only: nil) res = @client.post("/customers/create_portal", {customer_data: customer_data, customer_resources_filters: customer_resources_filters, customization_profile_id: customization_profile_id, deep_link: deep_link, exclude_locale_picker: exclude_locale_picker, features: features, is_embedded: is_embedded, landing_page: landing_page, locale: locale, navigation_mode: navigation_mode, read_only: read_only}.compact) - Seam::Resources::CustomerPortal.load_from_response(res.body["customer_portal"]) + Seam::Resources::CustomerPortal.from_http_response(res, "customer_portal", "/customers/create_portal") end # Deletes customer data including resources like spaces, properties, rooms, users, etc. diff --git a/lib/seam/routes/devices.rb b/lib/seam/routes/devices.rb index 5b6f78c1..7556c5be 100644 --- a/lib/seam/routes/devices.rb +++ b/lib/seam/routes/devices.rb @@ -29,7 +29,7 @@ def get(device_id: nil, name: nil) res = @client.get("/devices/get", {device_id: device_id, name: name}.compact) - Seam::Resources::Device.load_from_response(res.body["device"]) + Seam::Resources::Device.from_http_response(res, "device", "/devices/get") end # Returns a list of all [devices](https://www.seam.co/docs/core-concepts/devices). @@ -54,7 +54,7 @@ def get(device_id: nil, name: nil) def list(connect_webview_id: nil, connected_account_id: nil, connected_account_ids: nil, created_before: nil, custom_metadata_has: nil, customer_key: nil, device_ids: nil, device_type: nil, device_types: nil, limit: nil, manufacturer: nil, page_cursor: nil, search: nil, space_id: nil, unstable_location_id: nil, user_identifier_key: nil) res = @client.get("/devices/list", {connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, connected_account_ids: connected_account_ids, created_before: created_before, custom_metadata_has: custom_metadata_has, customer_key: customer_key, device_ids: device_ids, device_type: device_type, device_types: device_types, limit: limit, manufacturer: manufacturer, page_cursor: page_cursor, search: search, space_id: space_id, unstable_location_id: unstable_location_id, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::Device.load_from_response(res.body["devices"]) + Seam::Resources::Device.list_from_http_response(res, "devices", "/devices/list") end # Returns a list of all device providers. @@ -67,7 +67,7 @@ def list(connect_webview_id: nil, connected_account_id: nil, connected_account_i def list_device_providers(provider_category: nil) res = @client.get("/devices/list_device_providers", {provider_category: provider_category}.compact) - Seam::Resources::DeviceProvider.load_from_response(res.body["device_providers"]) + Seam::Resources::DeviceProvider.list_from_http_response(res, "device_providers", "/devices/list_device_providers") end # Updates provider-specific metadata for devices. diff --git a/lib/seam/routes/devices_unmanaged.rb b/lib/seam/routes/devices_unmanaged.rb index 6b90d1ab..d67e18bd 100644 --- a/lib/seam/routes/devices_unmanaged.rb +++ b/lib/seam/routes/devices_unmanaged.rb @@ -23,7 +23,7 @@ def get(device_id: nil, name: nil) res = @client.get("/devices/unmanaged/get", {device_id: device_id, name: name}.compact) - Seam::Resources::UnmanagedDevice.load_from_response(res.body["device"]) + Seam::Resources::UnmanagedDevice.from_http_response(res, "device", "/devices/unmanaged/get") end # Returns a list of all [unmanaged devices](https://www.seam.co/docs/core-concepts/devices/managed-and-unmanaged-devices). @@ -45,7 +45,7 @@ def get(device_id: nil, name: nil) def list(connect_webview_id: nil, connected_account_id: nil, connected_account_ids: nil, created_before: nil, customer_key: nil, device_ids: nil, device_type: nil, device_types: nil, limit: nil, manufacturer: nil, page_cursor: nil, search: nil) res = @client.get("/devices/unmanaged/list", {connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, connected_account_ids: connected_account_ids, created_before: created_before, customer_key: customer_key, device_ids: device_ids, device_type: device_type, device_types: device_types, limit: limit, manufacturer: manufacturer, page_cursor: page_cursor, search: search}.compact) - Seam::Resources::UnmanagedDevice.load_from_response(res.body["devices"]) + Seam::Resources::UnmanagedDevice.list_from_http_response(res, "devices", "/devices/unmanaged/list") end # Updates a specified [unmanaged device](https://www.seam.co/docs/core-concepts/devices/managed-and-unmanaged-devices). To convert an unmanaged device to managed, set `is_managed` to `true`. diff --git a/lib/seam/routes/events.rb b/lib/seam/routes/events.rb index e79015d9..04b6801e 100644 --- a/lib/seam/routes/events.rb +++ b/lib/seam/routes/events.rb @@ -20,7 +20,7 @@ def get(event_id: nil, device_id: nil, event_type: nil) res = @client.get("/events/get", {event_id: event_id, device_id: device_id, event_type: event_type}.compact) - Seam::Resources::SeamEvent.load_from_response(res.body["event"]) + Seam::Resources::SeamEvent.from_http_response(res, "event", "/events/get") end # Returns a list of all events. This endpoint returns the same events that would be sent to a [webhook](https://www.seam.co/docs/developer-tools/webhooks), but it enables you to filter or see events that already took place. Only events from the last 90 days are returned. @@ -60,7 +60,7 @@ def list(access_code_id: nil, access_code_ids: nil, access_grant_id: nil, access res = @client.get("/events/list", {access_code_id: access_code_id, access_code_ids: access_code_ids, access_grant_id: access_grant_id, access_grant_ids: access_grant_ids, access_method_id: access_method_id, access_method_ids: access_method_ids, acs_access_group_id: acs_access_group_id, acs_credential_id: acs_credential_id, acs_encoder_id: acs_encoder_id, acs_entrance_id: acs_entrance_id, acs_system_id: acs_system_id, acs_system_ids: acs_system_ids, acs_user_id: acs_user_id, between: between, connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, customer_key: customer_key, device_id: device_id, device_ids: device_ids, event_ids: event_ids, event_type: event_type, event_types: event_types, limit: limit, since: since, space_id: space_id, space_ids: space_ids, unstable_offset: unstable_offset, user_identity_id: user_identity_id}.compact) - Seam::Resources::SeamEvent.load_from_response(res.body["events"]) + Seam::Resources::SeamEvent.list_from_http_response(res, "events", "/events/list") end end end diff --git a/lib/seam/routes/instant_keys.rb b/lib/seam/routes/instant_keys.rb index bed36f30..e4fa3742 100644 --- a/lib/seam/routes/instant_keys.rb +++ b/lib/seam/routes/instant_keys.rb @@ -28,7 +28,7 @@ def get(instant_key_id: nil, instant_key_url: nil) res = @client.get("/instant_keys/get", {instant_key_id: instant_key_id, instant_key_url: instant_key_url}.compact) - Seam::Resources::InstantKey.load_from_response(res.body["instant_key"]) + Seam::Resources::InstantKey.from_http_response(res, "instant_key", "/instant_keys/get") end # Returns a list of all [instant keys](https://www.seam.co/docs/use-cases/granting-access/using-instant-keys). @@ -37,7 +37,7 @@ def get(instant_key_id: nil, instant_key_url: nil) def list(user_identity_id: nil) res = @client.get("/instant_keys/list", {user_identity_id: user_identity_id}.compact) - Seam::Resources::InstantKey.load_from_response(res.body["instant_keys"]) + Seam::Resources::InstantKey.list_from_http_response(res, "instant_keys", "/instant_keys/list") end end end diff --git a/lib/seam/routes/locks.rb b/lib/seam/routes/locks.rb index a8652fb3..e72ed715 100644 --- a/lib/seam/routes/locks.rb +++ b/lib/seam/routes/locks.rb @@ -24,7 +24,7 @@ def configure_auto_lock(auto_lock_enabled:, device_id:, auto_lock_delay_seconds: wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/locks/configure_auto_lock"), @client, wait_for_action_attempt) end # Returns a specified [lock](https://www.seam.co/docs/low-level-apis/smart-locks). @@ -39,7 +39,7 @@ def get(device_id: nil, name: nil) res = @client.get("/locks/get", {device_id: device_id, name: name}.compact) - Seam::Resources::Device.load_from_response(res.body["device"]) + Seam::Resources::Device.from_http_response(res, "device", "/locks/get") end # Returns a list of all [locks](https://www.seam.co/docs/low-level-apis/smart-locks). @@ -53,7 +53,7 @@ def get(device_id: nil, name: nil) def list(connect_webview_id: nil, connected_account_id: nil, customer_key: nil, device_type: nil, device_types: nil, manufacturer: nil) res = @client.get("/locks/list", {connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, customer_key: customer_key, device_type: device_type, device_types: device_types, manufacturer: manufacturer}.compact) - Seam::Resources::Device.load_from_response(res.body["devices"]) + Seam::Resources::Device.list_from_http_response(res, "devices", "/locks/list") end # Locks a [lock](https://www.seam.co/docs/low-level-apis/smart-locks). See also [Locking and Unlocking Smart Locks](https://www.seam.co/docs/low-level-apis/smart-locks/lock-and-unlock). @@ -64,7 +64,7 @@ def lock_door(device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/locks/lock_door"), @client, wait_for_action_attempt) end # Unlocks a [lock](https://www.seam.co/docs/low-level-apis/smart-locks). See also [Locking and Unlocking Smart Locks](https://www.seam.co/docs/low-level-apis/smart-locks/lock-and-unlock). @@ -75,7 +75,7 @@ def unlock_door(device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/locks/unlock_door"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/locks_simulate.rb b/lib/seam/routes/locks_simulate.rb index 716c4871..eb3bf495 100644 --- a/lib/seam/routes/locks_simulate.rb +++ b/lib/seam/routes/locks_simulate.rb @@ -19,7 +19,7 @@ def keypad_code_entry(code:, device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/locks/simulate/keypad_code_entry"), @client, wait_for_action_attempt) end # Simulates a manual lock action using a keypad. You can only perform this action for [August](https://www.seam.co/docs/device-and-system-integration-guides/august-locks) devices within [sandbox workspaces](https://www.seam.co/docs/core-concepts/workspaces#sandbox-workspaces). @@ -30,7 +30,7 @@ def manual_lock_via_keypad(device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/locks/simulate/manual_lock_via_keypad"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/media.rb b/lib/seam/routes/media.rb index 77aedf7a..f46f1643 100644 --- a/lib/seam/routes/media.rb +++ b/lib/seam/routes/media.rb @@ -15,7 +15,7 @@ def initialize(client:, defaults:) def get(media_id:, format: nil) res = @client.get("/media/get", {media_id: media_id, format: format}.compact) - Seam::Resources::Media.load_from_response(res.body["media"]) + Seam::Resources::Media.from_http_response(res, "media", "/media/get") end end end diff --git a/lib/seam/routes/noise_sensors.rb b/lib/seam/routes/noise_sensors.rb index 7446679b..843999af 100644 --- a/lib/seam/routes/noise_sensors.rb +++ b/lib/seam/routes/noise_sensors.rb @@ -27,7 +27,7 @@ def simulate def list(connect_webview_id: nil, connected_account_id: nil, customer_key: nil, device_type: nil, device_types: nil, manufacturer: nil) res = @client.get("/noise_sensors/list", {connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, customer_key: customer_key, device_type: device_type, device_types: device_types, manufacturer: manufacturer}.compact) - Seam::Resources::Device.load_from_response(res.body["devices"]) + Seam::Resources::Device.list_from_http_response(res, "devices", "/noise_sensors/list") end end end diff --git a/lib/seam/routes/noise_sensors_noise_thresholds.rb b/lib/seam/routes/noise_sensors_noise_thresholds.rb index 1cb3655d..bd6281d4 100644 --- a/lib/seam/routes/noise_sensors_noise_thresholds.rb +++ b/lib/seam/routes/noise_sensors_noise_thresholds.rb @@ -19,7 +19,7 @@ def initialize(client:, defaults:) def create(device_id:, ends_daily_at:, starts_daily_at:, name: nil, noise_threshold_decibels: nil, noise_threshold_nrs: nil) res = @client.post("/noise_sensors/noise_thresholds/create", {device_id: device_id, ends_daily_at: ends_daily_at, starts_daily_at: starts_daily_at, name: name, noise_threshold_decibels: noise_threshold_decibels, noise_threshold_nrs: noise_threshold_nrs}.compact) - Seam::Resources::NoiseThreshold.load_from_response(res.body["noise_threshold"]) + Seam::Resources::NoiseThreshold.from_http_response(res, "noise_threshold", "/noise_sensors/noise_thresholds/create") end # Deletes a [noise threshold](https://www.seam.co/docs/capability-guides/noise-sensors/configure-noise-threshold-settings) from a [noise sensor](https://www.seam.co/docs/capability-guides/noise-sensors). @@ -38,7 +38,7 @@ def delete(device_id:, noise_threshold_id:) def get(noise_threshold_id:) res = @client.get("/noise_sensors/noise_thresholds/get", {noise_threshold_id: noise_threshold_id}.compact) - Seam::Resources::NoiseThreshold.load_from_response(res.body["noise_threshold"]) + Seam::Resources::NoiseThreshold.from_http_response(res, "noise_threshold", "/noise_sensors/noise_thresholds/get") end # Returns a list of all [noise thresholds](https://www.seam.co/docs/capability-guides/noise-sensors/configure-noise-threshold-settings) for a [noise sensor](https://www.seam.co/docs/capability-guides/noise-sensors). @@ -47,7 +47,7 @@ def get(noise_threshold_id:) def list(device_id:) res = @client.get("/noise_sensors/noise_thresholds/list", {device_id: device_id}.compact) - Seam::Resources::NoiseThreshold.load_from_response(res.body["noise_thresholds"]) + Seam::Resources::NoiseThreshold.list_from_http_response(res, "noise_thresholds", "/noise_sensors/noise_thresholds/list") end # Updates a [noise threshold](https://www.seam.co/docs/capability-guides/noise-sensors/configure-noise-threshold-settings) for a [noise sensor](https://www.seam.co/docs/capability-guides/noise-sensors). diff --git a/lib/seam/routes/phones.rb b/lib/seam/routes/phones.rb index 0c4b2a0e..937c0cc5 100644 --- a/lib/seam/routes/phones.rb +++ b/lib/seam/routes/phones.rb @@ -27,7 +27,7 @@ def deactivate(device_id:) def get(device_id:) res = @client.get("/phones/get", {device_id: device_id}.compact) - Seam::Resources::Phone.load_from_response(res.body["phone"]) + Seam::Resources::Phone.from_http_response(res, "phone", "/phones/get") end # Returns a list of all [phones](https://www.seam.co/docs/capability-guides/mobile-access/managing-phones-for-a-user-identity). To filter the list of returned phones by a specific owner user identity or credential, include the `owner_user_identity_id` or `acs_credential_id`, respectively, in the request body. @@ -37,7 +37,7 @@ def get(device_id:) def list(acs_credential_id: nil, owner_user_identity_id: nil) res = @client.get("/phones/list", {acs_credential_id: acs_credential_id, owner_user_identity_id: owner_user_identity_id}.compact) - Seam::Resources::Phone.load_from_response(res.body["phones"]) + Seam::Resources::Phone.list_from_http_response(res, "phones", "/phones/list") end end end diff --git a/lib/seam/routes/phones_simulate.rb b/lib/seam/routes/phones_simulate.rb index 7351bfaa..f67a7739 100644 --- a/lib/seam/routes/phones_simulate.rb +++ b/lib/seam/routes/phones_simulate.rb @@ -17,7 +17,7 @@ def initialize(client:, defaults:) def create_sandbox_phone(user_identity_id:, assa_abloy_metadata: nil, custom_sdk_installation_id: nil, phone_metadata: nil) res = @client.post("/phones/simulate/create_sandbox_phone", {user_identity_id: user_identity_id, assa_abloy_metadata: assa_abloy_metadata, custom_sdk_installation_id: custom_sdk_installation_id, phone_metadata: phone_metadata}.compact) - Seam::Resources::Phone.load_from_response(res.body["phone"]) + Seam::Resources::Phone.from_http_response(res, "phone", "/phones/simulate/create_sandbox_phone") end end end diff --git a/lib/seam/routes/spaces.rb b/lib/seam/routes/spaces.rb index 5f760daa..14ec08b1 100644 --- a/lib/seam/routes/spaces.rb +++ b/lib/seam/routes/spaces.rb @@ -50,7 +50,7 @@ def add_devices(device_ids:, space_id:) def create(name:, acs_entrance_ids: nil, connected_account_ids: nil, customer_data: nil, customer_key: nil, device_ids: nil, space_key: nil) res = @client.post("/spaces/create", {name: name, acs_entrance_ids: acs_entrance_ids, connected_account_ids: connected_account_ids, customer_data: customer_data, customer_key: customer_key, device_ids: device_ids, space_key: space_key}.compact) - Seam::Resources::Space.load_from_response(res.body["space"]) + Seam::Resources::Space.from_http_response(res, "space", "/spaces/create") end # Deletes a space. @@ -73,7 +73,7 @@ def get(space_id: nil, space_key: nil) res = @client.get("/spaces/get", {space_id: space_id, space_key: space_key}.compact) - Seam::Resources::Space.load_from_response(res.body["space"]) + Seam::Resources::Space.from_http_response(res, "space", "/spaces/get") end # Gets all related resources for one or more Spaces. @@ -89,7 +89,7 @@ def get_related(exclude: nil, include: nil, space_ids: nil, space_keys: nil) res = @client.get("/spaces/get_related", {exclude: exclude, include: include, space_ids: space_ids, space_keys: space_keys}.compact) - Seam::Resources::Batch.load_from_response(res.body["batch"]) + Seam::Resources::Batch.from_http_response(res, "batch", "/spaces/get_related") end # Returns a list of all spaces. @@ -102,7 +102,7 @@ def get_related(exclude: nil, include: nil, space_ids: nil, space_keys: nil) def list(customer_key: nil, limit: nil, page_cursor: nil, search: nil, space_key: nil) res = @client.get("/spaces/list", {customer_key: customer_key, limit: limit, page_cursor: page_cursor, search: search, space_key: space_key}.compact) - Seam::Resources::Space.load_from_response(res.body["spaces"]) + Seam::Resources::Space.list_from_http_response(res, "spaces", "/spaces/list") end # Removes [entrances](https://www.seam.co/docs/low-level-apis/access-systems/retrieving-entrance-details) from a specific space. @@ -146,7 +146,7 @@ def remove_devices(device_ids:, space_id:) def update(acs_entrance_ids: nil, customer_data: nil, device_ids: nil, name: nil, space_id: nil, space_key: nil) res = @client.patch("/spaces/update", {acs_entrance_ids: acs_entrance_ids, customer_data: customer_data, device_ids: device_ids, name: name, space_id: space_id, space_key: space_key}.compact) - Seam::Resources::Space.load_from_response(res.body["space"]) + Seam::Resources::Space.from_http_response(res, "space", "/spaces/update") end end end diff --git a/lib/seam/routes/thermostats.rb b/lib/seam/routes/thermostats.rb index 100b25f1..51f0118f 100644 --- a/lib/seam/routes/thermostats.rb +++ b/lib/seam/routes/thermostats.rb @@ -31,7 +31,7 @@ def activate_climate_preset(climate_preset_key:, device_id:, wait_for_action_att wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/activate_climate_preset"), @client, wait_for_action_attempt) end # Returns a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats) to its [weekly program](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-thermostat-programs), the schedule that is configured on the device itself, releasing any hold that Seam has set. Seam stops managing the thermostat's climate until you [activate a climate preset](https://www.seam.co/docs/capability-guides/thermostats/configure-current-climate-settings), make a direct climate setting change, or one of the thermostat's [scheduled](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules) presets reaches its activation time. @@ -42,7 +42,7 @@ def activate_weekly_program(device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/activate_weekly_program"), @client, wait_for_action_attempt) end # Sets a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats) to [cool mode](https://www.seam.co/docs/capability-guides/thermostats/configure-current-climate-settings). @@ -55,7 +55,7 @@ def cool(device_id:, cooling_set_point_celsius: nil, cooling_set_point_fahrenhei wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/cool"), @client, wait_for_action_attempt) end # Creates a [climate preset](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-climate-presets) for a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats). @@ -99,7 +99,7 @@ def heat(device_id:, heating_set_point_celsius: nil, heating_set_point_fahrenhei wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/heat"), @client, wait_for_action_attempt) end # Sets a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats) to [heat-cool ("auto") mode](https://www.seam.co/docs/capability-guides/thermostats/configure-current-climate-settings). @@ -114,7 +114,7 @@ def heat_cool(device_id:, cooling_set_point_celsius: nil, cooling_set_point_fahr wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/heat_cool"), @client, wait_for_action_attempt) end # Returns a list of all [thermostats](https://www.seam.co/docs/capability-guides/thermostats). @@ -128,7 +128,7 @@ def heat_cool(device_id:, cooling_set_point_celsius: nil, cooling_set_point_fahr def list(connect_webview_id: nil, connected_account_id: nil, customer_key: nil, device_type: nil, device_types: nil, manufacturer: nil) res = @client.get("/thermostats/list", {connect_webview_id: connect_webview_id, connected_account_id: connected_account_id, customer_key: customer_key, device_type: device_type, device_types: device_types, manufacturer: manufacturer}.compact) - Seam::Resources::Device.load_from_response(res.body["devices"]) + Seam::Resources::Device.list_from_http_response(res, "devices", "/thermostats/list") end # Sets a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats) to ["off" mode](https://www.seam.co/docs/capability-guides/thermostats/configure-current-climate-settings). @@ -139,7 +139,7 @@ def off(device_id:, wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/off"), @client, wait_for_action_attempt) end # Sets a specified [climate preset](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-climate-presets) as the ["fallback"](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-climate-presets/setting-the-fallback-climate-preset) preset for a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats). @@ -163,7 +163,7 @@ def set_fan_mode(device_id:, fan_mode: nil, fan_mode_setting: nil, wait_for_acti wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/set_fan_mode"), @client, wait_for_action_attempt) end # Sets the [HVAC mode](https://www.seam.co/docs/capability-guides/thermostats/configure-current-climate-settings) for a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats). @@ -179,7 +179,7 @@ def set_hvac_mode(device_id:, hvac_mode_setting:, cooling_set_point_celsius: nil wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/set_hvac_mode"), @client, wait_for_action_attempt) end # Sets a [temperature threshold](https://www.seam.co/docs/capability-guides/thermostats/setting-and-monitoring-temperature-thresholds) for a specified thermostat. Seam emits a `thermostat.temperature_threshold_exceeded` event and adds a warning on a thermostat if it reports a temperature outside the threshold range. @@ -231,7 +231,7 @@ def update_weekly_program(device_id:, friday_program_id: nil, monday_program_id: wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/update_weekly_program"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/thermostats_daily_programs.rb b/lib/seam/routes/thermostats_daily_programs.rb index aca03265..372dd628 100644 --- a/lib/seam/routes/thermostats_daily_programs.rb +++ b/lib/seam/routes/thermostats_daily_programs.rb @@ -18,7 +18,7 @@ def initialize(client:, defaults:) def create(device_id:, name:, periods:) res = @client.post("/thermostats/daily_programs/create", {device_id: device_id, name: name, periods: periods}.compact) - Seam::Resources::ThermostatDailyProgram.load_from_response(res.body["thermostat_daily_program"]) + Seam::Resources::ThermostatDailyProgram.from_http_response(res, "thermostat_daily_program", "/thermostats/daily_programs/create") end # Deletes a thermostat daily program. @@ -40,7 +40,7 @@ def update(name:, periods:, thermostat_daily_program_id:, wait_for_action_attemp wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/thermostats/daily_programs/update"), @client, wait_for_action_attempt) end end end diff --git a/lib/seam/routes/thermostats_schedules.rb b/lib/seam/routes/thermostats_schedules.rb index e5c1fbab..ee81e34c 100644 --- a/lib/seam/routes/thermostats_schedules.rb +++ b/lib/seam/routes/thermostats_schedules.rb @@ -20,7 +20,7 @@ def initialize(client:, defaults:) def create(climate_preset_key:, device_id:, ends_at:, starts_at:, is_override_allowed: nil, max_override_period_minutes: nil, name: nil) res = @client.post("/thermostats/schedules/create", {climate_preset_key: climate_preset_key, device_id: device_id, ends_at: ends_at, starts_at: starts_at, is_override_allowed: is_override_allowed, max_override_period_minutes: max_override_period_minutes, name: name}.compact) - Seam::Resources::ThermostatSchedule.load_from_response(res.body["thermostat_schedule"]) + Seam::Resources::ThermostatSchedule.from_http_response(res, "thermostat_schedule", "/thermostats/schedules/create") end # Deletes a [thermostat schedule](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules) for a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats). @@ -38,7 +38,7 @@ def delete(thermostat_schedule_id:) def get(thermostat_schedule_id:) res = @client.get("/thermostats/schedules/get", {thermostat_schedule_id: thermostat_schedule_id}.compact) - Seam::Resources::ThermostatSchedule.load_from_response(res.body["thermostat_schedule"]) + Seam::Resources::ThermostatSchedule.from_http_response(res, "thermostat_schedule", "/thermostats/schedules/get") end # Returns a list of all [thermostat schedules](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules) for a specified [thermostat](https://www.seam.co/docs/capability-guides/thermostats). @@ -48,7 +48,7 @@ def get(thermostat_schedule_id:) def list(device_id:, user_identifier_key: nil) res = @client.get("/thermostats/schedules/list", {device_id: device_id, user_identifier_key: user_identifier_key}.compact) - Seam::Resources::ThermostatSchedule.load_from_response(res.body["thermostat_schedules"]) + Seam::Resources::ThermostatSchedule.list_from_http_response(res, "thermostat_schedules", "/thermostats/schedules/list") end # Updates a specified [thermostat schedule](https://www.seam.co/docs/capability-guides/thermostats/creating-and-managing-thermostat-schedules). diff --git a/lib/seam/routes/user_identities.rb b/lib/seam/routes/user_identities.rb index c6c7d670..505fa776 100644 --- a/lib/seam/routes/user_identities.rb +++ b/lib/seam/routes/user_identities.rb @@ -38,7 +38,7 @@ def add_acs_user(acs_user_id:, user_identity_id: nil, user_identity_key: nil) def create(acs_system_ids: nil, customer_key: nil, email_address: nil, full_name: nil, phone_number: nil, user_identity_key: nil) res = @client.post("/user_identities/create", {acs_system_ids: acs_system_ids, customer_key: customer_key, email_address: email_address, full_name: full_name, phone_number: phone_number, user_identity_key: user_identity_key}.compact) - Seam::Resources::UserIdentity.load_from_response(res.body["user_identity"]) + Seam::Resources::UserIdentity.from_http_response(res, "user_identity", "/user_identities/create") end # Deletes a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). This deletes the user identity and all associated resources, including any [credentials](https://www.seam.co/docs/api/acs/credentials/object), [acs users](https://www.seam.co/docs/api/acs/users/object) and [client sessions](https://www.seam.co/docs/api/client_sessions/object). @@ -58,7 +58,7 @@ def delete(user_identity_id:) def generate_instant_key(user_identity_id:, customization_profile_id: nil, max_use_count: nil) res = @client.post("/user_identities/generate_instant_key", {user_identity_id: user_identity_id, customization_profile_id: customization_profile_id, max_use_count: max_use_count}.compact) - Seam::Resources::InstantKey.load_from_response(res.body["instant_key"]) + Seam::Resources::InstantKey.from_http_response(res, "instant_key", "/user_identities/generate_instant_key") end # Returns a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). @@ -72,7 +72,7 @@ def get(user_identity_id: nil, user_identity_key: nil) res = @client.get("/user_identities/get", {user_identity_id: user_identity_id, user_identity_key: user_identity_key}.compact) - Seam::Resources::UserIdentity.load_from_response(res.body["user_identity"]) + Seam::Resources::UserIdentity.from_http_response(res, "user_identity", "/user_identities/get") end # Grants a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity) access to a specified [device](https://www.seam.co/docs/core-concepts/devices). @@ -97,7 +97,7 @@ def grant_access_to_device(device_id:, user_identity_id:) def list(created_before: nil, credential_manager_acs_system_id: nil, customer_key: nil, limit: nil, page_cursor: nil, search: nil, user_identity_ids: nil) res = @client.get("/user_identities/list", {created_before: created_before, credential_manager_acs_system_id: credential_manager_acs_system_id, customer_key: customer_key, limit: limit, page_cursor: page_cursor, search: search, user_identity_ids: user_identity_ids}.compact) - Seam::Resources::UserIdentity.load_from_response(res.body["user_identities"]) + Seam::Resources::UserIdentity.list_from_http_response(res, "user_identities", "/user_identities/list") end # Returns a list of all [devices](https://www.seam.co/docs/core-concepts/devices) associated with a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). This includes devices derived from the access grants assigned to the user identity and devices directly linked to the user identity. @@ -106,7 +106,7 @@ def list(created_before: nil, credential_manager_acs_system_id: nil, customer_ke def list_accessible_devices(user_identity_id:) res = @client.get("/user_identities/list_accessible_devices", {user_identity_id: user_identity_id}.compact) - Seam::Resources::Device.load_from_response(res.body["devices"]) + Seam::Resources::Device.list_from_http_response(res, "devices", "/user_identities/list_accessible_devices") end # Returns a list of all [ACS entrances](https://www.seam.co/docs/api/acs/entrances/object) accessible to a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). This includes entrances derived from the access grants assigned to the user identity and entrances accessible through ACS users linked to the user identity. @@ -115,7 +115,7 @@ def list_accessible_devices(user_identity_id:) def list_accessible_entrances(user_identity_id:) res = @client.get("/user_identities/list_accessible_entrances", {user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsEntrance.load_from_response(res.body["acs_entrances"]) + Seam::Resources::AcsEntrance.list_from_http_response(res, "acs_entrances", "/user_identities/list_accessible_entrances") end # Returns a list of all [access systems](https://www.seam.co/docs/low-level-apis/access-systems) associated with a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). @@ -124,7 +124,7 @@ def list_accessible_entrances(user_identity_id:) def list_acs_systems(user_identity_id:) res = @client.get("/user_identities/list_acs_systems", {user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsSystem.load_from_response(res.body["acs_systems"]) + Seam::Resources::AcsSystem.list_from_http_response(res, "acs_systems", "/user_identities/list_acs_systems") end # Returns a list of all [access system users](https://www.seam.co/docs/low-level-apis/access-systems/user-management) assigned to a specified [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity). @@ -133,7 +133,7 @@ def list_acs_systems(user_identity_id:) def list_acs_users(user_identity_id:) res = @client.get("/user_identities/list_acs_users", {user_identity_id: user_identity_id}.compact) - Seam::Resources::AcsUser.load_from_response(res.body["acs_users"]) + Seam::Resources::AcsUser.list_from_http_response(res, "acs_users", "/user_identities/list_acs_users") end # Merges one or more [user identities](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity) into a primary user identity, for when the same person ended up with more than one user identity. diff --git a/lib/seam/routes/user_identities_unmanaged.rb b/lib/seam/routes/user_identities_unmanaged.rb index d43c7994..a3428de6 100644 --- a/lib/seam/routes/user_identities_unmanaged.rb +++ b/lib/seam/routes/user_identities_unmanaged.rb @@ -14,7 +14,7 @@ def initialize(client:, defaults:) def get(user_identity_id:) res = @client.get("/user_identities/unmanaged/get", {user_identity_id: user_identity_id}.compact) - Seam::Resources::UnmanagedUserIdentity.load_from_response(res.body["user_identity"]) + Seam::Resources::UnmanagedUserIdentity.from_http_response(res, "user_identity", "/user_identities/unmanaged/get") end # Returns a list of all unmanaged [user identities](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity) (where is_managed = false). @@ -26,7 +26,7 @@ def get(user_identity_id:) def list(created_before: nil, limit: nil, page_cursor: nil, search: nil) res = @client.get("/user_identities/unmanaged/list", {created_before: created_before, limit: limit, page_cursor: page_cursor, search: search}.compact) - Seam::Resources::UnmanagedUserIdentity.load_from_response(res.body["user_identities"]) + Seam::Resources::UnmanagedUserIdentity.list_from_http_response(res, "user_identities", "/user_identities/unmanaged/list") end # Updates an unmanaged [user identity](https://www.seam.co/docs/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity) to make it managed. diff --git a/lib/seam/routes/webhooks.rb b/lib/seam/routes/webhooks.rb index b03bf3bb..421fd52b 100644 --- a/lib/seam/routes/webhooks.rb +++ b/lib/seam/routes/webhooks.rb @@ -15,7 +15,7 @@ def initialize(client:, defaults:) def create(url:, event_types: nil) res = @client.post("/webhooks/create", {url: url, event_types: event_types}.compact) - Seam::Resources::Webhook.load_from_response(res.body["webhook"]) + Seam::Resources::Webhook.from_http_response(res, "webhook", "/webhooks/create") end # Deletes a specified [webhook](https://www.seam.co/docs/developer-tools/webhooks). @@ -33,7 +33,7 @@ def delete(webhook_id:) def get(webhook_id:) res = @client.get("/webhooks/get", {webhook_id: webhook_id}.compact) - Seam::Resources::Webhook.load_from_response(res.body["webhook"]) + Seam::Resources::Webhook.from_http_response(res, "webhook", "/webhooks/get") end # Returns a list of all [webhooks](https://www.seam.co/docs/developer-tools/webhooks). @@ -41,7 +41,7 @@ def get(webhook_id:) def list res = @client.get("/webhooks/list") - Seam::Resources::Webhook.load_from_response(res.body["webhooks"]) + Seam::Resources::Webhook.list_from_http_response(res, "webhooks", "/webhooks/list") end # Updates a specified [webhook](https://www.seam.co/docs/developer-tools/webhooks). diff --git a/lib/seam/routes/workspaces.rb b/lib/seam/routes/workspaces.rb index 7a675930..4b45c0c2 100644 --- a/lib/seam/routes/workspaces.rb +++ b/lib/seam/routes/workspaces.rb @@ -30,7 +30,7 @@ def initialize(client:, defaults:) def create(name:, company_name: nil, connect_partner_name: nil, connect_webview_customization: nil, is_sandbox: nil, organization_id: nil, webview_logo_shape: nil, webview_primary_button_color: nil, webview_primary_button_text_color: nil, webview_success_message: nil) res = @client.post("/workspaces/create", {name: name, company_name: company_name, connect_partner_name: connect_partner_name, connect_webview_customization: connect_webview_customization, is_sandbox: is_sandbox, organization_id: organization_id, webview_logo_shape: webview_logo_shape, webview_primary_button_color: webview_primary_button_color, webview_primary_button_text_color: webview_primary_button_text_color, webview_success_message: webview_success_message}.compact) - Seam::Resources::Workspace.load_from_response(res.body["workspace"]) + Seam::Resources::Workspace.from_http_response(res, "workspace", "/workspaces/create") end # Returns the [workspace](https://www.seam.co/docs/core-concepts/workspaces) associated with the authentication value. @@ -38,7 +38,7 @@ def create(name:, company_name: nil, connect_partner_name: nil, connect_webview_ def get res = @client.get("/workspaces/get") - Seam::Resources::Workspace.load_from_response(res.body["workspace"]) + Seam::Resources::Workspace.from_http_response(res, "workspace", "/workspaces/get") end # Returns a list of [workspaces](https://www.seam.co/docs/core-concepts/workspaces) associated with the authentication value. @@ -46,7 +46,7 @@ def get def list res = @client.get("/workspaces/list") - Seam::Resources::Workspace.load_from_response(res.body["workspaces"]) + Seam::Resources::Workspace.list_from_http_response(res, "workspaces", "/workspaces/list") end # Resets the [sandbox workspace](https://www.seam.co/docs/core-concepts/workspaces#sandbox-workspaces) associated with the authentication value. Note that this endpoint is only available for sandbox workspaces. @@ -56,7 +56,7 @@ def reset_sandbox(wait_for_action_attempt: nil) wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt - Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt) + Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.from_http_response(res, "action_attempt", "/workspaces/reset_sandbox"), @client, wait_for_action_attempt) end # Updates the [workspace](https://www.seam.co/docs/core-concepts/workspaces) associated with the authentication value. diff --git a/spec/seam_client/invalid_response_spec.rb b/spec/seam_client/invalid_response_spec.rb new file mode 100644 index 00000000..0c9ee770 --- /dev/null +++ b/spec/seam_client/invalid_response_spec.rb @@ -0,0 +1,132 @@ +# frozen_string_literal: true + +RSpec.describe Seam::Http::InvalidResponseError do + let(:seam) { Seam.new(api_key: "seam_some_api_key", wait_for_action_attempt: false) } + let(:get_url) { "#{Seam::DEFAULT_ENDPOINT}/devices/get" } + let(:list_url) { "#{Seam::DEFAULT_ENDPOINT}/devices/list" } + + def json_response(body, status: 200) + {status: status, body: body, headers: {"Content-Type" => "application/json"}} + end + + def get_device + seam.devices.get(device_id: "device-1") + end + + def invalid_response_error(message) + raise_error(described_class, message) + end + + it "raises when the response is missing the expected key" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response("{}")) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", which the response does not contain' + ) do |error| + expect(error.path).to eq("/devices/get") + expect(error.response_key).to eq("device") + end + end + + it "raises when the response carries the wrong key" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response({devices: []}.to_json)) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", which the response does not contain' + ) + end + + it "raises when the response body is null" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response("null")) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", got NilClass instead of a response object' + ) + end + + it "raises when the response body is a string" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response('"device"')) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", got String instead of a response object' + ) + end + + it "raises when the response is plain text" do + stub_request(:get, get_url).with(query: hash_including({})).to_return( + status: 200, body: "OK", headers: {"Content-Type" => "text/plain"} + ) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", got String instead of a response object' + ) + end + + it "raises a Faraday parsing error when a JSON response does not parse" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response("gateway")) + + expect { get_device }.to raise_error(Faraday::ParsingError) + end + + it "raises when the value under the key is not an object" do + stub_request(:get, get_url).with(query: hash_including({})).to_return(json_response({device: "device-1"}.to_json)) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", got String instead of an object' + ) + end + + it "raises when the value under a list key is not a list" do + stub_request(:get, list_url).to_return(json_response({devices: {}}.to_json)) + + expect { seam.devices.list }.to invalid_response_error( + 'Seam returned an invalid response for /devices/list: expected "devices", got Hash instead of a list' + ) + end + + it "raises for a redirect instead of treating it as a success" do + stub_request(:get, get_url).with(query: hash_including({})).to_return( + status: 302, body: "", headers: {"Location" => "https://example.com/elsewhere"} + ) + + expect { get_device }.to invalid_response_error( + 'Seam returned an invalid response for /devices/get: expected "device", got a 302 response instead of a success response' + ) + end + + it "raises when a poll response is malformed while waiting" do + pending_attempt = {action_attempt: {action_attempt_id: "attempt-1", action_type: "UNLOCK_DOOR", status: "pending"}} + stub_request(:post, "#{Seam::DEFAULT_ENDPOINT}/locks/unlock_door").to_return(json_response(pending_attempt.to_json)) + stub_request(:get, "#{Seam::DEFAULT_ENDPOINT}/action_attempts/get").with(query: hash_including({})) + .to_return(json_response("{}")) + + expect do + seam.locks.unlock_door(device_id: "device-1", wait_for_action_attempt: {timeout: 1, polling_interval: 0.01}) + end.to invalid_response_error( + 'Seam returned an invalid response for /action_attempts/get: expected "action_attempt", which the response does not contain' + ) + end + + describe "through a paginator" do + def first_page + seam.create_paginator(seam.devices.method(:list), {limit: 1}).first_page + end + + it "raises when the pagination object is missing" do + stub_request(:get, list_url).with(query: hash_including({})).to_return(json_response({devices: []}.to_json)) + + expect { first_page }.to invalid_response_error( + 'Seam returned an invalid response for /devices/list: expected "pagination", which the response does not contain' + ) + end + + it "raises when the pagination object is not an object" do + stub_request(:get, list_url).with(query: hash_including({})) + .to_return(json_response({devices: [], pagination: "next"}.to_json)) + + expect { first_page }.to invalid_response_error( + 'Seam returned an invalid response for /devices/list: expected "pagination", got String instead of a pagination object' + ) + end + end +end diff --git a/spec/seam_error_spec.rb b/spec/seam_error_spec.rb index 9dc2514c..d44f2c45 100644 --- a/spec/seam_error_spec.rb +++ b/spec/seam_error_spec.rb @@ -9,6 +9,7 @@ Seam::Http::ApiError, Seam::Http::UnauthorizedError, Seam::Http::InvalidInputError, + Seam::Http::InvalidResponseError, Seam::Http::Options::SeamInvalidOptionsError, Seam::Http::Auth::SeamInvalidTokenError, Seam::ActionAttemptError,