How to get included values of jsonapi on a router with ember-data? - ember.js

I'm using jsonapi directives to make a connection between ember.js app and an API. I have a track that could have like 50 or more comments and I need to load them on a route to perform some logic.
This is and example response of the API:
{
"data": {
"id": 1,
"type": "track",
"attributes": {
"name": "XPTO"
},
"relationships": {
"comment": {
"data": [
{"id": 1, "type": "comment"}
]
}
}
},
"include": [
{
"id": 1,
"type": "comment",
"attributes": {
"text": "Lorem ipsum..."
}
}
]
}
Now imagine it with 50 comments, this would be very consuming to make a request for each call. If I do it in a view with an each loop, it doesn't make all the requests, but it I try to access it in a Route, it will make all the requests. How do I achieve that with the following code?
this.store.findRecord('track', 1).then((t) => {
// logic here
// I tried this but it would make all the requests too
t.get('comments');
})

U can use property "coalesceFindRequests" in your adapter
coalesceFindRequests: true
If you set coalesceFindRequests to true it will instead trigger the following request:
GET /comments?ids[]=1&ids[]=2
so this makes only one call for all the comments.
Note: Requests coalescing rely on URL building strategy. So if you
override buildURL in your app groupRecordsForFindMany more likely
should be overridden as well in order for coalescing to work.

Related

GCP DialogFlow CX - returning choice list / buttons in webhook response fulfillment_response or using parameters in custom payload to provide choices

I have created a chatbot in DialogFlow CX. After a customer identifies themselves, a call is made to the webhook (written in Python) which finds the 3 closest retail stores to the customer, and returns those in the webhook response as parameters:
bot_response = {
"fulfillment_response":
{
"messages": [
{
"text": {
"text": [
f'Thanks {first_name}! I\'ve located your account.'
]
}
}
]
},
"session_info": {
"session": session_name,
"parameters": {
"first_name": first_name,
"email_address": email_address,
"business_partner_id": business_partner_id,
"address_line_1": c['response']['address_line_1'],
"address_line_2": c['response']['address_line_2'],
"suburb": c['response']['suburb'],
"postcode": c['response']['postcode'],
"region": c['response']['state'],
"store_1": locations[0].store_name,
"store_1_id": locations[0].store_id,
"store_1_address": locations[0].address,
"store_2": locations[1].store_name,
"store_2_id": locations[1].store_id,
"store_2_address": locations[1].address,
"store_3": locations[2].store_name,
"store_3_id": locations[2].store_id,
"store_3_address": locations[2].address
}
}
}
My intention is to allow the customer to select 1 of these 3 store locations. In the above model, I've returned them as parameters, which are successfully recorded in dialogflow, however I am stuck on how to provide these values as a list of options to the customer. I am unsure whether I can
a) Provide a list of options back to the user as a Webhook Response (instead of parameters). All documentation I can find suggests only that text and parameters can be returned.
Or
b) Use the returned parameters to create a custom payload to present them as a list for the user to select from. Something like:
{
"richContent": [
[
{
"event": {
"name": "Store1",
"parameters": {},
"languageCode": ""
},
"subtitle": "${store_1_id}",
"title": "${store_1_address}",
"type": "list"
}
]
]
}
But I cannot find any documentation to suggest you can embed parameters into custom payloads.
Does anyone know of a way to solve this situation? Thank you!
As per usual, the mere act of posting a question on Stack Overflow somehow creates a higher statistical likelihood that I will in fact answer my own question. It's simple enough to add it to a custom payload to present in a list, simply using the syntax:
{
"richContent": [
[
{
"event": {
"name": "Store1",
"parameters": {},
"languageCode": ""
},
"subtitle": "$session.params.store_1_address",
"title": "Store 1",
"type": "list"
}
]
]
}

How to test API Gateway methods with custom authorizer and empty $context.authorizer.* variables?

I have an API Gateway with a POST method that puts directly to a DynamoDB table. My method is also configured to use a custom authorizer via Lambda.
In my template mapping I'm consuming some of the authorizer variables, such as $context.authorizer.principalId or $context.authorizer.accountId. Simplified template mapping looks as follows:
{
"TableName": "$stageVariables.tableName",
"Item": {
"AccountId": {
"S": "$context.authorizer.accountId"
},
"Id": {
"S": "$context.requestId"
},
"Content": {
"S": "$input.path('$.content')"
},
"UserId": {
"S": "$context.authorizer.principalId"
}
}
}
Now, when I make an HTTP request to this API method deployed to a an actual stage, that request will go through the custom authorizer and provide / fill in all $context.authorizer.* variables in the template which might look like this:
{
"TableName": "MyTable",
"Item": {
"AccountId": {
"S": "12345"
},
"Id": {
"S": "6fd5ff08-34c0-11e7-bf96-591a565835b3"
},
"Content": {
"S": "my content"
},
"UserId": {
"S": "userid-123456789"
}
}
}
When testing the API method via the API Gateway Test button, the test request is bypassing the custom authorizer (which makes sense, since authorizer can be tested separately) and produces a result like this:
{
"TableName": "MyTable",
"Item": {
"AccountId": {
"S": ""
},
"Id": {
"S": "test-invoke-request"
},
"Content": {
"S": "my content"
},
"UserId": {
"S": ""
}
}
}
The following content is now invalid, since all fields get validated against the model, and getting the following validation error:
Endpoint response body before transformations: {"__type":"com.amazon.coral.validate#ValidationException","message":"One or more parameter values were invalid: An AttributeValue may not contain an empty string"}
Is there some way to specify authorizer variables when testing API Gateway methods?
Or is there some smart way to define a fallback variable in the template mapping so that when it resolves to empty, it will fall back to, e.g., test-invoke-principalid, just like $context.requestId gets that out of the box?
All I want is to be still able to use the API Gateway test feature while keeping all the validation / authorizer settings in place.
Sure we can look at adding placeholders for the test invoke feature. Certainly for the principalId. As for the custom context variables, that might be more difficult, we'll see. We eventually would like to have a better end-to-end testing solution as well.

Delete record Libcloud (GoDaddy api)

I try to implement delete method for Record delate-record, but its my first time to use python and this api.
The GoDaddy API doesn't have a delete record method, so this functionality is not exposed in the driver.
https://developer.godaddy.com/doc#!/_v1_domains/recordReplace
The driver could offer the 'replace records in zone' method, which would allow you to fetch the current list of records, and then set the new list minus the record you want to remove. But that feature is not implemented and quite risky.
First,
Send a GET request to https://api.godaddy.com/v1/domains/{DOMAIN}/records
Then, Enumerate over all records of API Response (JSON Array) and prepare new data by removing the one that needs to be deleted.
API Response (SAMPLE)
[
{
"data": "192.168.1.1",
"name": "#",
"ttl": 600,
"type": "A"
},
{
"data": "ns1.example.com",
"name": "#",
"ttl": 3600,
"type": "NS"
},
{
"data": "#",
"name": "www",
"ttl": 3600,
"type": "CNAME"
},
{
"data": "mail.example.com",
"name": "#",
"ttl": 3600,
"priority": 1,
"type": "MX"
}
]
New Data (After deleting record) (SAMPLE)
[
{
"data": "192.168.1.1",
"name": "#",
"ttl": 600,
"type": "A"
},
{
"data": "ns1.example.com",
"name": "#",
"ttl": 3600,
"type": "NS"
},
{
"data": "#",
"name": "www",
"ttl": 3600,
"type": "CNAME"
}
]
Now,
Send a PUT request to https://api.godaddy.com/v1/domains/{DOMAIN}/records with new data.
The most important thing is how you identify the records in above array which needs to be deleted. This would not be a difficult task, assuming you have good programming skills.
I managed to worked around it in kind of a hacky - we had bunch of records we wanted to delete, doing it manually seemed weird so I added a Javascript into the Chrome Developer Console, running on an authenticated session from the DNS manage page:
function deleteGoDaddyRecords(recordId) {
$.ajax({
url: 'https://dcc.godaddy.com/api/v3/domains/<YOUR-DOMAIN.com>/records?recordId='+recordId,
type: 'DELETE',
success: function(result) {
console.log(result)
}
});
}
which let me use the same call the UI is calling when you ask to delete a record.
the only thing you need to provide is the AttributeUid which is not available with the public API, but it is in the front-end API:
https://dcc.godaddy.com/api/v2/domains/runahr.com/records
So I managed to create a script that will generate bunch of
deleteGoDaddyRecords('<RECORD-UUID>');
deleteGoDaddyRecords('<RECORD-UUID>');
copy & paste the generated script into the Developers Console and that solved it for now.
I hope GoDaddy will add a public DELETE endpoint to their API in the future :)

jsonapi + ember 2.0 + pagination

How to do pagination in latest version of ember-data (v2.2) and a jsonapi backend?
I am in control of the backend implementation so I can implement any strategy, but I would prefer to follow the standard as described here:
http://jsonapi.org/format/#fetching-pagination
However, that description is a bit cryptic to me without an example.
And how to handle that smoothly on the client (ember) side?
Is there some built in stuff in ember-data to process the paging-links?
EDIT:
I guess to get started I must process the meta information. By overriding the serializer. At the time deserialize is called I can read the meta from the payload but at that time I don't have an object to store it on. Later when my object is done deserialized I don't have access to the payload with the meta information.
Does that make sence? Here is my example payload:
{
"data": {
"id": "1",
"type": "user",
"attributes": {
"firstname": "John",
"lastname": "Doe",
"email": "john.doe#example.com",
}
},
"included": [{
"id": "68",
"type": "activity",
"attributes": {
"title": "Yoga",
}
}, {
"id": "65",
"type": "activity",
"attributes": {
"title": "Slalom",
}
}],
"meta": {
"activity-total": "23",
"activity-pagesize": "2",
"activity-offset": "0"
}
}
Where to put my code that reads the meta information and stores it on the user object?
You could use the Ember Infinity Addon. It does all the magic for you.

Where/when should I remove the relationship type to avoid an unknown keys warning?

I'm using Ember Data with a server application that follows the json:api standard. When I normalize the response from the server, I'm adding a relationshipType attribute from the links so that Ember Data knows what type of model to build when the relationship is polymorphic.
For example, here's the response from the server:
{
"members": {
"id": "1",
"created_at": "2014-10-15T18:35:00.000Z",
"updated_at": "2014-10-15T18:35:00.000Z",
"links": {
"user": {
"id": "1",
"type": "users",
"href": "http://test.host/api/v1/users/1"
},
"organization": {
"id": "2",
"type": "customers",
"href": "http://test.host/api/v1/customers/2"
}
}
}
}
The organization relationship is polymorphic, and the type in this instance is customers.
In the Ember application, I'm normalizing the response into following (which follows the RESTSerializer convention):
{
"members": {
"id": "1",
"created_at": "2014-10-15T18:35:00.000Z",
"updated_at": "2014-10-15T18:35:00.000Z",
"user": "1",
"userType": "users",
"organization": "2",
"organizationType": "customers"
}
}
This works, and Ember Data builds the correct user relationship and organization relationship (using the Customer model).
But, I'm receiving the following warning:
WARNING: The payload for '(subclass of DS.Model)' contains these unknown keys:
[userType,organizationType]. Make sure they've been defined in your model.
I'd like to remove these relationshipType keys and their values after they've been used.
Where should I do this?
Have you tried using https://github.com/kurko/ember-json-api? I may have some other overrides in my app to handle polymorphism but hopefully the package will get you closer.
Also see my pending PR.