Best Practices in Retrieving Related Data in a REST API - iphone

So I have a REST API in which I Have a resource in which other resources are linked to (related models, in programming point of view).
So how I am doing it right now is that whenever I request for a resource, related resources are referenced via URLs ('/related_data/related_data_id/').
However, I worry that, let's say there are 5 related resources to the one I'm retrieving, is that I would perform 5 GET requests. I am writing an iPhone client and I'm wondering if this is how to properly do it using REST (that I'm returning URLs). A sample JSON response is this:
{
"meta": {
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 2
},
"objects": [
{
"away_team": "/api/team/3/",
"country": "/api/country/1/",
"event_date": "2011-08-16",
"event_time": "06:00:00",
"event_timezone": "GMT",
"home_team": "/api/team/4/",
"id": "1",
"level": "/api/level/4/",
"resource_uri": "/api/event/1/",
"tournament": "/api/tournament/1/"
},
{
"away_team": "/api/team/4/",
"country": "/api/country/1/",
"event_date": "2011-09-29",
"event_time": "12:00:00",
"event_timezone": "UTC",
"home_team": "/api/team/3/",
"id": "2",
"level": "/api/level/1/",
"resource_uri": "/api/event/2/",
"tournament": "/api/tournament/6/"
}
]
}
Is this a proper way of doing it in REST, considering that "each URI must map to a resource" and all those things?
I am using Django and django-tastypie
Thanks in advance!

Yes; that is proper if the related resources are updated independently. REST architectures depend on caching for performance, and therefore work best with resources which act as atomic entities (see more here). That way, you can update resource B and have its representation be fresh without having to update resource A. See this SO comment for more design details.

Related

how to divide entities and share it in clean architecture

For my new project in flutter, I am trying to follow the Clean Architecture and diving each different feature in domain, data and presentation`.
Now, I have initiated with the Authentication feature where I have started creating the Entities however, I am pretty much confused and stuck on how to modularize the code based on the Clean Architecture practice.
For example,
The response of my login service is as follow,
so do I need to create entities and models for all JSON nested objects like for response , data , user , accountData and permissions ?
or is there any way to use IResponse to store common elements like status , message and data and then use only for relevant feature.
Not sure whether it is allowed to share entities in between the features. Like user block below can be a feature in Authorization and Employee
{
"status": "success",
"message": "successfully login",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6NywiaXNMb2dnZWRJbiI6dHJ1ZSwidGVuYW50SWQiOjEyLCJpYXQiOjE2MjU5OTE5MTAsImV4cCI6MTYyNjA3ODMxMH0.I0z9OIDnQS-MI1ya6usqycoryZ1TBwj3K52BRfrpMuY",
"user": {
"user_id": 7,
"email": "jd#gmail.com",
"first_name": "John",
"last_name": "Doe",
"phone": "",
"date_of_birth": "2015-08-06T00:00:00.000Z",
},
"accountData": {
"name": "Amazon",
"account_id": 1
},
"permissions": [
"ViewAllEmployee",
"AddNewEmployee"
]
}
}

Return several resources in REST call

I am providing access to a REST endpoint where some aggregates are computed.
Let's say the model is as follows:
Purchase:
amount: amount spent
group: one of ELECTRONICS, FOOD, FURNITURE, ...
date: purchase date
Now I want to offer a timeline of purchases, aggregated on a weekly basis, and partitioned by group. This will produce the following data:
{
"ELECTRONICS": [{"week": "2018WK1", "amount": 1000.0}, ...],
"FOOD": [{"week": "2018WK1", "amount": 2000.0}, ...],
"FURNITURE": [{"week": "2018WK1", "amount": 3000.0}, ...],
...
}
Some things to note:
the number of groups is not known in advance (it depends on the stored data)
since this is computed data, I would like to return the whole thing in one single request, instead of having to do the aggregates for each of the groups in separate requests
The URL for the request would be something like: /api/weekly_purchases/2018
How can I offer these kind of resources in a REST API?
Return several resources in REST call
How would you do it as a web page?
Somewhere on your web site would be a link, with text "this week's summary" (or whatever the appropriate concept is in the language of your domain). If a user clicked that link, the browser would do a GET on one URL, which would go to the server, aggregate all of the data together, and return the result.
So do that?
REST doesn't care about the spelling of the URI (the browser doesn't try to interpret the URL, except in very shallow generic ways), so /api/weekly_purchases/2018 is fine.
The trick is recognizing that a report summarizing purchases in the current fiscal year, broken out by week, is a resource. It may have data in it that duplicates the information in other resources, even data in many other resources, but it is still a resource itself.
As already mentioned in my initial comment or by VoiceOfUnreason the same techniques that apply to the browser-based Web apply to any interaction model used by applications that follow the REST architecture principles. As also mentioned by VoiceOfUnreason a client would initially request some state returned from the entry-point, i.e. https://api.acme.com that will return a collection of links a client can use to progress its task. In order for the client to determine which URL to invoke the response should give the URI a meaningful name (link-relation name). IANA maintains a list of already specified link-relation names you should use if possible or define your own one in further standards. According to Fielding the specification of media-types and link relations is one of the most important things to do if developing a RESTful architecture.
For simplicity I use a simplified HAL-JSON syntax throughout the example.
{
...
"_links": {
"self": {
"href": "https://api.acme.com"
},
...
"archives": {
"href": "https://api.acme.com/weekly_purchases"
},
...
}
}
According to the HTML 5 spec archives
indicates that the referenced document describes a collection of records, documents, or other materials of historical interest
The link relation name therefore describes the intent of the URI which client can use if interested in retrieve a collection of historical entries. The client does not really have to know the exact URI as he will learn it by simply following the link relation's target href element. This allows the server to change its internal URI structure anytime it has to without actually breaking clients.
On following the archives target URI a client will not really know yet how the actual data has to be retrieved as the URI and the link relation name are to generic. But the server will guide the client through its task. A response on the invocation of the abovementioned target URI might return the following content:
{
"year": [
"2018": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2018"
}
}
},
"2017": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2017"
}
}
},
...
"2014": {
"_links": {
"chapter": {
"href": "https://api.acme.com/weekly_purchases/2014"
}
}
}
],
"_links": {
"self": {
"href": "https://api.acme.com/weekly_purchases"
},
"first": {
"href": "https://api.acme.com/weekly_purchases"
},
"next": {
"href": "https://api.acme.com/weekly_purchases?p=1"
},
"last": {
"href": "https://api.acme.com/weekly_purchases?p=3"
},
"current": {
"href": "https://api.acme.com/weekly_purchases"
}
}
}
This response basically only teaches the client that there are multiple years available to choose from and the client has to decide which year s/he is interested in an invoke that URI to proceed its task. The next, last and first link relation indicate that there are multiple pages available as only the 5 years per page are returned. The current link relation name will always point to the most recent entry in the collection, which is the initial page (or first page) of the collection-resource. Note further how multiple different link-relation names may point to the same URI. Sometimes it isn't really clear which link relation names to use as their semantics partly overlap. This is just an example on what can be done with link relation names.
A client can now further drill down to the purchases done in 2018 by following the chapter link for 2018. A response on invoking that URI may now look like this:
{
"purchase": [
"W1": {
"sum": 1263.59,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/1"
}
}
},
"W2": {
"sum": 569.32,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/2"
}
}
},
...
"W48": {
"sum": 72.98,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/48"
}
}
},
"current": {
"sum": 72.98,
"currency": "Euro",
"_links": {
"about": {
"href": "https://api.acme.com/weekly_purchases/2018/48"
}
}
}
],
"_links": {
"index": {
"href": "https://api.acme.com/weekly_purchases"
},
"self": {
"href": "https://api.acme.com/weekly_purchases/2018"
},
"current": {
"href": "https://api.acme.com/weekly_purchases/2018"
},
"prev": {
"href": "https://api.acme.com/weekly_purchases/2017"
},
"prev-archive": {
"href": "https://api.acme.com/weekly_purchases/2017"
},
"first": {
"href": "https://api.acme.com/weekly_purchases/2000"
}
}
}
You could either add content here to the weekly summary or hide it down the road by following the about link only if clients are really interested in such details.
Note further: As weekly_purchases is just a string without meaning to the client it does not really know what it means. You could therefore also rename it to purchase-archive or something like that and introduce a further choice to the client and let the client determine whether it wants a weekly, monthly or total summary of that year.
REST is about providing choices to a client and teach it what the actual choices are intended for. One of the aims the RESTful architecture tries to solve is the strict coupling between clients and servers which prevent the latter one from evolving freely and the former ones to break if the latter one changes unexpectedly. This decoupling only works if certain standards are used to increase the likelihood for interoperability. Usually out-of-band information (pre-existing knowledge about the API and how to interact with it) is leading to a coupling. Even Fielding stated that some prior knowledge is needed though but not encoded directly into the application but on reusing certain standards like well-defined and stable media-types and link-relation names.

Creating a domain in Plesk's REST API

So, experimenting with Plesk's REST API (available as of version 17.8) for a project at work, and I'm starting to get a feel for it. I've been trying to experiment with adding a domain, but it's been giving me errors when I have to specify the hosting type.
The request body itself is as follows:
{
"name":"example.com",
"hosting_type":"virtual",
"description":"Description goes here"
}
This gets the following cryptic response:
{
"code": 1014,
"message": "htype\/vrt_hst is specified but there is no hosting\/vrt_hst"
}
Per the documentation provided at /api/v2/swagger.yml, any of the following values should be allowed: virtual, standard_forwarding, frame_forwarding, none
No matter what I put in, however, I get a variant of the response above (htype\/{type} is specified but there is no hosting\/{type}).
At this point I'm kind of stuck; I'm not sure what to check, and any references when I try to look up the error code go to references on Plesk's XML API instead. What's the missing link here needed to get the request to work?
It looks like system user is not specified - hosting_settings. Try to add domain with full json request. Here is example:
{
"name": "example.com",
"description": "My website",
"hosting_type": "virtual",
"hosting_settings": {
"ftp_login": "test_login",
"ftp_password": "test_pwd"
},
"base_domain": {
"id": 7,
"name": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"parent_domain": {
"id": 7,
"name": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"owner_client": {
"id": 7,
"login": "a10-52-41-48.qa.plesk.ru",
"guid": "b623e93d-dc72-4102-b5f0-ded427cf0fb1",
"external_id": "b623e93d-dc72-4102-b5f0-ded427cf0fb1"
},
"ipv4": [
"212.192.122.46"
],
"ipv6": [
"2002:5bcc:18fd:c:123:123:123:123"
],
"plan": {
"name": "Unlimited"
}
}
Examples for REST API https://app.swaggerhub.com/apis/plesk/api/v2#/Domains/post_domains

REST API design for specifying value options

Given a resource like:
GET: /api/examples/1
{
"id": 1,
"direction": "North"
}
Which also supports POST, PUT, how should the possible values for "direction" be specified?
Additionally, is there a solution which allows the consumer to know which values will be available if those values are contextual? e.g. if the example is made more complicated:
GET: /api/examples/
{[
{
"id": 1,
"startLocation": "Kentucky, USA",
"direction": "North"
}
{
"id": 2,
"startLocation": "North Pole",
"direction": "South"
}
}]
(with something vaguely like):
"options": [
{
"value": "North",
"validWhen": "startLocation !== `North Pole`"
},
{
"value": "East",
"validWhen": "true"
},
...
]
Is there a better solution than another resource linked from each example which returns the currently valid options? If not, how does the consumer know that changing "startLocation" changes the valid set of values for "direction"?
I think what you might be looking for is a JSON-Schema. This allows you to strictly describe what options are available in your JSON document, and you can link to the document using a describedBy link.
To expand on what #Justas said in his comment, if I understand your requirements correctly, your resource might look something like:
GET /examples/1
{
"startLocation": "Kentucky, USA",
...
"_links": {
"travel-north": "/some/url",
...
}
}

Facebook Marketing API Campaign spend_cap field returns inconsistently

I'm trying to pull data for each of my Ad Campaigns from the Facebook Marketing API.
In the Ads Insights API there is only a 'spend' field that returns how much of the budget for that campaign has been spent so within the specified date range parameter. This is documented at
developers.facebook.com/docs/marketing-api/insights/fields/v2.9
I would like to get the 'spend_cap' field that's specified in the Reference section of the Marketing API located in the link below. One thing I noted was that there are no parameters available to this node, that may be why the spend_cap is not returning. This is documented at
developers.facebook.com/docs/marketing-api/reference/ad-campaign-group
I am using the following url to request the data.
https://graph.facebook.com/v2.9/{act_id}/campaigns?fields=name,spend_cap&access_token={access_token}
However, it returns the spend_cap field inconsistently, as shown below. I've only included a couple examples but I'm certain that all my campaigns are set up with spending caps.
data:[
{
"id": "##############",
"name": "name1",
"start_time": "2016-06-24T14:47:34-0400",
"stop_time": "2016-07-03T14:47:34-0400"
},
{
"id": "##############",
"name": "name2",
"spend_cap": "30000",
"start_time": "2016-05-16T11:57:10-0400"
},
{
"id": "##############",
"name": "name3",
"spend_cap": "15000",
"start_time": "2016-05-16T11:44:06-0400",
"stop_time": "2017-04-01T00:00:00-0400"
},
{
"id": "##############",
"name": "name4",
"start_time": "2016-05-13T15:34:41-0400",
"stop_time": "2017-05-13T09:46:44-0400"
}
]
The spend_cap at the campaign level is an optional field which is why it is only returned for some of the campaigns.
In general within the Graph API, if a field contains no data, this field will be omitted from the response.
Our SDKs abstract this for you so you can always access a field of an object, regardless of whether it was in the response, so if you're not using one of our SDKs, you'll have to do the same.