Rails 4 API, how to create a URL from a JSON response? - ruby-on-rails

I'm working on an API where I have a few routes setup, ie
http://localhost:3000/phone_number_lookup/1234567890
which can return a JSON response like so:
{
"AccountCode": "1234",
"AccountID": 13579,
"BalanceCurrent": "5000",
"Phone": "1234567890",
"Id": 123123,
"SerialNumber": "Y2K2000XY2016",
"MACADDRESS": "y2k2000xy2016",
"EQUIPMENTTYPE_Name": "Motorola DCX100 HD DVR",
"ADDRESS_Zip": "90210",
"ItemID": 12345,
"iVideoSystemID": 1000001
"id": null
}
The next 'step' of the API consumption would be, 'given the initially returned response, use 4 of those parameters and pass them into a remote URL that will then do something.'
Like so:
http://myremoteURL.com/Service/?Param1=sSerialNumber&Param2=iVideoSystemID&Param3=sMAC&Param4=ItemID
It would be one thing to just set up a route that takes 4 parameters, but the route needs to be contingent on what the initial JSON response was.
What is the proper way to do this?

First of all, you'll have to convert your JSON to hash. Something like this will do:
[7] pry(main)> hash=JSON.parse(json)
=> {"AccountCode"=>"1234",
"AccountID"=>13579,
"BalanceCurrent"=>"5000",
"Phone"=>"1234567890",
"Id"=>123123,
"SerialNumber"=>"Y2K2000XY2016",
"MACADDRESS"=>"y2k2000xy2016",
"EQUIPMENTTYPE_Name"=>"Motorola DCX100 HD DVR",
"ADDRESS_Zip"=>"90210",
"ItemID"=>12345,
"iVideoSystemID"=>1000001,
"id"=>nil}
Then you'll have to choose 4 parameters to send. I just took last 4 parameters
[14] pry(main)> chosen_params = hash.slice("ItemID", "id", "iVideoSystemID", "ADDRESS_Zip")
=> {"ItemID"=>12345, "id"=>nil, "iVideoSystemID"=>1000001, "ADDRESS_Zip"=>"90210"}
Then you'll have to pass them to your remote url. This can be done using a helper described here. Then you'll have to just do something like generate_url("YOUR-URL-ADDR-HERE", chosen_params).
At this point you might want to change the generate_url helper in a way you need it to be to generate the url you need. Maybe it should take third parameter called action which will then generate url like http://www.google.com/action?{chosen_params}
The result will be:
[23] pry(main)> generate_url("http://www.google.com", chosen_params)
=> "http://www.google.com?ADDRESS_Zip=90210&ItemID=12345&iVideoSystemID=1000001&id="
Hope it helps. Let me know about any questions.

Could you modify the JSON response?
{
"AccountCode": "1234",
"AccountID": 13579,
...
"id": null
"follow_up_url": "http://myremoteURL.com/Service/?Param1=sSerialNumber&Param2=iVideoSystemID&Param3=sMAC&Param4=ItemID"
}
This allows your JSON to tell the requester "where to go next".

Related

Response Templating for a Static Json File

I am using WireMock in java to stub for a POST request. The request returns a json body file that is stored in my local. The stub looks like this:
wireMockServer.stubFor(get(urlMatching("/v1/invoices/.*"))
.willReturn(aResponse()
.withStatus(200)
.withBodyFile("testgetupgradeprorationamount/stubThree")));
Part of the response body file, "stubThree" looks like this:
"id": "ii_1EmM93Htp4Kkdrs8",
"object": "line_item",
"amount": 9600,
"currency": "usd",
"description": "Remaining time on 3 × Business after 17 Jun 2019",
"discountable": false,
"invoice_item": "ii_1EmM93HtpLyYzpmOC4Kkdrs8",
"livemode": false,
"metadata": {
},
"period": {
"end": 1563374954,
"start": 1560782957
}
The request url has a number of paramters and looks like this:
/v1/invoices/?subscription_items[0][quantity]=3&subscription_proration_date=1560892137&customer=cus_FHNIIE4b8LH7qL"
The stubbing works fine, but my goal is to give a dynamic response using response templating. I want to update the "start" field of the json file only, using the "subscription_proration_date" value from the request url.
I changed the start field and the stub like this:
"period": {
"end": 1566053354,
"start": "{{request.query.subscription_proration_date}}"
},
wireMockServer.stubFor(get(urlMatching("/v1/invoices/.*"))
.willReturn(aResponse()
.withStatus(200)
.withBodyFile("testgetupgradeprorationamount/stubThree")
.withTransformers("response-template")));
This is not working for me, so any directions would be really helpful. I also tried removing the quotations around the start field handlebar in the file, and that did not work either.
Thank you in advance!
so I was able to resolve my issue. The problem was that I did not add the proper extension to my WireMockServer instance:
.extensions(new ResponseTemplateTransformer(false));
If the boolean value is false, you additionally need to specify the transformer on a per stub basis like I did above. Otherwise, the extension is applied to all stubs.

Customize request format in Ember

I am building a Rails 5 backend API which will receive requests from my Ember app. However I'm having some trouble getting Ember to format the request in a way my Rails server understands.
By default, Rails creates controllers to expect parameters in this format, assuming the model is a, say, Car:
"car": {
"id": "1",
"name": "Foo",
"bar": "Bar",
...
}
However it looks like Ember is sending requests in this format:
"data": [
{
id: "1",
type: "cars",
attributes: {
"name: "Foo",
"bar": "Bar",
...
}
]
What can I do to make Ember send request payloads in a way my Rails server will understand? Thank you.
Your Rails is accepting REST adapter format, for that to work properly, your adapter should extend DS.RESTAdapter and serializer should extend DS.RESTSerializer. By default it will comes with JSONAPIAdapter and JSONAPISerializer.
If you are having control over the back end code, then consider writing json-api format response for that ember will work out of the box.
Reference:
https://emberjs.com/api/ember-data/2.14/classes/DS.RESTAdapter
https://emberjs.com/api/ember-data/2.14/classes/DS.RESTSerializer
https://emberjs.com/api/ember-data/2.14/classes/DS.JSONAPIAdapter
https://emberjs.com/api/ember-data/2.14.9/classes/DS.JSONAPISerializer

Is it possible to pass a Custom Data from the contact list into an external URL?

More specifically, what URL query parameter should I use to pass in a custom data into my URL, if possible?
For instance, I would like to pass in Custom Data 3 to my URL in the format www.website.com/?Custom3=${CustomData3}
("${CustomData3}" does not work.)
I have already asked customer support, but they said it was impossible. I was wondering if anyone else tried to do this and succeeded.
I'm not exactly sure what you are asking for. If you're asking if there is a way to automatically pipe custom data into an external URL, then no there isn't a way within SurveyMonkey to do that. You can pipe custom contact data into a Survey.
But you can manually pipe contact data yourself into an external URL using the API.
For example, you would fetch the contact details:
GET /v3/contacts/<contact_id>
Which will return a response with the details for that contact:
response = {
"id": "1234",
"first_name": "John",
"last_name": "Doe",
"email": "test#surveymonkey.com",
"custom_fields": {
"1": "Mr",
"2": "Company",
"3": "Address",
"4": "City",
"5": "Country",
"6": "Phone Number"
}
}
And then build the URL like:
url = "www.website.com/?Custom3=" + response["custom_fields"]["3"]
And then redirect the user to that URL yourself. You can write a function that reads a string and replaces ${<variable_name>} with the associated custom value (or use any templating engines in whatever programming language you're using e.g. mustache).

Handling better response from Aws::Route53::Client.new

First time trying to use the Ruby AWS ADK V2 and I am trying to format the data i am getting back and it seems quiet hard getting it into useable format.
All I want to do is get a list of Hosted Zones and display in a table.
I have a helper that has:
def hosted_zones
r53 = Aws::Route53::Client.new
#convert to hash first so we can parse and covert to json
h = (r53.list_hosted_zones).to_hash
j = JSON.parse((h.to_json))
end
which then returns me the following JSON:
{
"hosted_zones": [{
"id": "/hostedzone/Z1HSDGASSSME",
"name": "stagephil.com.",
"caller_reference": "2016-07-12T15:33:45.277646707+01:00",
"config": {
"comment": "Private DNS zone for stage",
"private_zone": true
},
"resource_record_set_count": 10
}, {
"id": "/hostedzone/ZJDGASSS0ZN3",
"name": "stagephil.com.",
"caller_reference": "2016-07-12T15:33:41.290143511+01:00",
"config": {
"comment": "Public DNS zone for stage",
"private_zone": false
},
"resource_record_set_count": 7
}],
"is_truncated": false,
"max_items": 100
}
To which I am running a really but while statement to interact through all the hosted_zone entries into a table.
Is this the best way to get the response or can you request the response to be json already?
Why are you converting a hash to JSON, only to convert it to a hash again? JSON.parse(some_hash.to_json) will just give you some_hash.
That being said, I don't think it is possible to get JSON directly from AWS, mainly due to the fact that their API responds with XML. I think that your solution is ideal if that's all you're doing, but if you want, you can make a request with an HTTP client and then take the XML that you receive and use something like ActiveSupport's Hash.from_xml to create a hash that you can then convert to JSON.

With Rails 4 and structured logging, how can I add the request id field to logs?

I am adding structured logging to a Rails 4 app. Using lograge and logstash-logger as describe in this article, I've got things mostly working.
I'm having trouble adding request id to the logs. The closest I've found is to add this to config/${ENV}.rb:
config.log_tags = [:uuid]
But this adds the request id to the tags list, instead of adding it as a named field.
{
"tags": [
"da76b4be-01ae-4cc4-8d3c-87062ea02cfe"
],
"host": "services",
"severity": "DEBUG",
"#version": "1",
"#timestamp": "2016-09-13T17:24:34.883+00:00",
"message": "..."
}
This is problematic. It makes it more awkward and less obvious on how to search for a particular request id. Plus, parsing the message in logstash it overwrites any other tags that are already associated with the log message.
Is there any way that I can add the request id to the log as a named field?
{
"request_id", "da76b4be-01ae-4cc4-8d3c-87062ea02cfe",
"host": "services",
"severity": "DEBUG",
"#version": "1",
"#timestamp": "2016-09-13T17:24:34.883+00:00",
"message": "..."
}
Old question but maybe it will help someone like me who struggled to find a simple way to do this.
Using the custom_payload (instead of custom_options), you can directly access the request received by the controller and get its id to add it to the logs:
config.lograge.custom_payload do |controller|
{
request_id: controller.request.request_id
}
end
No need to configure the log_tags for this to work.
There are several ways to do this. From Lograge, you can use the custom_options:
# all your lograge stuff...
config.lograge.enabled = true
config.lograge.custom_options = lambda do |event|
# use the `event.payload`
{uuid: event.payload[:uuid]}
end
You can overload any option in here - they'll take over the lib's ones.
The code responsible for this is here. The test that shows it work is here.

Resources