Structure of a RESTful API - api

I want to build a RESTful API for my small project. There are three simple resources that I have:
- Categories (id, title)
- Posts (id, text, category_id)
- Comments (id, text, post_id)
These are the end points that I need:
GET /categories/ => list of all categories
GET /categories/:id/posts => list of riddles in specified category
GET /posts/:id => get single post
GET /posts/:id/comments => list of comments for specified post
GET /comments/:id => get single comment
POST /posts/:id/comments => create a comment (text comes from POST params)
Is this a good structure for API in this case?
Is this consider to be a RESTful API?

REST doesn't have anything to say about URI structure, so it's not really meaningful to ask if your endpoints are RESTful.
As far as the design, I would consider this instead:
GET /categories
GET /posts?categoryId=<categoryId> -- or you could use category name, if the name is not the same as the id
GET /posts/<postId>
GET /comments?postId=<postId>
GET /comments/<commentId>
POST /comments
{ "postId" : 123, ... }

According to REST, url should uniquely identify the resource which is happening in your case. As long as your url is Cacheable and you are using correct verbs and correct status codes, do not indulge in too much quabble about url structure. Additionally, you might want to look into 'Hypermedia', if you want your apis to be truly restful

Related

how to do pagination in RESTFUL API in a effective way?

I want to support pagination in my RESTful API.
My API method should return a JSON list of product via http://localhost/products/v1/getproductsbycategory, there are potentially thousands of products, and I want to page through them, so my request should look something like this:
public function getProductsByCategory($product_id,$page){
$perPage=5;
$start=($page-1)*$perPage;
$stmt=$this->conn->prepare("SELECT id,product,description,destination_url,expiry_type,savings,expiry,title,last_updated_on FROM products WHERE product_id=? ORDER BY last_updted_on DESC LIMIT $start ,$perPage");
$stmt->bind_param('i',$category_id);
$stmt->execute();
$productbycategory=$stmt->get_result();
$stmt->close();
return $productbycategory;
}
}
Firstly, in a RESTful call, the URL should ideally be noun-based and not verbs. We are using HTTP verbs (GET, PUT, POST, etc) to do an action on a noun - product in your case.
So, the URL should be http://localhost/products/v1/category
This effectively means you are GETting product of type v1 based on category. To get a given page number, simply add it as a query parameter -
http://localhost/products/v1/category?page=1
and handle it accordingly in your GET implementation corresponding to localhost/products/v1/category
Hope this helps.
Pagination has nothing to do with the JSON format per se - it's all about the query string in the URL and how the server interprets that.
Expanding on #Sampada's answer, you can have a URL like
http://localhost/products/v1/category?pageSize=5&pageNumber=2
and then you'll simply pick the corresponding elements on the server side (consider whether you'll want 0 or 1-based index for the pageNumber), and return them.
Additionally you can wrap this collection in an object that also provides links as to navigate to the previous/next/specific page - see HATEOAS & Richardson's Maturity Model level 3.

Can't understand some basic REST stuff

Suppose my model is:
User:
id
nickname
I have a collection /users/
I want the Users to be retrieved by /users/{id} and not /users/${nickname}, because in some more complex cases, there could be no "logical unique constraint".
So the basic JSON payload I could use is for exemple:
{
id: 123,
nickname: 'someUserName'
}
Nothing fancy here.
POST on /users/
As far as I know, an user as an identifier. It is part of the resource representation, so it should be in the payload (?).
Put what if I want to generate the ID myself on the backend, using a DB sequence for exemple?
Then my payload becomes:
{
nickname: 'someUserName'
}
Is this appropriate?
What is supposed to be the output of this POST? Nothing? Just a header referencing the resource location, including the ID?
GET on /users/id
When we get the resource, we load its content as JSON:
{
id: 123,
nickname: 'someUserName'
}
PUT on /users/id
As far as I know, the payload used on this method is supposed to "override" the resource content. If we wanted partial updates, we would have used PATCH.
But what if I do:
PUT /users/123
{
id: 456,
nickname: 'someUserName'
}
Does this mean that we want to update the id of a resource?
Isn't it kind of redundant to use the id in both the URI and the payload?
Actually I don't really know how to handle the id.
I don't know if I am supposed to use the same resource representation in all POST / PUT / DELETE operations.
I don't know if the id should be part of the unique(?) resource representation.
But if the id is not part of the representation, then when I list the users, using GET /users/, if the ids are not returned, then I don't know how the client can get the user ids...
Can someone help me? :)
First of all
It is not REST if you don't use HATEOAS
I hope you understand this, I'll come back to that at the very end.
POST on /users/
It perfectly ok to not use an ID in the POST payload. If an ID is present react with an error message, so developers understand they are doing wrong.
Therefore only the nickname as a payload is perfectly valid if you don't have anything else in your user resource
The output of your server should include three important things:
HEADER: A status code indicating success or failure (usually 201 Created)
HEADER: The location of the newly created resource (just Location: /path/to/resource)
BODY: A representation of the created resource. Give back a complete payload like on a GET!
GET
perfectly valid
PUT
your analysis regarding PUT/PATCH matchs the spec, the new resource should be identical to the payload meaning the user wishes to change the id if it differs. if a payload contains values which shouldn't be changed (like the ID) you have two possibilities:
Ignore the ID in the payload
Return an error
In both cases inform the user about what you did and what went wrong. I prefer to send/get a 400 Bad Request. If a privileged user could change the ID but the particular user can't an 403 Forbidden may be more appropriate.
Also make sure to document your APIs behaviour. You may allow the ID to be omitted in your API. Don't forget to treat IDs given in a POST payload in a consistent way!
Overall questions
REST operates over Resources.
/users/ is an example for an collection of resources
/users/{id} is an example for a single resource
You should always use the exact same representation in each and every response. If for some reason it is more appropriate to give only a snippet of the information add metadata (link) pointing to the full resource representation.
The ID is always present except in the first POST request of an user.
POST implies that the future location of the resource is not known and has to be provided by the server.
This also means that GET /users/ should return the IDs for each resource.
As always in APIs return strict and be forgiving in requests. document your behaviour so users can learn.
HATEOAS
The true beauty of REST comes to daylight if you implement HATEOAS (Hypermedia As The Engine Of Application State). Part of this means that you should sugar your representations with useful tag/link combinations. This way clients never have to construct an url anymore.
An Example using HAL for your user representation would be:
{
"_links:" {
"self": { "href": "http://yourrest/users/123" }
},
"id": "123"
"nickname": "someUserName"
}
A nice wrapup of using HAL was written by Matthew Weier O'Phinney in his blog when he developed a ZF2 REST Module (first entry is completly zf free, only explaining HAL).
I'm interpreting your descriptions as saying that the id is not part of the resource, it's a unique identifier of the resource. In that case, it should not be part of the payload for any operation.
POST /users with payload {"nickname": "somebody"} would create a new resource with a URL returned in the Location header. That URL would presumably look like /users/123 but from the client's point of view there's no reason to expect that. It could look like /something/else/entirely.
GET /users/123 would (assuming that URL was returned by an earlier POST) return the payload {"nickname": "somebody"}.
PUT /users/123 would (with the same assumption as above) replace the resource with the payload you send with the PUT, say {"nickname": "somebody else"}.
If you want the client to be able to name a resource, then you'd also let PUT /users/123 create a new resource with that URL.
I know of no common RESTful way to rename a resource. I suppose a POST with the old URL as part of the query part or the body would make sense.
Now, suppose I'm wrong and you do want id to be part of the resource itself. Then every payload would include it. But from the client's point of view, there should be no assumption that "id": 123 implies that the URL would be /users/123.
Finally, all of this is from a fairly purist point of view. There is value to thinking of URLs as the only real identifier of a resource, but it's not awful to break that rule and have the client use logic to create the URLs.

Querying for Customers using the API

Using the command line shopify application
include ShopifyAPI
Customer.first(:params => {:query => "email:foo#fizz.com", :fields => "email"})
=> #<ShopifyAPI::Customer:0x00000100b75448 #attributes={"email"=>"poohbear#gmail.com"}, #prefix_options={}, #persisted=true>
I am curious if it is possible to have a query where you provide an email and the result is either empty set (not found) or a record of a customer? I am always getting a customer record back no matter what my query is. That makes it hard to determine if a Customer exists or not from outside the shop.
You're hitting the wrong endpoint. Customer.first queries the index endpoint (admin/customers.json) whereas you're trying to do a search (admin/customers/search.json).
The index endpoint doesn't understand the query param, so it ignores it and you get the regular index.
To fix this, you need to specify the endpoint you're trying to hit. Docs are here, Shopify-specific examples are here. Also here:
ShopifyAPI::Customer.find(:all, :from => :search, :params => { :q => "John" })
This is an old post, but Shopify's docs are pretty spotty. You need to use the search API endpoint AND you will need to quote the email address you are searching for, e.g.
/admin/customers/search.json?query=email:"email#domain.com"
If you don't quote the email address, you may get lots of similar email addresses.
See https://community.shopify.com/c/Shopify-APIs-SDKs/Find-a-Customer-by-Email-via-API-Call/td-p/141661

RESTful API - How do I return different results for the same resource?

Question
How do I return different results for the same resource?
Details
I have been searching for some time now about the proper way to build a RESTful API. Tons of great information out there. Now I am actually trying to apply this to my website and have run into a few snags. I found a few suggestions that said to base the resources on your database as a starting point, considering your database should be structured decently. Here is my scenario:
My Site:
Here is a little information about my website and the purpose of the API
We are creating a site that allows people to play games. The API is supposed to allow other developers to build their own games and use our backend to collect user information and store it.
Scenario 1:
We have a players database that stores all player data. A developer needs to select this data based on either a user_id (person who owns the player data) or a game_id (the game that collected the data).
Resource
http://site.com/api/players
Issue:
If the developer calls my resource using GET they will receive a list of players. Since there are multiple developers using this system they must specify some ID by which to select all the players. This is where I find a problem. I want the developer to be able to specify two kinds of ID's. They can select all players by user_id or by game_id.
How do you handle this?
Do I need two separate resources?
Lets say you have a controller name 'Players', then you'll have 2 methods:
function user_get(){
//get id from request and do something
}
function game_get(){
//get id from request and do something
}
now the url will look like: http://site.com/api/players/user/333, http://site.com/api/players/game/333
player is the controller.
user/game are the action
If you use phil sturgeon's framework, you'll do that but the url will look like:
http://site.com/api/players/user/id/333, http://site.com/api/players/game/id/333
and then you get the id using : $this->get('id');
You can limit the results by specifying querystring parameters, i.e:
http://site.com/api/players?id=123
http://site.com/api/players?name=Paolo
use phil's REST Server library: https://github.com/philsturgeon/codeigniter-restserver
I use this library in a product environment using oauth, and api key generation. You would create a api controller, and define methods for each of the requests you want. In my case i created an entirely seperate codeigniter instance and just wrote my models as i needed them.
You can also use this REST library to insert data, its all in his documentation..
Here is a video Phil threw together on the basics back in 2011..
http://philsturgeon.co.uk/blog/2011/03/video-set-up-a-rest-api-with-codeigniter
It should go noted, that RESTful URLs mean using plural/singular wording e.g; player = singular, players = all or more than one, games|game etc..
this will allow you to do things like this in your controller
//users method_get is the http req type.. you could use post, or put as well.
public function players_get(){
//query db for players, pass back data
}
Your API Request URL would be something like:
http://api.example.com/players/format/[csv|json|xml|html|php]
this would return a json object of all the users based on your query in your model.
OR
public function player_get($id = false, $game = false){
//if $game_id isset, search by game_id
//query db for a specific player, pass back data
}
Your API Request URL would be something like:
http://api.example.com/player/game/1/format/[csv|json|xml|html|php]
OR
public function playerGames_get($id){
//query db for a specific players games based on $userid
}
Your API Request URL would be something like:
http://api.example.com/playerGames/1/format/[csv|json|xml|html|php]

What is the proper RESTful way to "like" something in Rails 3?

Let's say I have a Rails 3 app that displays videos. The user can "Like" or "Dislike" the videos. Also, they can like/dislike other things like games. I need some help in the overall design and how to handle the RESTful routes.
Currently, I have a Like Class that uses polymorphic design so that objects are "likeable" (likeable_id, likeable_type)
I want to do this via AJAX (jQuery 1.5). So I was thinking something like:
javascript
// these are toggle buttons
$("likeVideo").click( function() {
$.ajax({
url: "/likes/video/" + video_id,
method: "POST",
....
});
} );
$("likeGame").click( function() {
$.ajax({
url: "/likes/game/" + game_id,
method: "POST",
....
});
} );
rails controller
Class Likes < ApplicationController
def video
# so that if you liked it before, you now DON'T LIKE it so change to -1
# or if you DIDN'T like it before, you now LIKE IT so change to 1
# do a "find_or_create_by..." and return JSON
# the JSON returned will notify JS if you now like or dislike so that the
# button can be changed to match
end
def game
# same logic as above
end
end
Routes
match "/likes/video/:id" => "likes#video", :as => :likes_video
match "/likes/game/:id" => "likes#game", :as => :likes_game
Does this logic seem correct? I am doing a POST via AJAX. Technically, shouldn't I be doing a PUT? Or am I being too picky over that?
Also, my controller uses non-standard verbs. Like video and game. Should I worry about that? Sometimes I get confused on how to match up the "correct" verbs.
An alternative would be to post to something like /likes/:id with a data structure that contains the type (game or video). Then I could wrap that in one verb in the controller...maybe even Update (PUT).
Any suggestions would be appreciated.
Rest architectural style does not specify which "verb" you should be using for what. It simply says that one can use HTTP if they want to for connectors.
What you are looking for is HTTP specifications for method definitions. In particular POST is intended for:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
while PUT:
requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.
Which category your functionality falls into is up to you - as long as you are consistent with yourself about it.