Why is a rails POST/PUT format different to GET by default? - ruby-on-rails

Say I have a ruby model which has a name and age attribute. A GET request for one of these objects returns something like this when using rails generate scaffold:
{
"id": 1,
"name": "foo",
"age": 21,
"parent_id": 1
}
By default a POST/PUT to this resource expects:
{
"user": {
"name": "foo",
"age": 21,
"parent_id": 1
}
}
When using nested resources configured in routes the default behaviour is to add the parent id outside of this nested hash too, e.g.: PUT /parents/1/users:
{
"parent_id": 1,
"user": {
"name": "foo",
"age": 21
}
}
I can go to the controller simply enough and alter what parameters are expected, but I'd like to know why that is the case and if I risk breaking anything if changing it.
More specifically this is a Rails API and I'd like to add swagger doc generation to the API, so having this asymmetrical request body is annoying.
So in summary my questions are:
What are the advantages of this, why is it the Rails default and what do I risk breaking by changing it?
How best to add swagger support to the API in a way which doesn't have different GET responses vs PUT/POST (which seems like bad design to me, but maybe I'm wrong)?
How best/should I make the API automatically add the parent id when making a call like POST /parents/1/users, because again the default generation doesn't support it and I'm wondering if there's a reason

What are the advantages of this?
This is perhaps an opinion-based answer, which is generally frowned upon by StackOverflow, but here's my 2 cents.
In the GET request, you are simply being returned a resource. So the attributes are all you need to know:
{
"id": 1,
"name": "foo",
"age": 21,
"parent_id": 1
}
On the other hand, for this PUT request:
{
"parent_id": 1,
"user": {
"name": "foo",
"age": 21
}
}
You can think of the parameters as being split into two "sections": The parent_id (which would normally get sent as a path param, not part of the request body!) is something to "search/filter" by, whereas the user params are the attributes of the user resource to update.
This logical separation of concerns is particularly useful in the context of web forms (which is what Rails was originally/primarily designed for), especially when dealing with complex queries or "nested" attributes.
what do I risk breaking by changing it?
Nothing really.
That format, however, was "optimised" for the context of RESTful APIs and web forms.
If you'd rather use some other format then go ahead; Rails isn't forcing you to use anything here. Just beware that a naive "better design" may come back to bite you down the line.
How best to add swagger support to the API in a way which doesn't have different GET responses vs PUT/POST (which seems like bad design to me, but maybe I'm wrong)?
You can design the API any way you like. If you want "flat parameters" everywhere, then just build the Rails application like that.
How best/should I make the API automatically add the parent id when making a call like POST /parents/1/users, because again the default generation doesn't support it and I'm wondering if there's a reason
I'm not sure what you mean by "the default generation doesn't support it". The default generation of what? The swagger docs? The rails application?
Anyway... That should be implemented as a path parameter. The swagger docs should look something like this:
/parents/{parent_id}/users:
get:
description: '.....'
parameters:
- name: parent_id
in: path
description: 'ID of the parent'
required: true
type: integer

Tom Lord’s answer and note is probably better than mine.
My guess is that this mimics the behaviour of HTTP. If you GET data, you can add parameters (?name=foo). However, if you POST data, you tend to put the payload in the body of the request. And not have any parameters in the URL.
It’s likely that Rails thinks that you’re going put that JSON object into the body of the request. Whereas the GET request it’s going to split the key/values apart and send as parameters.
The advantages of keeping it the way they are is that it’ll avoid a gotcha later. I’d argue this is always the best thing to do in programming, but also especially something like Rails. But, if you’re making an API I can see why you’d want to let people send data as parameters rather than a body that needs validating.
As for Swagger, let the user know they need to send the data as a JSON string, and then use the parameters feature as expected.
Last one is a bit tricky. I guess it’s up to the design of your API. You could pass it as part of the request. Maybe take a look through sometihng like RESTful API Design to clarify your goal.

Related

Azure Logic Apps Problem with Liquid Transformation of SOAP XML

I'm using Azure Logic Apps to integrate with a legacy SOAP API. I would like to translate the XML (particularly the responses) in to something easier to use such as json.
Normally I use a Custom Connector within Logic Apps to connect to new APIs. I've tried to create a Custom Connector for this SOAP, but the WSDL contains recursive references which apparently aren't allowed. I was able to create managed API with our APIM container, but still could not produce anything that would allow me to create the custom connector. So, I moved on to dealing with the transactions individually. A Liquid transformation map from XML to json seems ideal, but so far I haven't got it to work, namely because I can't figure out the naming convention to access certain XML elements (those that happen to have the same id as their parent). For now I am using the json(xml()) function as a work around, but it seems less ideal than a Liquid map.
As you can see the AgreementId is easily accessible via the normal naming conventions, but I can't seem to access any of the child elements of the 2nd RequestReportResponse node.
This is the XML I'm trying to transform:
<SOAP-ENV:Envelope>
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<RequestReportResponse>
<MessageHeader>
<AgreementId>urn:agreementId:</AgreementId>
</MessageHeader>
<RequestReportResponse>
<Extension>csv</Extension>
<FileByteArray>xyzFileBytes</FileByteArray>
<FileName>xyzFileName</FileName>
<StatusCode>200</StatusCode>
<StatusDescription>SUCCESS</StatusDescription>
</RequestReportResponse>
</RequestReportResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Here is the Liquid map I'm using:
{
"AgreementId": " {{content.Envelope.Body.RequestReportResponse.MessageHeader.AgreementId}}",
"FileByteArray": "{{content.Envelope.Body.RequestReportResponse.RequestReportResponse.FileByteArray}}",
"FileName": "{{content.Envelope.Body.RequestReportResponse.RequestReportResponse.FileName}}",
"StatusCode": "{{content.Envelope.Body.RequestReportResponse.RequestReportResponse.StatusCode}}",
"StatusDescription": "{{content.Envelope.Body.RequestReportResponse.RequestReportResponse.StatusDescription}}"
}
Expected result:
{
"AgreementId": "urn:agreementId:",
"FileByteArray": "xyzFileBytes",
"FileName": "xyzFileName",
"StatusCode": "200",
"StatusDescription": "SUCCESS"
}
Actual result:
{
"AgreementId": "urn:agreementId:",
"FileByteArray": "",
"FileName": "",
"StatusCode": "",
"StatusDescription": ""
}
It seems liquid doesn't have good support for the nested same tag name, we can use xslt instead to operate the xml and then transform to json which we want. But it's better for us to improve the format of xml resource to escape nested same tag name.

Having a POJO like feature in KarateAPI?

I have been using Karate and RestAssured for sometime. There are advantages and downside of both tools of course. Right now I have a RestAssured project where I have Request and Response object and POJOs. My requests wraps my endpoint and send my POJOs to those endpoint. I do all my Headers, etc configuration in an abstract layer. In case I need to override them, I override them during the test. If not, Its a two lines of code for me to trigger an endpoint.
My way of working with happy path and negative path of an edpoint is that I initialize the POJO before every test with new values in the constructor. Then I override the value that I want in test scope. For example, if I want to test a negative case for password field, I set this field to empty string during the test. But other fields are already set to some random stuff before the test.
But I dont know how to achieve this with Karate.
Karate allows me to create a JSON representation of my request body and define my parameters as seen below example.
{
"firstName": "<name>",
"lastName": "<lastName>",
"email": "<email>",
"role": <role>
}
Then in every test I have to fill all the fields with some data.
|token |value|
|name |'canberk'|
|lastName |''|
|email |'canberk#blbabla.com'|
|role |'1'|
and
|token |value|
|name |''|
|lastName |'akduygu'|
|email |'canberk#blbabla.com'|
|role |'1'|
It goes on like this.
It's ok with a 4 fields JSON body but when the body starts to have more than 20 fields, it become a pain to initialise every field for every test.
Does Karate have a way of achieving this problem with a predefined steps of I need to come up with a solution?
There are advantages and downside of both tools of course.
I'm definitely biased, but IMHO the only disadvantage of Karate compared to REST-assured is that you don't get compile time safety :) I hope that you have seen this comparison.
Karate has multiple ways to do what you want. Here's what I would do.
create a JSON file that has all your "happy path" values set
use the read() syntax to load the file (which means this is re-usable across multiple tests)
use the set keyword to update only the field for your scenario or negative test
You can get even more fancier if you use embedded expressions.
create a JSON file that has all your "happy path" values set and the values you want to vary look like foo: '##(foo)'
before using read() you init some variables for e.g. * def foo = 'bar' and if you use null that JSON key will even be removed from the JSON
read() the JSON. it is ready for use !
You can refer to this file that demonstrates some of these concepts for XML, and you may get more ideas: xml.feature

What is this url string concept called?

I have just been on a website and I noticed they have a strange query string structure in the URL, they seem to be key value pairs and when you make a change in the website form the values update in the URL.
Here is the URL:
http://www.holidaysplease.co.uk/holiday-finder/#{"d":"2016-06-1","a":[],"t":20,"r":200,"f":13,"tr":180,"s":[5,4,3],"ac":[],"c":[],"sh":[],"dh":[],"du":null,"b":"500-4407"}
Does anyone know what this concept is called? I recall seeing it once in a Java based web application but can someone reassure me how this is achieved and in what language?
It looks like this is a fragment identifier.
Wikipedia says:
The fragment identifier introduced by a hash mark # is the optional last part of a URL for a document. It is typically used to identify a portion of that document. The generic syntax is specified in RFC 3986. The hash mark separator in URIs does not belong to the fragment identifier.
RFC 3986 is defined here.
Before, I never saw that before. The upper information is what a little bit of research gave me back. I hope this is not completely wrong.
The text after a # in a URL is a fragment identifier, which is normally used to refer to a section in the document, but can contain any data which won't be sent in the request to the server, but can be read by the client using JavaScript.
In your example, the fragment identifier contains a data structure encoded with JSON, which is a serialization format supporting key-value pairs and arrays.
Here's the JSON from your example in a more readable form:
{
"d": "2016-06-1",
"a": [],
"t": 20,
"r": 200,
"f": 13,
"tr": 180,
"s": [
5,
4,
3
],
"ac": [],
"c": [],
"sh": [],
"dh": [],
"du": null,
"b": "500-4407"
}
The concept behind this is the data which the user entered is send to the server as the JSON structure in the URL. The server reads the string as a JSON and it process the request.
This process is very effective in WebForm and it can be done using the method called encodeURIComponent.
I think you noticed that when the date is changed, it just update the JSON in the URL. So, they send the data filled to the server in a JSON format.
In your URL,
d - days and year
du - duration
a - holiday type
t - temperature
r - rainfall
f- fight time
tr - travel
s - star for the hotels
b - budgets
Hope this information helps you :)
The part after the # is called a fragment identifier. Client-side javascript code can access the content of the fragment using location.hash. In this case the fragment contains json data. The browser will typically not even send the fragment to the web server, so it's only used client-side.
The most common use of the fragment identifier is to link to a specific element on a web page using it's id attribute. This is used for subsections of wikipedia articles:
https://en.wikipedia.org/wiki/Fragment_identifier#Basics
When the fragment contains json, you can inspect the data by opening up your browser's javascript console and calling this code.
JSON.parse(location.hash.substr(1))
This kind of scheme can be used by single page applications to store state in the url, so that you can bookmark it and share the url.

Where to put Bit.ly API call in Rails app

I'm planning on using Bit.ly Pro and the Bit.ly API to make my own short urls in a Rails 3 project.
I've got a User and a Note model. And a url structure like this: '/username/1-note-title'.
Now I would like to give each note a short url. But I don't know from where I should do the API call. Right now I got this code in the Note controller but I don't know if that's the right place or how to get the url of the specific note...
url = ???
parsed_json = JSON('http://api.bit.ly/v3/shorten?login=bitlyapidemo&apiKey=R_0da49e0a9118ff35f52f629d2d71bf07&longUrl=' + url + '&format=json')
#short_url = parsed_json["data"]["url"]
The JSON object structure just for reference:
{
"status_code": 200,
"data": {
"url": "http://bit.ly/cmeH01",
"hash": "cmeH01",
"global_hash": "1YKMfY",
"long_url": "http://betaworks.com/",
"new_hash": 0
},
"status_txt": "OK"
}
Help wanted, thanks in advance!
I seems that the short url should get created when a new note is created for a given user. In that context it would happen as the result of a create action in the NotesController (typically). Best practice would suggest that the logical responsibility should live the Note model so I would suggest you do the bit.ly shortening implemented in a save callback, either before or after, depending on how critical it is (in the context of your particular app) for a shortened URL to exist.
The challenge is do deal with the error case which is when the bit.ly service is unable to respond to your shortening request at all or is taking too long in so doing. That's when putting it in the callback may not make sense as it could potentially tie up your application when trying to fulfill the request.
If you don't need live URL shortening then you could consider creating shortening requests as queued jobs in a background process to be done asynchronously (retrying as necessary) and be triggered in the aforementioned after_save callback in your Note model

Multiple key/value pairs in HTTP POST where key is the same name

I'm working on an API that accepts data from remote clients, some of which where the key in an HTTP POST almost functions as an array. In english what this means is say I have a resource on my server called "class". A class in this sense, is the type a student sits in and a teacher educates in. When the user submits an HTTP POST to create a new class for their application, a lot of the key value pairs look like:
student_name: Bob Smith
student_name: Jane Smith
student_name: Chris Smith
What's the best way to handle this on both the client side (let's say the client is cURL or ActiveResource, whatever..) and what's a decent way of handling this on the server-side if my server is a Ruby on Rails app? Need a way to allow for multiple keys with the same name and without any namespace clashing or loss of data.
My requirement has to be that the POST data is urlencoded key/value pairs.
There are two ways to handle this, and it's going to depend on your client-side architecture how you go about doing it, as the HTTP standards do not make the situation cut and dry.
Traditionally, HTTP requests would simply use the same key for repeated values, and leave it up to the client architecture to realize what was going on. For instance, you could have a post request with the following values:
student_name=Bob+Smith&student_name=Jane+Smith&student_name=Chris+Smith
When the receiving architecture got that string, it would have to realize that there were multiple keys of student_name and act accordingly. It's usually implemented so that if you have a single key, a scalar value is created, and if you have multiples of the same key, the values are put into an array.
Modern client-side architectures such as PHP and Rails use a different syntax however. Any key you want to be read in as an array gets square brackets appended, like this:
student_name[]=Bob+Smith&student_name[]=Jane+Smith&student_name[]=Chris+Smith
The receiving architecture will create an array structure named "student_name" without the brackets. The square bracket syntax solves the problem of not being able to send an array with only a single value, which could not be handled with the "traditional" method.
Because you're using Rails, the square bracket syntax would be the way to go. If you think you might switch server-side architectures or want to distribute your code, you could look into more agnostic methods, such as JSON-encoding the string being sent, which adds overhead, but might be useful if it's a situation you expect to have to handle.
There's a great post on all this in the context of JQuery Ajax parameters here.
Send your data as XML or JSON and parse whatever you need out of it.

Resources