Exception: Ecoportal::API::Common::GraphQL::ResponseError

Inherits:
StandardError
  • Object
show all
Defined in:
lib/ecoportal/api/common/graphql/http_client.rb

Overview

Raised when a 200 response carries a top-level errors[] array.

★ Carries the RAW error entries, so extensions survives. Before this, the class collapsed the response into the joined message text and threw the rest away — which made it impossible for Ruby tooling to tell a permission problem from a request problem, the exact diagnosis we tell customers to perform. Tracked as Q-27 in docs/open-questions.md.

The backend's error contract (app/graphql/eco_portal_schema.rb, verified 2026-09-01) puts these keys under extensions:

key when shape
code always string: unauthorized, document_not_found, unprocessable_entity, write_conflict, internal_server_error, …
fullMessages unauthorized array of human strings (exp.result.reasons.full_messages)
details unauthorized ActionPolicy reasons.details — usually a Hash whose key names the failing policy and whose value lists the rules
problems validation, and only when the server runs with SHOW_GRAPHQL_EXCEPTION record errors

⚠ details is NOT reliably a Hash. Two call sites emit an Array instead (mutations/pages/send_as_email.rb sends inaccessible ids; queries/pages/templates/fetcher.rb sends [msg]). Accessors here therefore return whatever the server sent, unwrapped but uncoerced — callers must not assume a shape.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(msg = nil, errors: []) ⇒ ResponseError

Returns a new instance of ResponseError.

Parameters:

  • msg (String, nil) (defaults to: nil) —

    explicit message; defaults to the joined error messages.

  • errors (Array<Hash>) (defaults to: []) —

    raw top-level errors[] entries.



34
35
36
37
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 34

def initialize(msg = nil, errors: [])
  @errors = Array(errors)
  super(msg || build_message)
end

Instance Attribute Details

#errors ⇒ Array<Hash> (readonly)

Returns the raw errors[] entries, exactly as received.

Returns:

  • (Array<Hash>) —

    the raw errors[] entries, exactly as received.



30
31
32
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 30

def errors
  @errors
end

Instance Method Details

#codes ⇒ Array<String>

Returns every extensions.code present, in order.

Returns:

  • (Array<String>) —

    every extensions.code present, in order.



45
46
47
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 45

def codes
  extensions.filter_map { |ext| ext['code'] }
end

#details ⇒ Array

★ The fastest way to tell a permission problem from a request problem.

Returns:

  • (Array) —

    every extensions.details present. Shape is the server's — typically a Hash keyed by the failing policy, but sometimes an Array.



52
53
54
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 52

def details
  extensions.filter_map { |ext| ext['details'] }
end

#extensions ⇒ Array<Hash>

Returns the extensions object of each error that carried one.

Returns:

  • (Array<Hash>) —

    the extensions object of each error that carried one.



40
41
42
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 40

def extensions
  errors.filter_map { |err| err['extensions'] }
end

#full_messages ⇒ Array<String>

Returns flattened extensions.fullMessages.

Returns:

  • (Array<String>) —

    flattened extensions.fullMessages.



57
58
59
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 57

def full_messages
  extensions.flat_map { |ext| Array(ext['fullMessages']) }
end

#unauthorized? ⇒ Boolean

Returns whether ANY error was an authorization refusal. Use this to branch on "you cannot" vs "that request was wrong" — do not pattern-match the message text, which is prose and drifts.

Returns:

  • (Boolean) —

    whether ANY error was an authorization refusal. Use this to branch on "you cannot" vs "that request was wrong" — do not pattern-match the message text, which is prose and drifts.



64
65
66
# File 'lib/ecoportal/api/common/graphql/http_client.rb', line 64

def unauthorized?
  codes.include?('unauthorized')
end