Nested parameters on GET request - ruby-on-rails

Question of the day: how to encode URL to be able to pass complex data on a GET request?
# data to pass
{
"main_key": {
"other_key": {
"main_array": [{
"name": "Bob",
"nickname": "bobby"
},
{
"name": "Tom",
"nickname": "Tommy"
}
]
}
}
}
Here is the current solution I got with Postman
Here is the current Rails interpretation of such a query, which is correct.
# Rails server side
Parameters: {"main_key"=>{"other_key"=>{"main_array"=>[{"name"=>"Bob", "nickname"=>"bobby"}, {"name"=>"Tom", "nickname"=>"tommy"}]}}, "default"=>{"format"=>:json}}
Can anybody have a better way to achieve a request with such a complex nested array object?
The other solution I got is to pass JSON directly as value of a query parameter and then parse it from the controller.
**Edit: ** I can pass this json on the body of the request but as it's a GET method, it does not respect XHR requirements.

If you have jquery, you can use .param() method of it.
let myParams = {
"main_key": {
"other_key": {
"main_array": [{
"name": "Bob",
"nickname": "bobby"
},
{
"name": "Tom",
"nickname": "Tommy"
}
]
}
}
}
console.log($.param(myParams));
This will give you your desired string.
"main_key%5Bother_key%5D%5Bmain_array%5D%5B0%5D%5Bname%5D=Bob&main_key%5Bother_key%5D%5Bmain_array%5D%5B0%5D%5Bnickname%5D=bobby&main_key%5Bother_key%5D%5Bmain_array%5D%5B1%5D%5Bname%5D=Tom&main_key%5Bother_key%5D%5Bmain_array%5D%5B1%5D%5Bnickname%5D=Tommy"

Related

Describe pipe delimited encoding in object in response body in Open API 3.0

So maybe I'm trying to go into too much detail in my descriptor, but here's my use case. While defining the schema of the object that is returned in the response body for my API, I have one property of the object the value of which is an object with variable properties, so I am using the additionalProperties descriptor.
{
"type": "object",
"additionalProperties": {
"type": "string"
}
}
However instead of describing the type of the values in this variable keyed object as string, I would like to describe them more precisely, seeing that the string is actually a pipe delimited serialization of an array. Example:
{
"property1": {
"variableProperty1": "info1|info2|info3",
"variableProperty2": "info1|info2|info3"
}
}
Is there any way of describing this pipe-delimited serialization? Something like:
{
"type": "object",
"additionalProperties": {
"type": "array",
"explode": false,
"encoding": {
"style": "pipeDelimited"
}
},
}
Or is this only possible for query parameters?

How to identify subschemas with a URL URI in JSON Schema?

SPEC provides next example how to identify schema:
{
"$id": "http://example.com/root.json",
"definitions": {
"B": {
"$id": "other.json",
},
}
}
#/definitions/B
http://example.com/other.json
http://example.com/other.json#
http://example.com/root.json#/definitions/B
But how is it identified if root schema root.json would be defined under /some/path instead of / path?
{
"$id": "http://example.com/some/path/root.json",
"definitions": {
"B": {
"$id": "other.json",
},
}
}
How other.json should be identified?
http://example.com/other.json
or:
http://example.com/some/path/other.json
And which part of SPEC defines this?
Schemas can be identified by any URI that has been given to them,
including a JSON Pointer or their URI given directly by "$id". In all
cases, dereferencing a "$ref" reference involves first resolving its
value as a URI reference against the current base URI per RFC 3986
[RFC3986].
(Dereferencing section)[http://json-schema.org/latest/json-schema-core.html#rfc.section.8.3.2] of the spec.
The "base URI" is defined in RFC 3986 which is referenced in the JSON Schema specification.
It's not super easy to understand because it's quite complex. In the case of a URL, where the reference to resolve is is a non hash fragment, the base URI is is the URI parts before (but including) the last slash.
(Note: JSON Schema defines that the value of an $id must be an absolute URI, without any fragments.)
So to answer your question specifically other.json should be identified as http://example.com/some/path/other.json.
You can see this in action if you try using the following schema in this online JSON Schema validator...
{
"$id": "http://example.com/blah/root.json",
"definitions": {
"A": {
"$id": "#foo"
},
"B": {
"$id": "other.json",
"definitions": {
"X": {
"$id": "#bar"
},
"Y": {
"$id": "t/inner.json"
}
}
},
"C": {
"$ref": "http://example.com/blah/other.json"
}
},
"properties":{
"a": { "$ref": "#/definitions/C" }
}
}
In the $ref for "C", if you remove /blah, the validator will complain it can no longer resolve the reference.

Taking input as array in swagger not working

I have the following code for my swagger documentation. Here I am trying to create an API where I want to take input as an array of objects. so far I am doing like following.
{
method: 'POST',
path: '/api/Route',
handler: function(request, reply) {
//some operations
reply('Success');
},
config: {
description: 'Create a Route',
tags: ['api', 'user'],
auth: 'UserAuth',
validate: {
payload: {
"array": [{
userId: Joi.string().trim().required(),
status: Joi.number().required()
},
{
userId: Joi.string().trim().required(),
status: Joi.number().required()
},
{
userId: Joi.string().trim().required(),
status: Joi.number().required()
}
]
}
},
plugins: {
'hapi-swagger': {
responseMessages: swaggerDefaultResponseMessages
}
}
}
}
so what actually going on when I run the above code the swagger creates the documentation like this.
this is a link to the image. so please can anybody tell me why I am not getting the whole array in swagger documentation instead getting only one element of the array. and I also saw the Following question but unable to understand in which file they are making these changes. Could anybody help? Thanks in advance.
You could use the array validation of Joi. Then in the input, you could just pass the array into it. for that, you just need to write the following code in your payload instead of what you are writing at present.
payload: {
userData: Joi.array().items({
userName: Joi.string(),
status: Joi.string()
})
}
after that you swagger documentation looks something like this.
userData is your array of objects. and you could give input array of objects as following.
"userData": [{
"userName": "string", // objects
"status": "string"
},
{
"userName": "string", // objects this way you can add more
"status": "string"
}
]

Angular 4 & Rails 5 Post Request JSON Formatting

I'm developing an angular app using a rails backend. I'm having problems formatting the parameters hash so rails can use it. The data is a many to many relationship, and the form contains nested attributes. In Rails, my models utilize the accepts_nested_attributes_for helper. I know exactly what format rails expects, but when I make a POST request, there is one minor detail that's off. I'm going to list below two param hashes. One is what Angular produces, and the other is what Rails expects.
What's off about the Angular request is rails expects a deeper layer of nesting in the expense_expense_categories attributes. I've never understood why rails requires it. What angular produces looks logical to me. My question is.. What do I need to do to format the parameters in Angular? Looking at what I have so far, am I doing this in a way that satisfies Angular best practices?
Angular:
{
"expense": {
"date": "2017/4/13",
"check_number": "132",
"debit": "0",
"notes": "har",
"amount": "24",
"payee_id": "334"
},
"expense_expense_categories_attributes": [{
"expense_category_id": "59",
"amount": 12
},
{
"expense_category_id": "62",
"amount": 11
}
]
}
What Rails expects:
{
"expense": {
"date": "2017/12/12",
"check_number": "122",
"debit": "0",
"notes": "har",
"amount": "24",
"payee_id": "334",
"expense_expense_categories_attributes": {
"210212312": {
"expense_category_id": "72",
"amount": "12"
},
"432323432": {
"expense_category_id": "73",
"amount": "12"
}
}
}
}
My code in angular is as follows.
onSubmit() method in component:
onSubmit() {
this.expenseService.addExpense(this.expenseForm.value)
.subscribe(
() => {
this.errorMessage = '';
},
error => {
this.errorMessage = <any>error;
}
);
this.expenseForm.reset();
}
addExpense in my service file:
addExpense(expense: Expense): Observable<any> {
let headers = new Headers({'Content-Type': 'application/json'});
let options = new RequestOptions({headers: headers});
return this.http.post('http://localhost:3000/expenses', expense, options)
.map(
(res: Response) => {
const expenseNew: Expense = res.json();
this.expenses.push(expenseNew);
this.expensesChanged.next(this.expenses.slice());
})
.catch(this.handleError);
}
my main form:
private initForm() {
let expense_expense_categories_attributes = new FormArray([]);
this.expenseForm = this.fb.group({
id: '',
date: '',
amount: '',
check_number: '',
debit: '',
payee_id: '',
notes: '',
expense_expense_categories_attributes: expense_expense_categories_attributes
});
}
My FormArray for nested attributes:
onAddExpenseCategories() {
(<FormArray>this.expenseForm.get('expense_expense_categories_attributes')).push(
new FormGroup({
'expense_category_id': new FormControl(null, Validators.required),
'amount': new FormControl(null, [
Validators.required
])
})
);
}
UPDATE: I was able to get it working, but I had to use a god awful regex to manipulate the request to what I wanted. It was an extremely ugly option so I still need to find a better option. Is there a better way to format JSON Objects and replace the contents? I'm not sure the correct way to do it. Need help.
You need to add the expense_expense_categories to the wrap_parameters like this:
wrap_parameters :expense, include: [:expense_expense_categories_attributes]
Additional attributes must be explicitly added to wrap_parameters as it only wraps attributes of the model itself by default.

How do I design a ruby equivalent objects for this json structure

I have a json structure that I need to build up based on url parameters provided by a client. Currently I've been building the json structure out using Jbuilder.encode but it's getting pretty hairy.
self.query = Jbuilder.encode do |json|
json.query do
json.filtered do
json.filter do
json.bool do
if(search_term && username)
json.array!(should) do
........
How can I build ruby objects so that I convert them into json based on how they are initialized?
Below is the full json structure I'd like to capture in ruby models/poros (plain old ruby objects).
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [
{
"query": {
"query_string": {
"query": "tablet",
"fields": [
"standard_analyzed_name",
"standard_analyzed_message"
]
}
}
},
{
"term": {
"username": "feedmatic"
}
}
],
"must": [
{
"terms": {
"status_type": [
"3",
"4"
]
}
},
{
"range": {
"created_on": {
"gte": 20140712,
"lte": 1405134711
}
}
}
]
}
}
}
}
}
Hmm i'm not really sure about Poro's, but one thing I've seen is that when the structure starts to get hairy is to make a method that returns the hash representation of what you would like to show. Have you tried making a query method that returns a hash with that structure and then calling it in a jbuilder template?
There's an .attributes method for rails that returns a hash with the attributes, but you would have to look into how to use it with a PORO and if it works for this purpose.

Resources