diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ae6b617..7049eb01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ### 0.14.6 (Next) * [#305](https://github.com/slack-ruby/slack-ruby-client/pull/305): Added `admin.inviteRequests.approve`, `admin.inviteRequests.deny`, `admin.inviteRequests.list`, `admin.inviteRequests.approved.list`, `admin.inviteRequests.denied.list`, `admin.teams.create`, `admin.teams.list`, `admin.teams.admins.list`, `admin.teams.owners.list`, `admin.teams.settings`, `admin.teams.settings.setIcon`, `admin.teams.settings.setName`, `admin.teams.settings.setDescription`, `admin.users.assign`, `admin.users.invite`, `admin.users.remove`, `admin.users.setAdmin`, `admin.users.setOwner` and `admin.users.setRegular` endpoints - [@manuelmeurer](https://github.com/manuelmeurer). +* [#311](https://github.com/slack-ruby/slack-ruby-client/pull/311): Made Web API `response_metadata` more accessible in errors - [@jmanian](https://github.com/jmanian). * Your contribution here. ### 0.14.5 (2019/12/23) diff --git a/README.md b/README.md index 45e891d3..4a1d2afc 100644 --- a/README.md +++ b/README.md @@ -20,14 +20,15 @@ A Ruby client for the Slack [Web](https://api.slack.com/web), [RealTime Messagin - [Using the Legacy API Token](#using-the-legacy-api-token) - [Global Settings](#global-settings) - [Web Client](#web-client) - - [Test Auth](#test-auth) - - [Send Messages](#send-messages) - - [List Channels](#list-channels) - - [Upload a File](#upload-a-file) - - [Get Channel Info](#get-channel-info) - - [Get User Info](#get-user-info) - - [Search for a User](#search-for-a-user) - - [Other](#other) + - [Web Client Examples](#web-client-examples) + - [Test Auth](#test-auth) + - [Send Messages](#send-messages) + - [List Channels](#list-channels) + - [Upload a File](#upload-a-file) + - [Get Channel Info](#get-channel-info) + - [Get User Info](#get-user-info) + - [Search for a User](#search-for-a-user) + - [Other](#other) - [Web Client Options](#web-client-options) - [Pagination Support](#pagination-support) - [Error Handling](#error-handling) @@ -122,14 +123,18 @@ logger | An optional logger, defaults to `::Logger.new(STDOUT)` at `Logger The Slack Web API allows you to build applications that interact with Slack. -#### Test Auth +#### Web Client Examples + +Here are some examples of how to use the web client with the Web API. + +##### Test Auth ```ruby client = Slack::Web::Client.new client.auth_test ``` -#### Send Messages +##### Send Messages Send messages with [chat_PostMessage](https://api.slack.com/methods/chat.postMessage). @@ -141,7 +146,7 @@ See a fully working example in [examples/hi_web](examples/hi_web/hi.rb). ![](examples/hi_web/hi.gif) -#### List Channels +##### List Channels List channels with [channels_list](https://api.slack.com/methods/channels.list). @@ -151,7 +156,7 @@ channels = client.channels_list.channels general_channel = channels.detect { |c| c.name == 'general' } ``` -#### Upload a File +##### Upload a File Upload a file with [files_upload](https://api.slack.com/methods/files.upload). @@ -166,7 +171,7 @@ client.files_upload( ) ``` -### Get Channel Info +##### Get Channel Info You can use a channel ID or name (prefixed with `#`) in all functions that take a `:channel` argument. Lookup by name is not supported by the Slack API and the `channels_id` method called invokes `channels_list` in order to locate the channel ID. @@ -178,7 +183,7 @@ client.channels_info(channel: 'C04KB5X4D') # calls channels_info client.channels_info(channel: '#general') # calls channels_list followed by channels_info ``` -### Get User Info +##### Get User Info You can use a user ID or name (prefixed with `@`) in all functions that take a `:user` argument. Lookup by name is not supported by the Slack API and the `users_id` method called invokes `users_list` in order to locate the user ID. @@ -190,7 +195,7 @@ client.users_info(user: 'U092BDCLV') # calls users_info client.users_info(user: '@dblock') # calls users_list followed by users_info ``` -### Search for a User +##### Search for a User Constructs an in-memory index of users and searches it. If you want to use this functionality, add the [picky](https://github.com/floere/picky) gem to your project's Gemfile. @@ -198,7 +203,7 @@ Constructs an in-memory index of users and searches it. If you want to use this client.users_search(user: 'dblock') ``` -#### Other +##### Other Refer to the [Slack Web API Method Reference](https://api.slack.com/methods) for the list of all available functions. @@ -270,7 +275,7 @@ all_members # many thousands of team members retrieved 10 at a time #### Error Handling -If a request fails, a `Slack::Web::Api::Errors::SlackError` will be raised. The error message contains the error code. In case of multiple errors, the error codes are separated by commas. The original response is also accessible using the `response` attribute. +If a request fails, a `Slack::Web::Api::Errors::SlackError` will be raised. The error message contains the error code, which is also accessible with `slack_error.error`. In case of multiple errors, the error message contains the error codes separated by commas, or they are accessible as an array with `slack_error.errors`. The original response is also accessible using the `response` attribute. The `response_metadata` is accessible with `slack_error.response_metadata`. If you exceed [Slack’s rate limits](https://api.slack.com/docs/rate-limits), a `Slack::Web::Api::Errors::TooManyRequestsError` will be raised instead. diff --git a/lib/slack/web/api/errors/slack_error.rb b/lib/slack/web/api/errors/slack_error.rb index 74f161a1..92e4e03e 100644 --- a/lib/slack/web/api/errors/slack_error.rb +++ b/lib/slack/web/api/errors/slack_error.rb @@ -10,6 +10,18 @@ def initialize(message, response = nil) super message @response = response end + + def error + response.body.error + end + + def errors + response.body.errors + end + + def response_metadata + response.body.response_metadata + end end end end diff --git a/lib/slack/web/client.rb b/lib/slack/web/client.rb index 75749f33..b2d253e2 100644 --- a/lib/slack/web/client.rb +++ b/lib/slack/web/client.rb @@ -10,7 +10,7 @@ class Client def initialize(options = {}) Slack::Web::Config::ATTRIBUTES.each do |key| - send("#{key}=", options[key] || Slack::Web.config.send(key)) + send("#{key}=", options.fetch(key, Slack::Web.config.send(key))) end @logger ||= Slack::Config.logger || Slack::Logger.default @token ||= Slack.config.token diff --git a/spec/fixtures/slack/web/views_open_error.yml b/spec/fixtures/slack/web/views_open_error.yml new file mode 100644 index 00000000..a5f2cad9 --- /dev/null +++ b/spec/fixtures/slack/web/views_open_error.yml @@ -0,0 +1,76 @@ +--- +http_interactions: +- request: + method: post + uri: https://slack.com/api/views.open + body: + encoding: UTF-8 + string: token=token&trigger_id=trigger_id&view=%7B%7D + headers: + Accept: + - application/json; charset=utf-8 + User-Agent: + - Slack Ruby Client/0.14.6 + Content-Type: + - application/x-www-form-urlencoded + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json; charset=utf-8 + Content-Length: + - '154' + Connection: + - keep-alive + Date: + - Wed, 19 Feb 2020 17:52:59 GMT + Server: + - Apache + X-Content-Type-Options: + - nosniff + Expires: + - Mon, 26 Jul 1997 05:00:00 GMT + Cache-Control: + - private, no-cache, no-store, must-revalidate + X-Xss-Protection: + - '0' + Vary: + - Accept-Encoding + Pragma: + - no-cache + Access-Control-Allow-Headers: + - slack-route, x-slack-version-ts, x-b3-traceid, x-b3-spanid, x-b3-parentspanid, + x-b3-sampled, x-b3-flags + Strict-Transport-Security: + - max-age=31536000; includeSubDomains; preload + Referrer-Policy: + - no-referrer + X-Slack-Backend: + - h + Access-Control-Expose-Headers: + - x-slack-req-id, retry-after + Access-Control-Allow-Origin: + - "*" + X-Via: + - haproxy-www-ixj4 + X-Cache: + - Miss from cloudfront + Via: + - 1.1 b6cc1359c0cd55a8339441d8abb6a450.cloudfront.net (CloudFront) + X-Amz-Cf-Pop: + - JFK51-C1 + X-Amz-Cf-Id: + - fWF96IvY1omctxPC6XwjvZ2TIfpmVLlsT35MsfAWqK7zDChMCpE_oQ== + body: + encoding: ASCII-8BIT + string: '{"ok":false,"error":"invalid_arguments","response_metadata":{"messages":["[ERROR] + missing required field: title [json-pointer:\/view]","[ERROR] missing required + field: blocks [json-pointer:\/view]","[ERROR] missing required field: type + [json-pointer:\/view]"]}}' + http_version: null + recorded_at: Wed, 19 Feb 2020 17:52:59 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/slack/web/api/errors/slack_error_spec.rb b/spec/slack/web/api/errors/slack_error_spec.rb index 09a4d3b1..4aa1be0a 100644 --- a/spec/slack/web/api/errors/slack_error_spec.rb +++ b/spec/slack/web/api/errors/slack_error_spec.rb @@ -11,6 +11,28 @@ rescue described_class => e expect(e.response).not_to be_nil expect(e.response.status).to eq 200 + expect(e.message).to eql 'not_authed' + expect(e.error).to eql 'not_authed' + expect(e.response_metadata).to be_nil + end + end + + it 'provides access to any response_metadata', vcr: { cassette_name: 'web/views_open_error' } do + begin + client.views_open(trigger_id: 'trigger_id', view: {}) + raise 'Expected to receive Slack::Web::Api::Errors::SlackError.' + rescue described_class => e + expect(e.response).not_to be_nil + expect(e.response.status).to eq 200 + expect(e.message).to eql 'invalid_arguments' + expect(e.error).to eql 'invalid_arguments' + expect(e.response_metadata).to eq( + 'messages' => [ + "[ERROR] missing required field: title [json-pointer:\/view]", + "[ERROR] missing required field: blocks [json-pointer:\/view]", + "[ERROR] missing required field: type [json-pointer:\/view]" + ] + ) end end end diff --git a/spec/slack/web/faraday/response/raise_error_spec.rb b/spec/slack/web/faraday/response/raise_error_spec.rb index 8106a561..0df68082 100644 --- a/spec/slack/web/faraday/response/raise_error_spec.rb +++ b/spec/slack/web/faraday/response/raise_error_spec.rb @@ -29,7 +29,13 @@ end context 'with a single error in the body' do - let(:body) { { 'error' => 'already_in_channel' } } + let(:body) do + { + 'ok' => false, + 'error' => 'already_in_channel', + 'response_metadata' => { 'messages' => [] } + } + end it 'raises a SlackError with the error message' do expect { raise_error_obj.on_complete(env) }.to( @@ -41,6 +47,7 @@ context 'with multiple errors in the body' do let(:body) do { + 'ok' => false, 'errors' => [ { 'error' => 'already_in_channel' }, { 'error' => 'something_else_terrible' }