Does it make sense to define a GET /users/{id}/photos route or should I just send multiple GET /photos/{id} requests to return a user's photos? - api

This is a dilemma I find myself facing very often when dealing with nested resources.
So suppose the target user has n photos. Does it make sense to define a GET /users/{id}/photos route or should I just send n GET /photos/{id} requests by first requesting the User object and then looping through that User's photo_ids attribute?

From a best practices perspective, I would not send several request for such similar resources. In that scenario, you end up creating more work for yourself by having to rate limit on the backend, in order to keep your users with a lot of pictures from blowing up your server. That would be impactful to your UX as well.
I recommend you format your route as such:
GET /users/photos?id={{id}}
And return all associated photos with that user ID all at once. You can always limit that to X number of photos per call too, and paginate:
GET /users/photos?id=658&page={{1,2,3, etc.}}
My personal preference is always to try to keep variable data in the URL parameters. Having spent the afternoon with several unrelated APIs, I can tell you a whole slew of developers agree.

Related

Calculating Steam Inventory Value

I don't have problem with getting inventory items. But I can't calculate items prices efficiently.
Valve doesn't have an api for prices.
What i have tried (using "steamcommunity.com") (javascript for example):
itemHashNameArray.forEach((hashname) => {
let url = `https://steamcommunity.com/market/priceoverview/&appid=730&market_hash_name=${hashname}`;
let itemDetails = steamApi(url);
//"steamApi" function just sends get request to site and returns response as json.
let itemPrice = parseFloat(itemDetails.lowest_price.split(" ")[0].replace(",", "."));
})
"steamcommunity.com/market" allows you to get 1 item price per request.
It is very slow / not efficient. Also steam blocks you after so many request.
Third partie apis that I found, allows 1 item per request too.
And they don't even support other currencies except dollar.
I need to calculate for other currencies too.
Is there faster and better way/api?
Just to clarify what's going on:
Most webpages and APIs have limits as far as requests, this helps prevent malicious DoS attacks or simply too much of a resource drain (often costly too). I've ran into this trouble with trying to pull Wikipedia/DBPedia information.
While this is annoying, often times a company or a third-party will recognize the need for doing bulk transactions against their data, and open up an API (usually for a fee): https://partner.steamgames.com/doc/gettingstarted
Some third parties include SteamApis and Steamlytics.
There is a whole subreddit dedicated to this too, here's a relevant post for the API call to get all of a user's inventory items: https://www.reddit.com/r/SteamBot/comments/jey4sg/help_i_am_trying_to_make_a_script_that_counts_the/
Potentially another option is to roll-your-own API service, which could somehow pull inventory data at a rate that doesn't hit limits. Not sure of the legality of this or what kind of hoops third parties have had to jump through, and it would be the most costly probably unless you start charging for its usage. I think loading the full html and then writing a parser to dissect some of that information with straight Javascript or JQuery would alleviate some of the calls looking like spam, but that probably has a limit too and I'm unsure that would include all of the relevant information easily available.

How to get reposted tracks from my activities?

Using the Souncloud API, I'd like to retrieve the reposted tracks from my activities. The /me/activities endpoint seems suited for this and I tried the different types provided.
However, I didn't find out how to get that data. Does anyone know?
Replace User Id, limit and offset with what you need:
https://api-v2.soundcloud.com/profile/soundcloud:users:41691970?limit=50&offset=0
You could try the following approach:
Get the users that shared a track via /tracks/{id}/shared-to/users endpoint.
Fetch the tracks postet by this user via /tracks endpoint, as the _user_id_ is contained.
Compare the tracks metadata with the one you originally posted.
I am not into the Soundcloud API, but taking a close look at it seems to make this approach at least as technical possible, though e.g. fetching all tracks won't be a production solution, of course. It's more a hint. Perhaps reposting means something totally different in this context.
And the specified entpoint exists in the general api doc, so I don't know if you would have to extend the java-api-wrapper for using it.

RESTfully creating object graphs

I'm trying to wrap my head around how to design a RESTful API for creating object graphs. For example, think of an eCommerce API, where resources have the following relationships:
Order (the main object)
Has-many Addresses
Has-many Order Line items (what does the order consist of)
Has-many Payments
Has-many Contact Info
The Order resource usually makes sense along with it's associations. In isolation, it's just a dumb container with no business significance. However, each of the associated objects has a life of it's own and may need to be manipulated independently, eg. editing the shipping address of an order, changing the contact info against an order, removing a line-item from an order after it has been placed, etc.
There are two options for designing the API:
The Order API endpoint intelligently creates itself AND its associated resources by processing "nested resource" in the content sent to POST /orders
The Order resource only creates itself and the client has to make follow-up POST requests to newly created endpoints, like POST /orders/123/addresses, PUT /orders/123/line-items/987, etc.
While the second option is simpler to implement at the server-side, it makes the client do extra work for 80% of the use-cases.
The first option has the following open questions:
How does one communicate the URL for the newly created resource? The Location header can communicate only one URL, however the server would've potentially created multiple resources.
How does one deal with errors? What if one of the associons has an error? Do we reject the entire object graph? How is that error communicated to the client?
What's the RESTful + pragmatic way of dealing with this?
How I handle this is the first way. You should not assume that a client will make all the requests it needs to. Create all the entities on the one request.
Depending on your use case you may also want to enforce an 'all-or-nothing' approach in creating the entities; ie, if something falls, everything rolls back. You can do this by using a transaction on your database (which you also can't do if everything is done through separate requests). Determining if this is the behavior you want is very specific to your situation. For instance, if you are creating an order statement you may which to employ this (you dont want to create an order that's missing items), however if you are uploading photos it may be fine.
For returning the links to the client, I always return a JSON object. You could easily populate this object with links to each of the resources created. This way the client can determine how to behave after a successful post.
Both options can be implemented RESTful. You ask:
How does one communicate the URL for the newly created resource? The Location header can communicate only one URL, however the server would've potentially created multiple resources.
This would be done the same way you communicate linkss to other Resources in the GET case. Use link elements or what ever your method is to embed the URL of a Resource into a Representation.

REST best practices: should a store also return metadata?

I'm building my first REST API (at least trying) for a personal project.
In this project there are resources called players which hold can be in a team. According to REST API design rulebook a resource should be made either to be a document or a store and one should keeps these roles as segregated as possible.
Yet I would like to append some metadata to the team resource, eg the date the team was founded. Is it okay then for GET /teams/atlanta to return this metadata (making it a document) alongside the list of players in the team (making it a store).
Is this a good idea? If so why? If not why not and how to solve this better?
I know there are no rules to developing a REST API, but there are good practices and I would like to adhere to those. Please also not that this is really my first REST API so pardon my ignorance if there is any.
I would recommend having GET /teams/atlanta return just the information about the team, such as the founding date that you mention, and then having GET /teams/atlanta/players return the list of players for that team. These distinctions become more important when you are presenting an API that uses HTTP methods other than GET.
For example, if you wanted to add a player to a team - this would be a lot easier if you could just POST a player object to /teams/atlanta/players than if you had to PUT the whole team object to /teams/atlanta every time you wanted to add one individual player.
If your API only allows retrieval of data, and if it is for a specific client application, there is an argument for combining all the team data into one object to save the client having to make additional requests for the data, but bear in mind that it is less flexible.
Your application may want to display a list of teams by calling GET /teams but you probably wouldn't want all of the player information included in each object in the list as this is quite a lot of data, but if GET /teams/atlanta returns player information then it would be inconsistent not to include it in the list version too.
I would personally favour splitting up the resources as I've suggested, and live with the fact the client may need to make an extra request or two.

The REST-way to check/uncheck like/unlike favorite/unfavorite a resource

Currently I am developing an API and within that API I want the signed in users to be able to like/unlike or favorite/unfavorite two resources.
My "Like" model (it's a Ruby on Rails 3 application) is polymorphic and belongs to two different resources:
/api/v1/resource-a/:id/likes
and
/api/v1/resource-a/:resource_a_id/resource-b/:id/likes
The thing is: I am in doubt what way to choose to make my resources as RESTful as possible. I already tried the next two ways to implement like/unlike structure in my URL's:
Case A: (like/unlike being the member of the "resource")
PUT /api/v1/resource/:id/like maps to Api::V1::ResourceController#like
PUT /api/v1/resource/:id/unlike maps to Api::V1::ResourceController#unlike
and case B: ("likes" is a resource on it's own)
POST /api/v1/resource/:id/likes maps to Api::V1::LikesController#create
DELETE /api/v1/resource/:id/likes maps to Api::V1::LikesController#destroy
In both cases I already have a user session, so I don't have to mention the id of the corresponding "like"-record when deleting/"unliking".
I would like to know how you guys have implemented such cases!
Update April 15th, 2011: With "session" I mean HTTP Basic Authentication header being sent with each request and providing encrypted username:password combination.
I think the fact that you're maintaining application state on the server (user session that contains the user id) is one of the problems here. It's making this a lot more difficult than it needs to be and it's breaking a REST's statelessness constraint.
In Case A, you've given URIs to operations, which again is not RESTful. URIs identify resources and state transitions should be performed using a uniform interface that is common to all resources. I think Case B is a lot better in this respect.
So, with these two things in mind, I'd propose something like:
PUT /api/v1/resource/:id/likes/:userid
DELETE /api/v1/resource/:id/likes/:userid
We also have the added benefit that a user can only register one 'Like' (they can repeat that 'Like' as many times as they like, and since the PUT is idempotent it has the same result no matter how many times it's performed). DELETE is also idempotent, so if an 'Unlike' operation is repeated many times for some reason then the system remains in a consistent state. Of course you can implement POST in this way, but if we use PUT and DELETE we can see that the rules associated with these verbs seem to fit our use-case really well.
I can also imagine another useful request:
GET /api/v1/resource/:id/likes/:userid
That would return details of a 'Like', such as the date it was made or the ordinal (i.e. 'This was the 50th like!').
case B is better, and here have a good sample from GitHub API.
Star a repo
PUT /user/starred/:owner/:repo
Unstar a repo
DELETE /user/starred/:owner/:repo
You are in effect defining a "like" resource, a fact that a user resource likes some other resource in your system. So in REST, you'll need to pick a resource name scheme that uniquely identifies this fact. I'd suggest (using songs as the example):
/like/user/{user-id}/song/{song-id}
Then PUT establishes a liking, and DELETE removes it. GET of course finds out if someone likes a particular song. And you could define GET /like/user/{user-id} to see a list of the songs a particular user likes, and GET /like/song/{song-id} to see a list of the users who like a particular song.
If you assume the user name is established by the existing session, as #joelittlejohn points out, and is not part of the like resource name, then you're violating REST's statelessness constraint and you lose some very important advantages. For instance, a user can only get their own likes, not their friends' likes. Also, it breaks HTTP caching, because one user's likes are indistinguishable from another's.