Proper resource names of a REST API - api

Let's say we are making an invoice API. What is a more appropriate resource?
GET
paid_invoices
due_invoices
all_invoices
or
GET
invoices/all
invoices/due
invoices/paid
Additional question: If your API allows marking invoices as paid what's the proper resource?
PUT //where 3 is the id
invoices/3
or
PUT
pay_invoice/3

I would say:
GET /invoices returns all invoices;
A filter can return either paid or due invoices: GET /invoices?state=paid where state can be paid or due.
To mark an invoice as paid, you can either set the corresponding state to your resource, and then you just have to update (replace actually) it using PUT /invoices/<id>.
Alternatively, you can patch your resource: PATCH /invoices/<id>. This method requires a diff like state=paid for example.
It's just a matter of what you want to send to your API (a complete resource, or just the change to apply).
A non-REST solution could be to perform a PATCH request to /invoices/<id>/paid. It's not pure REST but it's ok.

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.

Softlayer API To get a particular Storage ID for a particular Order ID

After placing order for a storage in softlayer, I need to get that storage id for a particular order id.The api call i am using, is giving me a list of storage ID. But, if user orders for a storage, only one storage id the user should get right.
So, the api is not properly filtering and not getting a particularly storage id for a particular order id . The rest api, i am using is given below and please tell me what should be the proper filtering ,
"https://[username]:[apikey]#api.softlayer.com/rest/v3/SoftLayer_Account/getIscsiNetworkStorage.json?objectFilter={"networkStorage": {"billingItem": {"nasType": { "operation": "ISCSI"}, "orderItem": {"order": {"id":{"operation":"[orderID]"}}}}}} "
This api is provided by softlayer team
Regards,
Debartha
use this request:
GET https://api.softlayer.com/rest/v3/SoftLayer_Account/getIscsiNetworkStorage?objectMask=mask[billingItem[orderItem[order]]]&objectFilter={"iscsiNetworkStorage": {"billingItem": { "orderItem": {"order": {"id":{"operation":5208963}}}}}}
note: replace 5208963, with your orderID
Basically all the devices must have a billingItem and that billingItem should have orderItem.order.id property, so you can use this filter to get any device using the orderID property, you just to need to make sure that the "iscsiNetworkStorage" value, in the filter, has the same name as the method you are calling (in this case getIscsiNetworkStorage method ), but without the pre-fix "get" and it must start with lower case e.g.
getIscsiNetworkStorage -> iscsiNetworkStorage
Regards

Bigcommerce API - Create Shipment - Include all Items

according to the documentation, the Create Shipment method requires the property "items" - an array of the items being shipped, for example:
{
"tracking_number": "EJ958083578US",
"comments": "Ready to go...",
"order_address_id": 1,
"items": [
{
"order_product_id": 15,
"quantity": 2
}
]
}
In our business, a shipment almost invariably contains ALL items from the relevant order.
That being the case, is there a way to create a shipment without listing all items (which would require iterating over the product line-items)? Or, alternatively, a way to include all items by default (without iterating)?
We are simply wishing to automate the process of adding tracking numbers to orders - which (as a manual process) involves uploading a csv with [order_number: tracking_number] - i.e. it self-evidently assumes that all items are being shipped. The API seems not to include that (very sensible) option, but I may be wrong.
From Bigcommerce Support:
There is not a way to add a tracking number without adding a shipment nor a way to default the shipment to include all products. This is a helpful suggestion though that I will be passing on to our Product Team for possible implementation into future versions of the API.
Unfortunately for now it is necessary that you GET to the products subresource of an order and iterate over all of the products to pull their 'id' values and 'order_address_id' values so you can generate your POST request to the shipment subresource. It is not necessary to make a GET request to the shipping address subresource directly unless you want the details of that shipping address. It is also not necessary to make a GET request to the base order object unless you want details found there or you are looking to automate the process of checking for orders ready to ship.
So assuming you know an order ID that you want to ship it should only take 2 requests total to both GET the products subresource and then POST to the shipment resource.

Should we always validate resource id in url and body in HTTP PUT request?

Suppose I am updating a employee record
url - /api/employees/10
body -
{
id : 10,
name : xyz
}
Should I validate for the employee id in url is same as in response? Because one employee can hit the url himself but update the data of another employee by sending another value in the PUT body.
If you have to validate, it's likely that you want to use POST. A POST is not idempotent and you are supposed to manage the change.
PUT is idempotent, and it just creates a resource. It implies that you don't actually care what id 10 is and whether it is a new id or an existing id. You just replace id 10 with the resource you supply. You only use PUT when you know what the uri should be.
Yes, if the representation of the object in the body contains its own key, you should validate that it matches the key from the URL. It's an error for the client to try to PUT an object at /api/employees/10 that isn't a valid value for employee #10's record, so you should check for that and report it as an error just as you would check that the object has correct syntax.
I believe that the best error code to return in this case is 422 Unprocessable Entity, but I might be wrong about that.
Another thing you can do instead is don't include the key at all in the body. However I find that keeping the key in makes sense for consistency with the way the same type of object is represented in other parts of the API (possibly embedded inside other objects). This is especially true when using XML (although it looks like you are using JSON here).

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]