REST API - POST Behavior - rest

In a true REST API how is POST supposed to behave for an operation like this
Supposse there is a
POST v1/report --> some body with id1, id2 - passed in a request
id1, id2 are part of unique index. For their combination needs to be unique for every resource.
If there already exists data in the table with id1 and id2 is POST supposed to
return that data. In this case do what GET would do
return an exception since there already exists data.
Since POST is not idempotent what is it supposed to do in true sense.
Making sure I implement REST API verbs in the correct way.

Related

How to specify multiple query parameters instead of request body in http verb delete?

I have http verb delete endpoint in which i would like to know how to specify multiple query parameters in http verb delete endpoint.
Based on my research i came to know that it is better to specify
parameters as part of query string than in request body for http verb delete
endpoint.
I am dynamically creating endpoints in which i have htpp delete endpoint.lets say i have delete endpoint like below :
https://root/Customer
Now i have interface for delete configuration where user select columns require to delete a record from table.
So lets say i have a below table in which i have 2 columns(Col1,Col2) uniquely identifying a record:
Customer
Col1
Col2
Col3
User select this Customer table and select columns to delete record from table for http verb delete endpoint.
So in case of single Column which is unique i am generating url like this :
https://root/Customer/Col1
But now when i will have 2 or more than 2 columns uniquely identifying a record and from customer if user select 2 or more than 2 columns then is below url correct as per http standards :
https://root/Customer/Col1?Col2={value1}&Col3={Value2}
Can anybody please guide me for this?

GET a resource filtering by a composite key as query parameter?

I'm thinking the best way to create an endpoint that one of the filters be a composite key.
Per example, we have a rest service to search for orders:
/orders/
We can filter the orders by start and final date:
/orders?dt-start=2017-05-11T17:12Z&dt-final=2017-05-11T17:12Z
Until here, so far so good. But I would like to filter the orders by customer. The customer is identified by his type of document and number of this document.
So, something like this could be possible:
/orders?type=ID&number=123456789
But the type and number are query parameters that only work together, it's a composite key. But using query parameter - like the last example - seems that the API user can do too:
/orders?number=123456789
/orders?type=ID
But not makes sense. Yes, I could return an error in response (bad request) if only one of these parameters were passed, but this is not natural for who are reading the API endpoint.
Another strategy is combine type and number in the same parameter, but I never see this in any API.
/orders?document=ID-12345678
It's odd to me too. I prefer to use separated parameters instead of this.
So, there are a way to use query parameter and solve this problem in a more "elegant" way?
Thanks!
Don't make up a composite key, instead conditionally require the two params. This ins't bad and IMO is much cleaner than creating a composite key which isn't represented by the data (or resource).
I've done this before, so to help illustrate I'll point you to it. This resource is to query for CyberFacts. The query is bound by a date range. To get data, you can do one of two things.
You can say ?today=true, and get the data for today (equivalent to saying ?startDate=2017-05-13&endDate=2017-05-13)
You can use the startDate and endDate query parameters, however if you use one and not the other (eg ?startDate=2017-05-13) you will receive a 400 Bad Request status response on the query and a error message in the response body.
So in this case I've done a few things to make this work
Make a higher priority parameter (today overrides startDate and endDate)
Document the valid behaviors
Provide appropriate error responses
For you only #2 and #3 would be needed, I think. Not knowing all of your use cases, I would suggest using /orders?type=ID&number=123456789 and document that number is a require query param when type=ID, and also include the appropriate error (eg: "You queried for an Order by Type 'ID', however you did not provide a 'number' query parameter")
How about providing a default value for type, (such as 'ID') as a fallback if the type parameter is absent (I'd probably go for the most common/used document type depending on your situation).
While for the number parameter I would enforce it, i.e. by specifying that it is a required parameter (somewhere in the docs?). If absent, return a bad request.

REST: If the procedure is a DB UPDATE command, should your API call strictly be PUT?

Consider the following invoice table with two entries, id 1 and 2:
id, item, date_paid
1, 'apple', ''
2, 'banana', ''
When a payment is made date_paid column needs to be updated.
What is a proper REST verb for this?
POST invoices/1/payments
or
PUT invoices/1/payments
I feel like POST is proper since I am "adding" a payment detail but then again internally I'm actually "updating" a DB row so PUT seems applicable also.
If I understand your example, you have an invoice that was created in your Invoice table at some point in the past. You're now updating said invoice to reflect that a payment was made. That's definitely an update and PUT is the correct verb. Presumably you might also have a Payment table with the actual payment details (amount, payer, etc.). If so, then that's where you would be adding a new payment record. That call would be a POST.

POST request for JOIN table

Let's say 3 tables
session
-------------------------
id | name | date
-------------------------
speaker
-------------------------
id | name
-------------------------
session_speaker
-------------------------
session_id | speaker_id
-------------------------
I've endpoints already in place to do the insertion
POST /session
POST /speaker
What kind of REST request should I create to specify the intention to insert into the JOIN table using POST /session or any other method (passing session_id and speaker_id)
Note: I've a PATCH request already in place to activate or deactivate a session.
Question:
Basically seeking an ideal REST based solution to handle CRUD based operations for the JOIN table, please advise.
You could use the following REST operation for creating the relationship:
PUT speakers/speaker/{speakerId}/session/{sessionId}/
I don't advise using plural names in URLs (e.g. speakers), I'd recommend a singular name such as SessionSpeaker, but as you can't change it from "speakers" I've used it as requested.
You should also use PUT instead of POST for inserting data, as PUT is idempotent i.e. PUT guards against you inserting the same speaker at a session.
To then retrieve speakers information you could use:
GET speakers/session/{sessionId}
GET speakers/speaker/{speakerId}
Another good answer regarding REST and entity multiplicity is here.

Can web2py serve REST data of many-to-may tables via parse_as_rest?

I need to serve REST data about a many-to-many relationship. I've been playing with web2py's lovely parse_as_rest functionality, but can't quite get the many-to-many thing working.
As an example, let's take standard users and groups.
Tables:
user
id
user_name
group
id
group_name
membership
id
user_id
group_id
What pattern do I need to use to serve a url that will give me all group_name's that a user belongs to?
patterns = [
"/user[user]",
"/user[user]/id/{user.id}",
"/user[user]/id/{user.id}/membership[membership.user_id]",
# This is the line that I can't make yet:
#"/user[user]/id/{user.id}/membership[membership.user_id]/group<WHAT GOES HERE>",
"/group[group]",
"/group[group]/id/{group.id}",
]
parser = db.parse_as_rest(patterns, args, vars)
With the non-commented lines above, I can get to these urls:
.../user
.../user/id/1
.../user/id/1/membership
.../group
.../group/id/3
URL #3 shows me all my memberships, and I can then make several separate calls to URL #5 to get the group_name values, but there's got to be a way to do this with one call.
Help me StackOverflow! You're my only hope.
EDIT: Fixed bad cutting and pasting.
This question is in top of Google search for that topic.
Just start building query from the many-to-many table.
/user[membership]/id/{membership.user_id}/groups[group.id]
You don't really need 'user' table for this request.
Then request to "/user/id/22/groups" will give you all groups not only their IDs.