Designing RESTful shopping cart - rest

I am building a single page application for booking hotel conference rooms and am not sure how to set it up, or even if RESTful is the proper approach. There will be four steps to this SPA:
The user chooses a date (available dates come from server - some days could be fully booked).
The user chooses a conference room (conference rooms available at this hotel on the date chosen in step 1 are retrieved from the server).
The user enters their name, address, billing info.
User sees confirmation page.
This same SPA will be used by multiple hotels with the same database back-end, and for the front-end I was thinking Ember.
Is RESTful the right approach for this application?
I was thinking:
GET /dates?hotel_id=xxx (should I pass the hotel ID in the URL vs. in headers vs. in the body?)
GET /rooms?hotel_id=xxx&date=yyy (should I be passing the date and hotel_id in, or somehow remember it on the server?)
POST /order with body: {date, conference_room_id, name/address/billing info}, returns { confirmation_id }
Should the name/address/billing info be put into a separate POST?
Thank you for your advice.

In a REST(ful) framework there's no concept of session. Every request must send all the required information in order to identify a resource.
I'll post an example below, based on requirements you provided.
GET /hotels/{hotel_id}/dates
Path params:
hotel_id (required)
Query params:
startDate (optional, default: today)
endDate (optional, default (example): today + 3 months)
status (optional, "available"/"booked"/"all", default: "all")
Response body: [{"id":"20160503", "dateStr":"May 5th 2016", "status": "available"}]
GET /hotels/{hotel_id}/dates/{date_id}/rooms
Path params:
hotel_id (required)
date_id (required)
Query params:
status (optional, "booked"/"available"/"all", default:"all")
Response body: [{"id": "12", "status": "available", "reservationId": ""}, {"id: "13", "status": "booked", "reservationId" : "123"}]
Note: this kind of implementation allows to list different combinations of dates and rooms (e.g. booked rooms in available days).
POST /hotels/{hotel_id}/reservations
Path params:
hotel_id(required)
Request body: {"dateId":"20160503", "roomId":"12", "firstName":"John", "lastName":"Doe", "address": "xxx", "vatNumber" : "yyy", "companyName": "zzz"}
Note: if you store billing addresses as separate entities (e.g. if your server is required to "remember" them), then it can be useful to implement POST and GET services for billing addresses (/billing) and refer to them with proper identifiers.
Response body: {"reservationId" : "324"}
GET /hotels/{hotel_id}/reservations/{reservation_id}
Path params:
hotel_id(required)
reservation_id (required)
Response body: {"dateId":"20160503", "roomId":"12", "firstName":"John", "lastName":"Doe", "address": "xxx", "vatNumber" : "yyy", "companyName": "zzz"} (same as POST request body)

GET /dates?hotel_id=xxx (should I pass the hotel ID in the URL vs. in headers vs. in the body?)
GET /rooms?hotel_id=xxx&date=yyy (should I be passing the date and hotel_id in, or somehow remember it on the server?)
POST /order with body: {date, conference_room_id, name/address/billing info}, returns { confirmation_id }
Your solution can use Restful API approach. Because it enable any other component to directly call your APIs. It can be APP, or a website or plugin or just another java program connected to internet, they just need to trigger your API and they are done.
URL you mentioned for your application, please note that one should use resource-based URL approach while building RESTful api.
GET /date/hotels/ -> Gives you all available rooms in all hotels on that particular day
GET /dates/hotels/ -> Give you list of available rooms for a particular hotel (Use dates/hotel_id instead of dates/?hotel_id=xxx). Parameter should be used to filter your result. E.g. dates/hotels/hotel_id?PIN=142: This should gives you hotel whose pin matches 142
dates/hotels?MAX_RECORD=50: This should give you list of hotels but limit to 50
You can find more about creating resource-based Restful API https://www.youtube.com/playlist?list=PLqq-6Pq4lTTZh5U8RbdXq0WaYvZBz2rbn

I would put the "Selects" into GETs as designed.
e.g. dates GET /hotel/:id/date -> Get all available dates
rooms GET /hotel/:id/date/:date/rooms -> Get all available rooms
per design in a RESTful API GET is defined for requesting data.
For the POST I would not breakdown into a seperate POST but you can put some parameter like hotel_id or date into the URL.
Best
Fabian

Related

REST API best practice : GET x objects for x number of customer ids

I want to design a rest endpoint where the requirement is to return list of objects (one for each customer_id)
how should I expose/name the endpoint:
GET (issue is : there can be big number of c_id, and thus avoiding this approach as some frameworks has limit on the url length)
/customers/customer_id=cid_1,cid_2
OR
POST
/customers-list/
Request Body: {customer_id: [cid_1,cid_2]}
NOTE: I have a POST also (to create a new customer):
POST
/customers
Request Body: {id: cid_1,name:"first_last",designation:"manager"}

How to get the list of all users including their last login

I have a dashboard to do for my organization about the use of smartsheet licenses by employees.
Normally, the request to obtain such information is as follows (according to the documentation):
https://api.smartsheet.com/2.0/users?include=lastLogin
However, this request displays exactly 100 results per page. All I want is to have all the results.
The documentation indicates that another parameter must be added to the request to obtain the full list of results. The request becomes:
https://api.smartsheet.com/2.0/users?include=lastLogin&includeAll=true
It works, however I only get the entire list of users without their last login, which brings me back to my question: How to get the list of all users including their last login ?
So, according to the docs for the List Users operation, specifying the include=lastLogin query string parameter will only include the lastLogin attribute for each User object in the response when the number of results returned in the response is 100 or fewer. (FWIW, I'd suspect that Smartsheet implemented this behavior because it'd be detrimental to API performance if a single API request tried to fetch the lastLogin value for hundreds or thousands of users.)
Good news though -- you can still get the info you want -- it's just going to take a little extra effort (and code) on your part. You'll need to submit a separate API request for each page of results (i.e., include both the include=lastLogin query string paramater and also the page query string parameter to specify the page number of results you want to retrieve with each request), and then join the results from all responses into a single list that you write to your dashboard. The value of the totalPages attribute in the initial List Users response will tell you how many total pages (of 100 users each by default, which is the maximum number of users you can request at a time if you want the lastLogin attribute included for each User object) are available -- i.e., how many requests you will need to issue in order to get all users and the lastLogin attribute for each.
For example, your first request would be:
GET https://api.smartsheet.com/2.0/users?include=lastLogin
...and let's assume that the response looks like this:
{
"pageNumber": 1,
"pageSize": 100,
"totalPages": 3,
"totalCount": 100,
"data": [
...
]
}
This response will contain the first 100 users -- but the response tells you it's only the first page of three available pages of results (i.e., the value of the totalPages attribute in the response is 3) -- so you'll need to issue two more requests in order to have retrieved the full set of users.
So, next you issue a second request, this time including the page parameter to specify that you want page 2:
GET https://api.smartsheet.com/2.0/users?include=lastLogin&page=2
...and the response returns the second page of results that looks like this:
{
"pageNumber": 2,
"pageSize": 100,
"totalPages": 3,
"totalCount": 100,
"data": [
...
]
}
This response will contain the next 100 users -- i.e., the second page of three available pages -- you'll need to issue one more request in order to have retrieved the full set of users.
So finally, you issue a third request, this time including the page parameter to specify that you want page 3:
GET https://api.smartsheet.com/2.0/users?include=lastLogin&page=3
...and the response contains the third (and in this example, final) page of results that looks something like this (where the value of the totalCount property is a numeric value >= 1 and <= 100 that indicates the number of users in the response):
{
"pageNumber": 3,
"pageSize": 100,
"totalPages": 3,
"totalCount": 52,
"data": [
...
]
}
Now, because the value of the pageNumber property in the response is equal to the value of the totalPages property in the response, you know this is the final set of users and you don't need to issue any more requests.
Between the 3 requests, you've now retrieved the full set of users (and the lastLogin attribute value for each).

Issue populating assignment_group in servicenow via REST API

I am trying to create Servicenow incident ticket using REST API. Here is the link and body:
https://<mydomain>.service-now.com/api/now/table/incident and body:
{
"short_description":"testing short description",
"assignment_group":"Software",
"urgency":"Medium",
"impact": "Low",
"caller_id":"John Doe",
"description":"testing description"
}
Incident ticket is getting created with all fields populated as requested except assignment_group and description fields. I know these are reference fields. I tried all combination but information is not getting populated for these two fields. Any one has any suggestions? I tried for assignment_group the sys_id value also like "assignment_group":"4ikilo9f1bb43740ddfa315bcd4kmj89" and "assignment_group":{"sys_id":"4ikilo9f1bb43740ddfa315bcd4kmj89"} etc.
pass the id of the assignment group within the API call than directly giving the name of the group, this worked for me :)

When to know when I should put the parameters in the body or not?

I was thinking about the most logical request for my api, while trying to think about rest, but I can't wrap my head around which one of these three choices is correct: what would be the best design for the request, supposing that I want to send 10 from some user triggering the request to user2?
1)
POST /pay
body: {"username": "user2", "amount": 10}
2)
POST /pay/users/user2
body: {"amount": 10}
3)
POST /pay/users/user2/10
I don't know how much information should be in the URL vs. how much information should be in the URL.
Suppose you have many users and some functions that users can perform.
So your api could be like:
GET /users # get user list
POST /users + {"name": "John"} # create user
DELETE /users/{userId} # remove user
GET /users/{userId} # get user by id
GET /users/{userId}/payments # get users payments
POST /users/{userId}/payments + {"amount": 10} # submit new payment
GET /users/{userId}/payments/{paymentId} # get users payment details
As you can see it is a very simple resource tree.
I recommend taking a look at restful-api-guidelines
You want to put an Canonical Identifier in the URL and any other data in the body.
For a POST (which is used to create an new resource) the Canonical Identifier generaly does not yet exist therefor it doesn't need one.
The server then creates one and returns it to the client in the location header.
If you mean to update instead of insert, PUT or PATCH should be used. If the username is your Identifier, then option 2 should be used. An identifier should in general not be editable.
Since your "adding" an new payment I would suggest using option 1. But I would call it payment and perhaps add more information about the payment.

How do I export GLBudgetLineDetail via Rest API?

My goal is to export data from the [GLBudgetlineDetail] table via the Rest API.
To accomplish this:
1) I created created a custom endpoint based on the Budgets screen (Finance > General Ledger > Work Area > Enter > Budgets)
!(http://imgur.com/sQC0zOI)
2) I populated the endpoint by adding all the fields from the Budget Articles container
!(http://imgur.com/tZp2GMh)
When I query this endpoint, I only get an empty array returned "[]".
Here is the query:
GET http ://servername/WebServiceAPITest/entity/MyStore/6.00.001/Budget
Headers:
Content-Type -> application/json
("Budget" is the name I gave to the endpoint)
I can successfully query other endpoints (Accounts, Vendors, JournalTransactions, etc) but I can't get any data back from this one.
I created the MyStore Demo (Course I210) and have access to the [GLBudgetLineDetail] table and can verify that it has data. On the Budgets screen, if I filter to year 2013, Ledger 'Budget', Branch 'SOFT', I can see Budget information.
How do I get access to this info via the Rest API?
Since you mentioned the Course I210, You might want to refer yourself to the section 3.4.1 about Retrieving the Price of an Item for a Customer.
In that section, they are saying that if you want to retrieve data from an inquiry, you must use the Put command:
"Because you are retrieving the price of an item from the inquiry, you will use the Put() method to obtain data."
Since the Budget Screen is an Inquiry Screen you must use the Put command to set the parameter you want.
Here is one that I tried and that worked on an Acumatica web site with demo
data:
PUT http://localhost/Demo610u04/entity/BudgetEndpoint/6.00.001/Budget
Headers (Key -> Value):
Content-Type -> application/json
Accept -> application/json
Body :
{
"BudgetArticles":[{}],
"FinancialYear":{"Value":"2016"},
"Ledger":{"Value":"BUDGET"}
}
EDIT: Looking at the image you added, you should have your budget Filter fields in the main entity and have a sub entity of type Detail containing the Budget Articles fields