Merge branch 'master' of github.com:openwhisk/openwhisk-client-js
diff --git a/lib/client.js b/lib/client.js
index e1060c8..47feba2 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -1,9 +1,10 @@
'use strict'
const messages = require('./messages')
-const BaseOperationError = require('./base_operation_error')
+const OpenWhiskError = require('./openwhisk_error')
const rp = require('request-promise')
const url = require('url')
+const http = require('http')
class Client {
constructor (options) {
@@ -73,53 +74,33 @@
}
handle_errors (reason) {
+ let message = `Unknown Error From API: ${reason.message}`
if (reason.hasOwnProperty('statusCode')) {
- let error
- switch (reason.statusCode) {
- case 400:
- error = messages.BAD_REQUEST_ERROR
- break
- case 401:
- case 403:
- error = messages.INVALID_AUTH_ERROR
- break
- case 404:
- error = messages.MISSING_URL_ERROR
- break
- case 408:
- error = messages.INVOKE_TIMEOUT_ERROR
- break
- case 409:
- error = messages.CREATE_CONFLICT_ERROR
- break
- case 502:
- error = messages.ACTION_INVOCATION_ERROR
- break
- default:
- error = messages.API_SYSTEM_ERROR
- }
-
- throw new BaseOperationError(`${error} ${this.err_message(reason.error)}`, reason.error)
+ const responseError = this.err_message(reason.error)
+ message = `${reason.options.method} ${reason.options.url} Returned HTTP ${reason.statusCode} (${http.STATUS_CODES[reason.statusCode]}) --> "${responseError}"`
}
- throw new Error(`Error encountered calling OpenWhisk: ${reason.message}`)
+ throw new OpenWhiskError(message, reason.error)
}
+ // Error messages might be returned from platform or using custom
+ // invocation result response from action.
err_message (error) {
- if (!error) return 'Missing error message.'
+ if (!error) return 'Response Missing Error Message.'
if (typeof error.error === 'string') {
return error.error
- } else if (error.response && error.response.result) {
- const result = error.response.result
- if (typeof result.error === 'string') {
- return result.error
- } else if (typeof result.statusCode === 'number') {
- return `application error, status code: ${result.statusCode}`
+ } else if (error.response && error.response.result
+ && error.response.result.error) {
+ const err = error.response.result.error
+ if (typeof err === 'string') {
+ return err
+ } else if (typeof err.error === 'string') {
+ return err.error
}
}
- return 'Missing error message.'
+ return 'Response Missing Error Message.'
}
}
diff --git a/lib/messages.js b/lib/messages.js
index b690b36..49b3501 100644
--- a/lib/messages.js
+++ b/lib/messages.js
@@ -14,13 +14,6 @@
MISSING_TRIGGER_BODY_ERROR: 'Missing mandatory trigger parameter from options.',
MISSING_PACKAGE_BODY_ERROR: 'Missing mandatory package parameter from options.',
MISSING_NAMESPACE_ERROR: 'Missing namespace from options, please set a default namespace or pass one in the options.',
- INVOKE_TIMEOUT_ERROR: 'Action invocation timed out before completing.',
- CREATE_CONFLICT_ERROR: 'Conflict detected updating resource.',
- INVALID_AUTH_ERROR: 'OpenWhisk authentication failed, check API key?',
- BAD_REQUEST_ERROR: 'API call failed due to invalid request payload.',
- MISSING_URL_ERROR: 'Invalid URL for API called, OpenWhisk returned HTTP 404 response.',
- API_SYSTEM_ERROR: 'API call failed, response contained error code.',
- ACTION_INVOCATION_ERROR: 'Action invocation failed, API returned error code.',
INVALID_OPTIONS_ERROR: 'Invalid constructor options.',
MISSING_BASEPATH_ERROR: 'Missing mandatory basepath parameter from options.'
}
diff --git a/lib/base_operation_error.js b/lib/openwhisk_error.js
similarity index 76%
rename from lib/base_operation_error.js
rename to lib/openwhisk_error.js
index 0cbfedd..bec6dcd 100644
--- a/lib/base_operation_error.js
+++ b/lib/openwhisk_error.js
@@ -1,10 +1,10 @@
'use strict';
-module.exports = function BaseOperationError(message, error) {
+module.exports = function OpenWhiskError(message, error) {
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.message = message;
this.error = error;
};
-require('util').inherits(module.exports, Error);
\ No newline at end of file
+require('util').inherits(module.exports, Error);
diff --git a/test/unit/client.test.js b/test/unit/client.test.js
index 16bed22..285c6e5 100644
--- a/test/unit/client.test.js
+++ b/test/unit/client.test.js
@@ -2,6 +2,7 @@
const test = require('ava')
const Client = require('../../lib/client')
+const http = require('http')
test('should use default constructor options', t => {
const client = new Client({api_key: 'aaa', apihost: 'my_host'})
@@ -98,21 +99,18 @@
t.is(client.auth_header(), `Basic ${Buffer.from(api_key).toString('base64')}`)
})
-test('should throw errors for HTTP response failures', t => {
+test('should return path and status code in error message', t => {
const client = new Client({api_key: true, api: true})
- t.throws(() => client.handle_errors({statusCode: 400}), /invalid request/)
- t.throws(() => client.handle_errors({statusCode: 400, error: { error: 'some msg'}}), /some msg/)
- t.throws(() => client.handle_errors({statusCode: 401}), /authentication failed/)
- t.throws(() => client.handle_errors({statusCode: 403}), /authentication failed/)
- t.throws(() => client.handle_errors({statusCode: 404}), /HTTP 404/)
- t.throws(() => client.handle_errors({statusCode: 408}), /timed out/)
- t.throws(() => client.handle_errors({statusCode: 409}), /Conflict/)
- t.throws(() => client.handle_errors({statusCode: 500, error: {}}), /API call failed/)
- t.throws(() => client.handle_errors({statusCode: 500, error: {response: {result: {error: 'custom'}}}}), /custom/)
- t.throws(() => client.handle_errors({statusCode: 500, error: {response: {result: {statusCode: 404}}}}), /404/)
- t.throws(() => client.handle_errors({statusCode: 502, error: {}}), /Action invocation failed/)
- t.throws(() => client.handle_errors({statusCode: 502, error: {response: {result: {error: 'custom'}}}}), /custom/)
- t.throws(() => client.handle_errors({statusCode: 502, error: {response: {result: {statusCode: 404}}}}), /404/)
+ const method = 'METHOD', url = 'https://blah.com/api/v1/actions/list', statusCode = 400
+ t.throws(() => client.handle_errors({options: { method, url }, statusCode }), `${method} ${url} Returned HTTP ${statusCode} (${http.STATUS_CODES[statusCode]}) --> "Response Missing Error Message."`)
+})
+
+test('should return response error string in error message', t => {
+ const client = new Client({api_key: true, api: true})
+ const method = 'METHOD', url = 'https://blah.com/api/v1/actions/list', statusCode = 400
+ t.throws(() => client.handle_errors({error: { error: 'hello' }, options: { method, url }, statusCode }), `${method} ${url} Returned HTTP ${statusCode} (${http.STATUS_CODES[statusCode]}) --> "hello"`)
+ t.throws(() => client.handle_errors({error: { response: { result: { error: 'hello' } } }, options: { method, url }, statusCode }), `${method} ${url} Returned HTTP ${statusCode} (${http.STATUS_CODES[statusCode]}) --> "hello"`)
+ t.throws(() => client.handle_errors({error: { response: { result: { error: { error: 'hello' } } } }, options: { method, url }, statusCode }), `${method} ${url} Returned HTTP ${statusCode} (${http.STATUS_CODES[statusCode]}) --> "hello"`)
})
test('should throw errors for non-HTTP response failures', t => {