I'm currently using the following. It works, but I'd like to bake it into one data structure. This means moving the status and title into the array somehow. Is this possible?
## Invalid Credentials Object (object)
+ status: 401 (number)
+ title: `Invalid Credentials`
## Invalid Credentials (object)
+ errors (array[Invalid Credentials Object])
I'd like it to somehow resemble:
## Invalid Credentials (object)
+ errors (array[
+ status: 401 (number)
+ title: `Invalid Credentials`
])
Could you not do something like;
# Invalid Credentials (object)
+ errors (array[
#error
+ status: 401 (number)
+ message: 'Invalid Credentials'
])
Of course that's assuming you can next objects within an array.
Related
When I run this code:
$client->evaluate('
box.session.settings.error_marshaling_enabled = false
box.error{code = 42, reason = "Foobar", type = "MyError"}
');
regardless of the value of error_marshaling_enabled I always get a response with a new (extended) error format:
[
49 => 'Foobar',
82 => [
0 => [
0 => [
0 => 'CustomError',
2 => 3,
1 => 'eval',
3 => 'Foobar',
4 => 0,
5 => 42,
6 => [
'custom_type' => 'MyError',
],
],
],
],
],
Why is that?
Short answer.
error_marshaling_enabled option affects only how error objects are encoded in response body (48, IPROTO_DATA). It does not affect how they are returned as exceptions, in the response header (82, IPROTO_ERROR).
Long answer.
In Tarantool an error object can be returned in 2 ways: as an exception and as an object. For example, this is how to throw an error as exception:
function throw_error()
box.error({code = 1000, reason = "Error message"})
-- Or
error('Some error string')
end
This is how to return it as an object:
function return_error()
return box.error.new({code = 1000, reason = "Error message"})
end
If the function was called remotely, using IPROTO protocol via a connector like netbox, or PHP connector, or any other one, the error return way affects how it is encoded into MessagePack response packet. When the function throws, and the error reaches the top stack frame without being caught, it is encoded as IPROTO_ERROR (82) and IPROTO_ERROR_24 (49).
When the error object is returned as a regular value, not as an exception, it is encoded also as a regular value, inside IPROTO_DATA (48). Just like a string, a number, a tuple, etc.
With encoding as IPROTO_ERROR/IPROTO_ERROR_24 there is no much of a configuration space. Format of these values can't be changed. IPROTO_ERROR is always returned as a MessagePack map, with a stack of errors in it. IPROTO_ERROR_24 is always an error message. The IPROTO_ERROR_24 field is kept for compatibility with connectors to Tarantool versions < 2.4.1.
With encoding as a part of IPROTO_DATA you can choose serialization way using error_marshaling_enabled option. When it is true, errors are encoded as MessagePack extension type MP_EXT, and contain the whole error stack, encoded exactly like IPROTO_ERROR value. When the option is false (default behaviour in 2.4.1), the error is encoded as a string, MP_STR, which is the error's message. If there is a stack of errors, only the newest error is encoded.
error_marshaling_enabled option exists for backward compatibility, in case your application on Tarantool wants to be compatible with old connectors, which don't support MP_EXT encoded errors.
In Tarantool < 2.4.1 errors were encoded into result MessagePack as a string with error message, and error stacks didn't exist at all. So when the new format and the error stacks feature were introduced, making the new format default would be a too radical change breaking the old connectors.
Consider these examples of how error marshaling affects results. I use Tarantool 2.4.1 console here, and built-in netbox connector. The code below can be copy pasted into the console.
First instance:
box.cfg{listen = 3313}
box.schema.user.grant('guest', 'super')
function throw_error()
box.error({code = 1000, reason = "Error message"})
end
function return_error()
return box.error.new({code = 1000, reason = "Error message"})
end
Second instance:
netbox = require('net.box')
c = netbox.connect(3313)
Now I try to call the function on the second instance:
tarantool> c:call('throw_error')
---
- error: Error message
...
The c:call('throw_error') threw an exception. If I catch it using pcall() Lua function, I will see the error object.
tarantool> ok, err = pcall(c.call, c, 'throw_error')
tarantool> err:unpack()
---
- code: 1000
base_type: ClientError
type: ClientError
message: Error message
trace:
- file: '[string "function throw_error()..."]'
line: 2
...
As you can see, I didn't set error_marshaling_enabled, but got the full error. Now I will call the other function, without exceptions. But the error object won't be full.
tarantool> err = c:call('return_error')
tarantool> err
---
- Error message
...
tarantool> err:unpack()
---
- error: '[string "return err:unpack()"]:1: attempt to call method ''unpack'' (a nil
value)'
...
The error was returned as a mere string, error message. Not as an error object. Now I will turn on the marshaling:
tarantool> c:eval('box.session.settings.error_marshaling_enabled = true')
---
...
tarantool> err = c:call('return_error')
---
...
tarantool> err:unpack()
---
- code: 1000
base_type: ClientError
type: ClientError
message: Error message
trace:
- file: '[C]'
line: 4294967295
...
Now the same function returned the error in the new format, more featured.
On the summary: error_marshaling_enabled affects only returned errors. Not thrown errors.
I'm attempting to make a GET call to a test management system that exposes an API. I want to provide Basic Auth in the header of the HTTPRequest provided as an action in OT like so.
includes: login.js
actors:
- actor: WEB
segments:
- segment: 1
actions:
- script: var xUsername = $env("X_USERNAME");
- script: var xPassword = $env("X_PASSWORD");
- script: $log("This is the username " + xUsername);
- script: $log("This is the password " + xPassword);
- description: Sample Reading testid
action: org.getopentest.actions.HttpRequest
args:
$checkpoint: true
$localData:
testRailCaseInfo: $output.body
url: https://sub.domain.io/api/v2/get_results/1234
headers:
Content-Type: application/json
Authorization: Basic xUsername xPassword
verb: GET
Is this correct?
Here are two ways to do it (please note I didn't test this code). You can either build the Authorization header value using a JavaScript expression,
- description: Read test ID
action: org.getopentest.actions.HttpRequest
args:
url: https://sub.domain.io/api/v2/get_results/1234
verb: GET
headers:
Content-Type: application/json
Authorization: |
$script
"Basic " + $base64($env("X_USERNAME") + ":" + $env("X_PASSWORD"))
or build the header value in a script action, ahead of time:
- script: |
// Build the authentication header
var authHeader =
"Basic " + $base64($env("X_USERNAME") + ":" + $env("X_PASSWORD"));
- description: Read test ID
action: org.getopentest.actions.HttpRequest
args:
url: https://sub.domain.io/api/v2/get_results/1234
verb: GET
headers:
Content-Type: application/json
Authorization: $script authHeader
I should probably explain what is the role or $script prefix in the two examples. When the value of an action argument starts with a dollar-prefixed symbol (like $json, $data, $format, etc.), the test actor understands that the expression is JavaScript code, evaluates the expression and uses the result as the value for the argument. When a JS expression doesn't start with a dollar-prefixed symbol (e.g. our expressions start with "Basic" and authHeader, respectively) we must prefix the expression with $script followed by one or more whitespace characters, to let the test actor know that the string that follows is JavaScript code and not just an ordinary string literal.
As for the format of the basic authentication scheme, you can find more information here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization.
How can I use generic named type in my API Blueprint definition?
I try like this:
FORMAT: 1A HOST: http://test.com/
# API Blueprint testing.
## Resource [/resources]
### Action [GET]
+ Response 200 (application/json)
+ Attributes
+ decorated_person (Address Decorator(Person))
# Data Structures
## Person (object)
+ first_name
+ last_name
## Address Decorator (*T*)
+ address
But Apiary Editor give me the error:
base type 'Address Decorator(Person)' is not defined in the document
here is two problems. Address Decorator isn't base type for example object and in attributes you have to use Mixin or Nesting.
FORMAT: 1A
HOST: http://test.com/
# API Blueprint testing.
## Resource [/resources]
### Action [GET]
+ Response 200 (application/json)
+ Attributes
+ Include AddressDecorator
# Data Structures
## Person (object)
+ first_name
+ last_name
## AddressDecorator (object)
+ address
I want to search (say) "accounts" based on "name" or "status".
So I would like to have two actions :
GET /persons/?q=name==Jea*
GET /persons/?q=status==locked
How can I document that ?
I tried an Action with multiples transactions :
### GET /accounts{?q}
+ Request by name
+Parameters
+q (required, FIQLQuery)
**Only name is supported**
+ Request by status
+Parameters
+q (required, FIQLQuery)
**Only status is supported**
But Apiary editor complains because :
I must provide a message-body for my GET requests:
Message-body asset is expected to be a pre-formatted code block, every of its line indented by exactly 8 spaces or 2 tabs.
The + Parameters block is not recognized :
Ignoring unrecognized block
Thanks a lot
i can make solution that works for me.
Try this API Blueprint:
FORMAT: 1A
# requestByname
## Accounts [/accounts/?{q,type}]
### GET
+ Parameters
+ q (required, FIQLQuery)
+ type (string, `name` or `status`)
+ Request Name (application/json)
+ Response 200
{"name": "test"}
+ Request Status (application/json)
+ Response 200
{"status": 200}
I have jQuery.ajax() creating a request to a url (cms2/docman/dir/%id) (%id is a numeric unsigned integer). The page requested runs some functions and outputs an array. This array is then run through drupal_json. drupal_json() echo's out the content first setting the header to
Content-Type: text/javascript; charset=utf-8
So far, everything seems to be going well. The functions are all running and the JSON is being outputted as expected. Through firebug it shows that the response received is JSON and offers the "JSON" tab to preview it.
However, jQuerys jQuery.ajax() function says that a parser error occurred and that it returned "invalid" json. I copied out the json returned and tossed it into an editor (Eclipse PDT) but it shows that there are no errors.
I'm completely stumped at this point. The only thing I can think of is if there is some kind of limit on the amount of text returned via this method.
Creates the request:
function request(url) {
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
async: false,
success: function(data) {
if(data.status) {
docman.store = data.info;
}
else {
docman.hideMessages();
docman.error(data.message);
}
},
error: function(data,ts,et) {
docman.hideMessages();
docman.error(data);
docman.store = data.responseText;
}
});
}
JSON output here - http://codetidy.com/102
You can use http://www.jsonlint.com/ to check your JSON. You'll find it tells you that line 136 contains an invalid code:
syntax error, unexpected TINVALID at
line 136 Parsing failed
You need to double escape the character code. (Two backslashes).
you have to do something like this
diff --git a/includes/common.inc b/includes/common.inc
index b86f2d2..ff246a3 100644
--- a/includes/common.inc
+++ b/includes/common.inc
## -2539,8 +2539,8 ## function drupal_to_js($var) {
case 'resource':
case 'string':
return '"'. str_replace(array("\r", "\n", "<", ">", "&"),
- array('\r', '\n', '\x3c', '\x3e', '\x26'),
- addslashes($var)) .'"';
+ array('\r', '\n', '\u003c', '\u003e', '\u0026'),
+ str_replace("\'","'", addslashes($var))) .'"';
case 'array':
// Arrays in JSON can't be associative. If the array is empty or if it
// has sequential whole number keys starting with 0, it's not associative