Rest API url with multiple identifiers - rest

I have an architecture issue concerning a RestAPI url with multiple identifiers.
In a simple relationship, I use to write something like this :
GET /users/2/tickets/46 to retrieve the ticket 46 of the user 2.
But I want to retrieve, for example, a list of operations which can be identified by two identifiers, a userId and a workstationId. Both of them are not related.
For a GET request, it's weird for me to write this :
GET /users/2/workstations/5/operations because there's no relation...
Is it a best practice to use url parameters as filter ? :
GET /operations?userId=2&workstationId=5
EDIT :
And for a PUT/PATCH request when editing a specific operation, should I keep the same pattern :
PATCH /operations/123?userId=2&workstationId=5
{
"data":"test"
}
Or should I put the identifiers in json payload :
PATCH /operations/123
{
"userId":"2",
"workstationId":"5",
"data":"test"
}

Related

Salesforce REST API how to avoid leaking sensitive data in query parameter

I'm trying to do query using REST API, and ran into the following problem:
Using GET request on the query endpoint exposes the entire query string, which may contain sensitive data such as SSN, phone number, etc...
https://[instance-url].my.salesforce.com/services/data/v48.0/query/?q=SELECT Id FROM Contact WHERE SSN__c = '123456789'
How can I do such a query using rest api securely?
IS there an equivalent request I can make using at least POST request with post body being the query? since that part is encrypted over https.
Thank you for help
You have two options.
Parameterized Search API. This option is available out of the box with POST as the method. The API is a RESTful interface to Salesforce's text-based search engine. Normally, text-based search uses SOSL as the query language. Parameterized Search API skips SOSL and gives you an easier option to work with.
If you POST the following body to /services/data/v48.0/parameterizedSearch
{
"q": "123456789",
"sobjects": [
{
"name": "Contact",
"where": "SSN__c = '123456789'"
}
],
"fields": ["id"]
}
you should see something like this as the response, assuming single record is returned by search (ID is redacted):
{
"searchRecords" : [ {
"attributes" : {
"type" : "Contact",
"url" : "/services/data/v48.0/sobjects/Contact/003..."
},
"Id" : "003..."
} ]
}
The value of q key in the JSON payload must be the same as the value in the where key/clause. You're doing a full-text search on 123456789 across all objects and all fields in the search index. This could return many records..but you're filtering the search down in a structured way to guarantee that you'll only see Contact records where SSN__c = '123456789'. As long as the objects + fields you're trying to retrieve are present in the index the results you'll see via Parameterized Search in this specific example are going to be the same as that of a SOQL query via /query
Custom REST API (aka Apex REST / Apex web service). This is a typical implementation option for cases like yours. You can send whatever payload via POST and then process it however you like.
Apex class:
#RestResource(urlMapping='/findcontactbyssn')
global class ContactResource {
#HttpPost
global static void findContactBySSN() {
SearchRequest input = (SearchRequest)JSON.deserialize(RestContext.request.requestBody.toString(),SearchRequest.class);
Contact c = [SELECT Id FROM Contact WHERE SSN__c = :input.ssn];
SearchResponse output = new SearchResponse();
output.id = c.id;
RestContext.response.responseBody = Blob.valueOf(JSON.serialize(output));
RestContext.response.statusCode = 200;
}
class SearchRequest {
public String ssn {get;set;}
}
class SearchResponse {
public String id {get;set;}
}
}
POST to /services/apexrest/findcontactbyssn with
{
"ssn": "12345678"
}
and you should see this response:
{
"id": "003..."
}
AFAIK, salesforce only provides a GET method for executing SOQL queries. One can write their own REST endpoint in their org that accepts a query in body and execute it, but thats a waste of time in my opinion.
Query string parameters are secured over https. Its a common misconception, where people think whole url is open in plain text in transmission. When a request is made to an https url, first it establishes a Secure Tunnel to [instance-url].my.salesforce.com then transmits the rest of the url and any other data over the secure tunnel.
If you're worried about some man in the middle attack sniffing out the SSN from your query string, don't. One downside is, if you are accessing this url from a browser instead of a programmatic call, then there is a chance for browser to stored/cache for history or auto complete, then it won't be so good.
But I doubt if you would be able to do this via browser, as salesforce requires a bearer token set in Authorization header and there is no easy way that I know of to set headers while typing the url in the browser or clicking a link.
To know more about how query string is secure over https please refer to this stackoverflow question

REST URL for transforming one resource into another resource

I am struggling to come with proper REST URL for converting one resource into another. The API method does not do any CRUD operations but instead transform/convert one resource into another type of resource.
I have 2 resources Workunit and Document. I have 3 operations on these two resources
1> trasform Workunit into Document
2> sync Workunit into Document (different logic than transform)
3> transform Document into Workunit
and i have the following urls
[POST] api/v1/workunits/transform
[POST] api/v1/workunits/sync
[POST] api/v1/documents/transform
problem here is action is a part of REST URL
any suggestions?
problem here is action is a part of REST URL
That's not a problem - clients don't depend on the URL for semantics, so you can use any spelling you like; api/v1/4dc233fa-c77c-49d7-b7d6-296ffeb89612 is perfectly satisfactory.
It's analogous to having a verb as a variable name -- it may not be in keeping with your local coding standards, but the compiler doesn't care. So too is it with your URL and the general purpose components that use it.
Choosing a good identifier is like choosing a good name; it requires having a clear understanding of what the thing is. In the case of URI/URL, the thing being identified is a resource, which is to say something that is described by a document. GET/POST/PUT/DELETE and so on are all requests that we do something interesting with the underlying document.
So the usual pattern might be to POST a transform message to the workunit resource, or to POST a transform message to the Document resource, or to POST a sync message to the workunit resource.
Hmm, that last one sounds backwards; if the workunit is unchanged, and the Document is changed by the sync, then you would probably send a sync message to the Document resource.
So if I have /api/v1/documents/1, and I need to sync it, then I would normally use POST /api/v1/documents/1, with the sync semantics described in the message body (on the web, that would usually be an application/x-www-form-urlencoded representation of the sync message).
But it could just as easily be a message that says "Sync documents/1 with workitem/2" that I POST to the todo list for the synchronizer.
We are just putting documents politely into the server's in-tray, so that it can do useful work. The in-tray can have whatever label you want.
It is fine with given situation.
Nevertheless, if I am getting you right it may be a good idea to create two different controllers.
It's up to you but think of changing structure a little bit:
Separate the logic of Transformation and Sync into two different controllers, so you can avoid URL issue.
TransformationController
[Route("api/v1/transformation-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> TransformWorkunits()
{
//logic
}
[HttpPost("documents")]
public Task<Response> TransformDocuments()
{
//logic
}
}
SynchronizationController
[Route("api/v1/synchronization-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> SyncWorkunits()
{
//logic
}
}
So the URLs will be:
[POST] api/v1/transformation-controller/workunits
[POST] api/v1/synchronization-controller/workunits
[POST] api/v1/transformation-controller/documents
So this is a way to avoid verbs and fit REST rules.
If there will be more objects to transform/sync from and into, then you'll have to improve this approach.

REST: Is it considered restful if API sends back two type of response?

We have stock website and we help buyers connect with the sellers. We are creating API to let buyers push their contact details and get back the seller details. This is transaction and get logged in our database. We have created following API:
The request is POST, the URL looks like:
/api/leads
The request body looks like:
{
"buyermobile": "9999999999",
"stockid": "123"
}
The response looks like:
{
"sellermobile" : "8888888888",
"selleraddress": "123 avenue park"
}
We have a new requirement, i.e. we need to send back PDF URL (instead of "sellermobile" & "selleraddress"). This PDF URL would contain the seller details in case it comes from one of our client.
We have modified the same API, now the request body looks like:
{
"buyermobile": "9999999999",
"stockid": "123",
"ispdf": true
}
The response looks like:
{
"sellerdetailspdf" : "https://example.com/sellerdetails-1.pdf",
}
Is it RESTFUL to do this? OR we should create separate API for getting response as PDF?
I wouldn't approach it this way. What happens when you need to add XLS? Do you add "isxls" to the request too?
Things I'd consider:
Use a mime type for content negotiation. Post the same request, and specify in the Accept header what you expect back - JSON, PDF, etc. You're then actually getting the report instead of a link to the report, which may or may not be better.
- or -
Include a link in the typical lead response.
{
"sellermobile" : "8888888888",
"selleraddress": "123 avenue park",
"_links": {
"seller-details-pdf": "https://example.com/sellerdetails-1.pdf"
}
}
- or -
Support a query parameter that specifies the type in the response.
- or -
Have a single property that specifies the type in the response, rather than a boolean. Much cleaner to extend when you add new response types.
The first two options have the bonus that you don't require clients to handle multiple response types to a single request. That's not forbidden by any spec, but it's annoying for clients. Try not to annoy the people who you want to pay you. :)
Again the implementation looks good to me, however you could potentially look at breaking the return of the PDF URL to another endpoint maybe something like api/lead/pdf that way your request body is the same for api/lead and all subsequent endpoints under /lead. Allowing your routes and other code to handle small portioned tasks instead of having a route that handles multiple flags and multiple code routes.
That looks good to me - the same type of input should give the same type of response but in your case you have two different types of input - one with the "ispdf" flag and one without. So it's consistent to responds with two different types of response, one with the PDF link and one without.
That's still something you'll want to document but basically it's a correct implementation.

REST API using GET Params

Say we have the following server resource:
api.example.com/event/1
Which returns some arbitrary resource, say:
{
id: 1,
details: {
type: 'webinar',
....
},
attendees: [
{
user_id: 1,
first_name: 'Bob'
...
},
...
]
}
It might be useful for a client to make a request to get just the event details of the event but not the list of attendees.
Is it better to provided two separate URLs for the resources and force two separate requests if a client wants both resources?
api.example.com/event/{event_id}
api.example.com/attendees/{event_id}
Or is it better to offer the same two endpoints, but optionally have the first one support a GET param to toggle the attendee listing on or off
api.example.com/event/{event_id}?listAttendees={true|false}
api.example.com/attendees/{event_id}
Where the listAttendees parameter will either have the representation return the attendee list or not.
Is it an common practice to allow GET params to change the representation returned from a specific URL?
I'd say the most correct way to do that in REST would be with different media-types, or media-type parameters, but since most people don't use custom media-types, I often use something I call the zoom protocol. The idea is that you have a zoom or expand parameter, with a numeric value, and it recursively includes the children entities, decreasing the parameter until it reaches zero.
So, a request like:
GET api.example.com/event/1
Returns the plain representation for the event resource, without embedding anything. A request like:
GET api.example.com/event/1?zoom=1
Would include the immediate children of event, in your case, the atendees. Following on that:
GET api.example.com/event/1?zoom=2
Would include the immediate children of event, the immediate children of atendees.
To answer your question, in REST the whole URI is an atomic identifier, so the parameters are part of the URI. That can be a problem if you're using something that won't interpret URIs in the same way, like old cache servers who won't cache URIs with a querystring.

Best practice for partial updates in a RESTful service

I am writing a RESTful service for a customer management system and I am trying to find the best practice for updating records partially. For example, I want the caller to be able to read the full record with a GET request. But for updating it only certain operations on the record are allowed, like change the status from ENABLED to DISABLED. (I have more complex scenarios than this)
I don't want the caller to submit the entire record with just the updated field for security reasons (it also feels like overkill).
Is there a recommended way of constructing the URIs? When reading the REST books RPC style calls seem to be frowned upon.
If the following call returns the full customer record for the customer with the id 123
GET /customer/123
<customer>
{lots of attributes}
<status>ENABLED</status>
{even more attributes}
</customer>
how should I update the status?
POST /customer/123/status
<status>DISABLED</status>
POST /customer/123/changeStatus
DISABLED
...
Update: To augment the question. How does one incorporate 'business logic calls' into a REST api? Is there an agreed way of doing this? Not all of the methods are CRUD by nature. Some are more complex, like 'sendEmailToCustomer(123)', 'mergeCustomers(123, 456)', 'countCustomers()'
POST /customer/123?cmd=sendEmail
POST /cmd/sendEmail?customerId=123
GET /customer/count
You basically have two options:
Use PATCH (but note that you have to define your own media type that specifies what will happen exactly)
Use POST to a sub resource and return 303 See Other with the Location header pointing to the main resource. The intention of the 303 is to tell the client: "I have performed your POST and the effect was that some other resource was updated. See Location header for which resource that was." POST/303 is intended for iterative additions to a resources to build up the state of some main resource and it is a perfect fit for partial updates.
You should use POST for partial updates.
To update fields for customer 123, make a POST to /customer/123.
If you want to update just the status, you could also PUT to /customer/123/status.
Generally, GET requests should not have any side effects, and PUT is for writing/replacing the entire resource.
This follows directly from HTTP, as seen here: http://en.wikipedia.org/wiki/HTTP_PUT#Request_methods
You should use PATCH for partial updates - either using json-patch documents (see https://datatracker.ietf.org/doc/html/draft-ietf-appsawg-json-patch-08 or http://www.mnot.net/blog/2012/09/05/patch) or the XML patch framework (see https://www.rfc-editor.org/rfc/rfc5261). In my opinion though, json-patch is the best fit for your kind of business data.
PATCH with JSON/XML patch documents has very strait forward semantics for partial updates. If you start using POST, with modified copies of the original document, for partial updates you soon run into problems where you want missing values (or, rather, null values) to represent either "ignore this property" or "set this property to the empty value" - and that leads down a rabbit hole of hacked solutions that in the end will result in your own kind of patch format.
You can find a more in-depth answer here: http://soabits.blogspot.dk/2013/01/http-put-patch-or-post-partial-updates.html.
I am running into a similar problem. PUT on a sub-resource seems to work when you want to update only a single field. However, sometimes you want to update a bunch of things: Think of a web form representing the resource with option to change some entries. The user's submission of form should not result in a multiple PUTs.
Here are two solution that I can think of:
do a PUT with the entire resource. On the server-side, define the semantics that a PUT with the entire resource ignores all the values that haven't changed.
do a PUT with a partial resource. On the server-side, define the semantics of this to be a merge.
2 is just a bandwidth-optimization of 1. Sometimes 1 is the only option if the resource defines some fields are required fields (think proto buffers).
The problem with both these approaches is how to clear a field. You will have to define a special null value (especially for proto buffers since null values are not defined for proto buffers) that will cause clearing of the field.
Comments?
RFC 7396: JSON Merge Patch (published four years after the question was posted) describes the best practices for a PATCH in terms of the format and processing rules.
In a nutshell, you submit an HTTP PATCH to a target resource with the application/merge-patch+json MIME media type and a body representing only the parts that you want to be changed/added/removed and then follow the below processing rules.
Rules:
If the provided merge patch contains members that do not appear within the target, those members are added.
If the target does contain the member, the value is replaced.
Null values in the merge patch are given special meaning to indicate the removal of existing values in the target.
Example test cases that illustrate the rules above (as seen in the appendix of that RFC):
ORIGINAL PATCH RESULT
--------------------------------------------
{"a":"b"} {"a":"c"} {"a":"c"}
{"a":"b"} {"b":"c"} {"a":"b",
"b":"c"}
{"a":"b"} {"a":null} {}
{"a":"b", {"a":null} {"b":"c"}
"b":"c"}
{"a":["b"]} {"a":"c"} {"a":"c"}
{"a":"c"} {"a":["b"]} {"a":["b"]}
{"a": { {"a": { {"a": {
"b": "c"} "b": "d", "b": "d"
} "c": null} }
} }
{"a": [ {"a": [1]} {"a": [1]}
{"b":"c"}
]
}
["a","b"] ["c","d"] ["c","d"]
{"a":"b"} ["c"] ["c"]
{"a":"foo"} null null
{"a":"foo"} "bar" "bar"
{"e":null} {"a":1} {"e":null,
"a":1}
[1,2] {"a":"b", {"a":"b"}
"c":null}
{} {"a": {"a":
{"bb": {"bb":
{"ccc": {}}}
null}}}
For modifying the status I think a RESTful approach is to use a logical sub-resource which describes the status of the resources. This IMO is pretty useful and clean when you have a reduced set of statuses. It makes your API more expressive without forcing the existing operations for your customer resource.
Example:
POST /customer/active <-- Providing entity in the body a new customer
{
... // attributes here except status
}
The POST service should return the newly created customer with the id:
{
id:123,
... // the other fields here
}
The GET for the created resource would use the resource location:
GET /customer/123/active
A GET /customer/123/inactive should return 404
For the PUT operation, without providing a Json entity it will just update the status
PUT /customer/123/inactive <-- Deactivating an existing customer
Providing an entity will allow you to update the contents of the customer and update the status at the same time.
PUT /customer/123/inactive
{
... // entity fields here except id and status
}
You are creating a conceptual sub-resource for your customer resource. It is also consistent with Roy Fielding's definition of a resource: "...A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time..." In this case the conceptual mapping is active-customer to customer with status=ACTIVE.
Read operation:
GET /customer/123/active
GET /customer/123/inactive
If you make those calls one right after the other one of them must return status 404, the successful output may not include the status as it is implicit. Of course you can still use GET /customer/123?status=ACTIVE|INACTIVE to query the customer resource directly.
The DELETE operation is interesting as the semantics can be confusing. But you have the option of not publishing that operation for this conceptual resource, or use it in accordance with your business logic.
DELETE /customer/123/active
That one can take your customer to a DELETED/DISABLED status or to the opposite status (ACTIVE/INACTIVE).
Things to add to your augmented question. I think you can often perfectly design more complicated business actions. But you have to give away the method/procedure style of thinking and think more in resources and verbs.
mail sendings
POST /customers/123/mails
payload:
{from: x#x.com, subject: "foo", to: y#y.com}
The implementation of this resource + POST would then send out the mail. if necessary you could then offer something like /customer/123/outbox and then offer resource links to /customer/mails/{mailId}.
customer count
You could handle it like a search resource (including search metadata with paging and num-found info, which gives you the count of customers).
GET /customers
response payload:
{numFound: 1234, paging: {self:..., next:..., previous:...} customer: { ...} ....}
Use PUT for updating incomplete/partial resource.
You can accept jObject as parameter and parse its value to update the resource.
Below is the Java function which you can use as a reference :
public IHttpActionResult Put(int id, JObject partialObject) {
Dictionary < string, string > dictionaryObject = new Dictionary < string, string > ();
foreach(JProperty property in json.Properties()) {
dictionaryObject.Add(property.Name.ToString(), property.Value.ToString());
}
int id = Convert.ToInt32(dictionaryObject["id"]);
DateTime startTime = Convert.ToDateTime(orderInsert["AppointmentDateTime"]);
Boolean isGroup = Convert.ToBoolean(dictionaryObject["IsGroup"]);
//Call function to update resource
update(id, startTime, isGroup);
return Ok(appointmentModelList);
}
Check out http://www.odata.org/
It defines the MERGE method, so in your case it would be something like this:
MERGE /customer/123
<customer>
<status>DISABLED</status>
</customer>
Only the status property is updated and the other values are preserved.
Regarding your Update.
The concept of CRUD I believe has caused some confusion regarding API design. CRUD is a general low level concept for basic operations to perform on data, and HTTP verbs are just request methods (created 21 years ago) that may or may not map to a CRUD operation. In fact, try to find the presence of the CRUD acronym in the HTTP 1.0/1.1 specification.
A very well explained guide that applies a pragmatic convention can be found in the Google cloud platform API documentation. It describes the concepts behind the creation of a resource based API, one that emphasizes a big amount of resources over operations, and includes the use cases that you are describing. Although is a just a convention design for their product, I think it makes a lot of sense.
The base concept here (and one that produces a lot of confusion) is the mapping between "methods" and HTTP verbs. One thing is to define what "operations" (methods) your API will do over which types of resources (for example, get a list of customers, or send an email), and another are the HTTP verbs. There must be a definition of both, the methods and the verbs that you plan to use and a mapping between them.
It also says that, when an operation does not map exactly with a standard method (List, Get, Create, Update, Delete in this case), one may use "Custom methods", like BatchGet, which retrieves several objects based on several object id input, or SendEmail.
It doesn't matter. In terms of REST, you can't do a GET, because it's not cacheable, but it doesn't matter if you use POST or PATCH or PUT or whatever, and it doesn't matter what the URL looks like. If you're doing REST, what matters is that when you get a representation of your resource from the server, that representation is able give the client state transition options.
If your GET response had state transitions, the client just needs to know how to read them, and the server can change them if needed. Here an update is done using POST, but if it was changed to PATCH, or if the URL changes, the client still knows how to make an update:
{
"customer" :
{
},
"operations":
[
"update" :
{
"method": "POST",
"href": "https://server/customer/123/"
}]
}
You could go as far as to list required/optional parameters for the client to give back to you. It depends on the application.
As far as business operations, that might be a different resource linked to from the customer resource. If you want to send an email to the customer, maybe that service is it's own resource that you can POST to, so you might include the following operation in the customer resource:
"email":
{
"method": "POST",
"href": "http://server/emailservice/send?customer=1234"
}
Some good videos, and example of the presenter's REST architecture are these. Stormpath only uses GET/POST/DELETE, which is fine since REST has nothing to do with what operations you use or how URLs should look (except GETs should be cacheable):
https://www.youtube.com/watch?v=pspy1H6A3FM,
https://www.youtube.com/watch?v=5WXYw4J4QOU,
http://docs.stormpath.com/rest/quickstart/