How to handle "Change Reason" in a PUT Request? - web-services

I work with a system that requires that each change be audited and a reason specified for each change. In trying to keep with good REST design, we want to use the HTTP verbs correctly.
With regards to this particular case, I am unsure about best way to handle this situation. Lets say we have a simple entity:
URL: /users/100
JSON: { username: 'usr1', firstName: 'John', lastName: 'Smith' }
Now if I want to update the username from 'usr1' to 'user1', our system requires that I specify the reason for the change.
Without the change reason requirement, we could easily just PUT the JSON to the URL.
My question is what is the best way to send the change reason to the server. Here are the options I have come up with so far:
Add a changeReason attribute to the entity.
Add changeReason as a query parameter.
Add a changeReason header.
None of these options seem right to me. Has anyone dealt with this before?

First, some thoughts to your proposed solutions:
Add changeReason to the JSON object: Is bad, because (if using the same mime-type) the GET would not need that field.
As query parameter: Is wrong, because it is not a parameter for the resource (but for the request)
As header: Is wrong, because this is an out-of-band information.
So, certainly this information should be part of the request representation, and the update happens on the user, so the URL should not change (it is the same resource). I propose the PATCH method, which was created seemingly for the exact purpose you describe.
With the PATCH method, you have to describe a "change" representation, that specifically describes a change you want applied to a resource. This document format will be different from any resource formats, and could then contain a "changeReason". Looks something like this:
PATCH /users/100
Content-Type: application/vnd.company.auditedchange+json
{
"replaceFields": {
"username": "user1"
}
"changeReason": "Typo in username."
}

Introduce a new resource userchange. POST to it with the information about the change.
POST /userchange
Content-Type: application/json
{
"id": 100,
"changes": {
"username": "user1"
},
"reason": "fixed name"
}
The server would execute the change on the user and log the reason.

Related

AWS AppSync access parent resolver properties in nested resolver (interpolation problem?)

I have a GraphQL API which works like this:
mutation {
customer(id: "123") {
someMutation(new: "data") {
id name email # from customer
}
}
}
We use nested resolver style because we have a large schema, and it helps keep things clean.
This means we need to resolve "args" from the someMutation, and inherit the ID from the parent resolver.
AWS AppSync docs claims that you can do this with the $context.source.id field, but there are so far as I can tell zero documented options. We have tried this Velocity Template:
{
"version": "2018-05-29",
"method": "POST",
"params": {
"headers": {
"Content-Type": "application/json"
},
"query": {
"command_name": "set_email",
"new": $util.toJson($context.arguments.new),
}
},
"resourcePath": $util.toJson("/customers/$context.source.id")
}
Scant little documentation exists (except this "resolver template mapping guide") about interpolation, or string concatenation, it is pretty inadequate.
According to the "Resolver mapping template context reference" $context.source should "A map that contains the resolution of the parent field."
The failure mode here is that my downstream HTTP resolver is receiving the literal string "/customers/$context.source.id" rather than the interpolated variable.
Try as I might I cannot figure a way to get an interpolated value with or without any $util...() helpers for JSONification string concatenation, any combination of quoting, etc.
So, I figured this out in the end. The parent resolver wasn't responding with the {id: '123'...} data.
I found out that AppSync has a test console, which helped me verify that, yes, indeed my VTL template was working correctly with the expected payload.
What I found incredibly unintuitive, however was that unlike most template languages which would interpolate an empty variable to "" (empty string), VTL templates seem to behave as though you had no interpolation what so ever leading me to question the interpolation syntax in general.
See the screenshot from the AppSync test console below.
There should also be a way to write tests in that use the AWS CLI/SDK but I didn't bother looking into it, ergonomics are bad for that, needing us to configure the CI with a test account on AWS, and we test our application logic at a higher level, anyway.

REST - post to get data. How else can this be done?

According to my understandings, you should not post to get data.
For example, I'm on a project and we are posting to get data.
For example, this following.
{
"zipCOde":"85022",
"city":"PHOENIX"
"country":"US"
"products":[
{
"sku":"abc-21",
"qty":2
},
{
"sku":"def-13",
"qty":2
}
]
}
Does it make sense to post? How could this be done without posting? There could be 1 or more products.
Actually there is a SEARCH method in HTTP, but sadly it is for webdav. https://msdn.microsoft.com/en-us/library/aa143053(v=exchg.65).aspx So if you want to send a request body with the request, then you can try with that.
POSTing is okay if you have a complex search. Complex search is relative, by me it means, that you have different logical operators in your query.
The current one is not that complex, and you can put the non-hierarchical components into the query string of the URI. An example with additional line breaks:
GET /products/?
zipCOde=85022&
city=PHOENIX&
country=US&
filters[0]['sku']=abc-21&
filters[0]['qty']=2&
filters[1]['sku']=def-13&
filters[1]['qty']=2
You can choose a different serialization format and encode it as URI component if you want.
GET /products/?filter={"zipCOde":"85022","city":"PHOENIX","country":"US","products":[{"sku":"abc-21","qty":2},{"sku":"def-13","qty":2}]}
One potential option is to JSON.serialize your object and send it as a query string parameter on the GET.

REST API design: different granularity for receiving and updating resources

I'm in the process of creating a REST API. Among others, there is a resource-type called company which has quite a lot of attributes/fields.
The two common use cases when dealing with company resources are:
Load a whole company and all its attributes with one single request
Update a (relatively small) set of attributes of a company, but never all attributes at the same time
I came up with two different approaches regarding the design of the API and need to pick one of them (maybe there are even better approaches, so feel free to comment):
1. Using subresources for fine-grained updates
Since the attributes of a company can be grouped into categories (e.g. street, city and state represent an address... phone, mail and fax represent contact information and so on...), one approach could be to use the following routes:
/company/id: can be used to fetch a whole company using GET
/company/id/address: can be used to update address information (street, city...) using PUT
/company/id/contact: can be used to update contact information (phone, mail...) using PUT
And so on.
But: Using GET on subresources like /company/id/address would never happen. Likewise, updating /company/id itself would also never happen (see use cases above). I'm not sure if this approach follows the idea of REST since I'm loading and manipulating the same data using different URLs.
2. Using HTTP PATCH for fine-grained updates
In this approach, there are no extra routes for partial updates. Instead, there is only one endpoint:
/company/id: can be used to fetch a whole company using GET and, at the same time, to update a subset of the resource (address, contact info etc.) using PATCH.
From a technical point of view, I'm quite sure that both approaches would work fine. However, I don't want to use REST in a way that it isn't supposed to be used. Which approach do you prefer?
Do you really nead each and every field contained in the GET response all the time? If not, than its more than just fine to create own resources for addresses and contacts. Maybe you will later find a further use-case where you might reuse these resources.
Moreover, you can embed other resources as well in resources. JSON HAL (hal-json) f.e. explicitely provides an _embedded property where you can embed the current state of f.e. sub-resources. A simplified HAL-like JSON representation of an imaginary company resource with embedded resources could look like this:
{
"name":"Test Company",
"businessType":"PLC",
"foundingYear": 2010,
"founders": [
{
"name": "Tim Test",
"_links": {
"self": {
"href": "http://example.org/persons/1234"
}
}
}
],
...
"_embedded": {
"address": {
"street": "Main Street 1",
"city": "Big Town",
"zipCode": "12345",
"country": "Neverland"
"_links": {
"self": {
"href": "http://example.org/companies/someCompanyId/address/1"
},
"googleMaps": {
"href": "http://maps.google.com/?ll=39.774769,-74.86084"
}
}
},
"contacts": {
"CEO": {
"name": "Maria Sample",
...
"_links": {
"self": {
"href": "http://example.org/persons/1235"
}
}
},
...
}
}
}
Updating embedded resources therefore is straigtforward by sending a PUT request to the enclosed URI of the particluar resource. As GET requests my be cached, you might need to provide finer grained caching settings (f.e. with conditional GET requests a.k.a If-Modified-Since or ETAG header fields) to retrieve the actual state after an update. These headers should consider the whole resource (incl. embedded once) in order to return the updated state.
Concerning PUT vs. PATCH for "partial updates":
While the semantics of PUT are rather clear, PATCH is often confused with a partial update by just sending the new state for some properties to the service. This article however describes what PATCH really should do.
In short, for a PATCH request a client is responsible for comparing the current state of a resource and calculating the necessary steps to transform the current resource to the desired state. After calculating the steps, the request will have to contain instructions the server has to understand to execute these instructions and therefore produces the updated version. A PATCH request is furthermore atomic - either all instructions succeed or none. This adds some transaction requirements to this request.
In this particular case I'd use PATCH instead of subresources approach. First of all this isn't a real subresources. It's just a fake abstraction introduced to eliminate the problem of updating the whole big entity (resource). Whereas PATCH is a REST compatible, well established and common approach.
And (IMO ultima ratio), imagine that you need to extend company somehow (by adding magazine, venue, CTO, whatever). Will you be adding a new endpoint to enable client to update this newly-added part of a resource? How it finishes? With multiple endpoint that no one understands. With PATCH your API is ready for new elements of a company.

Different Models for RESTful GET and POST

Does it violate the ideas of REST, or accepted conventions, to have different models for GET/PUT/POST at the same URL?
An example:
Consider a simple resource found at api/things
I can create a thing by:
POST api/things
with body = { Name: "New Thing" }
This returns me a thing along with location
{ Id: 500, Name: "New Thing", Links: ["api/things/500"] }
Location Header: api/things/500
I can get the thing with:
GET api/things/500
and I will get
{ Id: 500, Name: "New Thing", Links: ["api/things/500"] }
If I want to update it:
PUT api/things/500
{ Name: "Updated Thing", IsActive: false }
There are "rules" in this example that are hidden behind the different models.
When creating you can't specify the Id or IsActive setting. The Id is generated by the server always starts as Active.
You cannot update an Id, and thus the "link" which uses it, so the PUT model does not contain an Id field.
One strong criticism of this: I cannot do a POST to create a new one, change the Name field, and PUT it back to Update it. I would have to know to remove the Id and links fields. I could "be liberal in what I accept" and allow the Ids and Links to be on the PUT request, but then I need to make additional decisions like, "is it a 400 if the Id/Link they send is different?, and "is it a 400 if they don't send an Id/Link?". If the API claims to accept those fields on PUT, that could be seen as a contract that they are able to be updated.
It is perfectly valid to accept different DTO's for different methods. Quite often, a POST will create a new entity with default properties such as Id, StartDate or Active, etc. so these properties are not present on a "POST DTO". I tend to shy away from PUT's since the definition is you are replacing one entity with another, which could include an Id. I opt for PATCH in most cases where you are accepting deltas and partial objects. You can verify each property that was sent up and determine if it's a readonly property or not. In some cases, based on roles, it may be readonly for one user, and patchable by another. By following this, POST is one DTO, PATCH is partial, PUT is non-existent, and GET returns the full DTO.
I've only seen a couple places where PUT is useful. You want to change the binary of a file or you have a collection that you want to change, PUT is great. Otherwise, I love PATCH.

REST Array manipulation best practice

I have full access to foo resource via REST:
{
"name": "foo",
"tags": [
"tag01",
"tag02",
"tag03"
]
}
I would like to delete tag01 in tags array.
Usually I would GET \foo and PUT \foo it back without tag01.
In this case this object is small, so this is ok.
But let's assume it's much bigger. For this case I don't like to download and upload this data. After some google research I found out http PATCH. I looks like exactly what I need.
My request in PATCH way is now
PATCH /foo/tags?op={add|delete}
To delete I would use:
PATCH /foo/tags?op=delete
With this data:
{
"value": "tag01"
}
There are now two thinks that I don't like:
query field op - are there some deafult names described in rfc or smth. like this
member value in request data - this is also freely chosen name
It doesn't look correct to me.
Is there some other way to manipulate arrays via REST?
Are there some name conventions to do it in PATCH way?
The payload of a PATCH should contain "instructions describing how a resource currently residing on the origin server should be modified to produce a new version". All information should be passed in the payload and not in query-params.
For instance you could send:
PATCH /foo
[
{
"op": "remove",
"path": "/tags/0"
}
]
Path /tags/0 points to the first element of the array. The remaining elements should be shifted to the left.
See the JSON Patch draft for more details.
Is there some other way to manipulate arrays via REST?
Yes, because it is not correct. By REST you map your URLs to resources (not operations) and you manipulate resources using HTTP methods and sending representations. Having an op:remove in an URL or in a representation is wrong.
Are there some name conventions to do it in PATCH way?
No there are no REST naming conventions. The URI structure does not matter by REST clients, because they follow hyperlinks with semantic annotations.
If you need an op:remove or similar somewhere, then it indicates that your URI - resource mapping is not good. Probably you have to define a new resource or rethink the resource structure.
I would describe what you want as a bulk create and bulk delete. You can model this cases with something like:
POST /collection [{},{},...] -> 201
DELETE /collection?filter="..." -> 204
In order to delete something from a collection you need a resource identifier URI. In this case this can contain the tag name or the index in the array (if it is ordered).
/foo/tags/tag01
/foo/tags/0
It is up to you, but I would use the tag name.
After that it is pretty simple:
POST /foo/tags ["a","b","c"]
DELETE /foor/tags?name="a,b,c"
So PATCH is not the method you are looking for, because you are creating and removing resources and not replacing them.