Jump to content

Name/value pairs or key/value properties for REST API update


NotionCommotion

Recommended Posts

I implemented an endpoint which receives name/value pairs:

PUT someresource/123 {"name": "description", "value": "Some new description"}

I think I made a mistake, and should have implemented it as:

PUT someresource/123 {"description": "Some new description"}

The reason I think so is updating multiple properties is only (easily) possible using the later:

PUT someresource/123 {"description": "Some new description", "otherProperty": "bla bla bla"}

Assuming I am not using some 3rd party client library which only works with name/value pairs, any compelling reason why one shouldn't default to the later approach with key/values?

Link to comment
Share on other sites

Before moving on...

The following seems clean enough:

//PUT /some/resource/123   body: {"description": "Some new description", "name": "new name" ...}
$app->get('/some/resource/{id:[0-9]+}', function (Request $request, Response $response, $args) {
    $resource=$this->getResource($args['id']);
    $params=$request->getParsedBody();
    foreach($params as $name=>$value) {
        $resource->$name=$value; //but implement more securely
    }
});

If I only wanted to update a single property (i.e. {"description": "Some new description"} ), the same server code works.

But I can also change the client request and do something like the following.

//PUT /some/resource/123/description   body: Some new description
$app->get('/some/resource/{id:[0-9]+}/{property}', function (Request $request, Response $response, $args) {
    $resource=$this->getResource($args['id']);
    $value=$request->getBody();
    $resource->$args['property']=$value;  //but implement more securely
});

Under normal circumstances, probably doesn't make sense.  Agree?

What if I wasn't updating some value stored in the DB but some "option" object which is stored as MySQL type JSON and wanted to keep it more flexible?

{
	"title": {
		"text": "Activity",
		"style": {
			"fontSize": "24px"
		}
	},
	"tooltip": {
		"borderWidth": 0,
		"backgroundColor": "none",
		"shadow": false,
		"style": {
			"fontSize": "16px"
		},
		"pointFormat": "{series.name}<br><span style=\"font-size:2em; color: {point.color}; font-weight: bold\">{point.y}%</span>"
	},
	"pane": {
		"startAngle": 0,
		"endAngle": 360,
		"background": [{
				"outerRadius": "112%",
				"innerRadius": "88%",
				"backgroundColor": "rgba(124,181,236,0.3)",
				"borderWidth": 0
			}, {
				"outerRadius": "87%",
				"innerRadius": "63%",
				"backgroundColor": "rgba(67,67,72,0.3)",
				"borderWidth": 0
			}, {
				"outerRadius": "62%",
				"innerRadius": "38%",
				"backgroundColor": "rgba(144,237,125,0.3)",
				"borderWidth": 0
			}
		]
	},
	"yAxis": {
		"min": 0,
		"max": 100,
		"lineWidth": 0,
		"tickPositions": []
	},
	"plotOptions": {
		"solidgauge": {
			"dataLabels": {
				"enabled": false
			},
			"linecap": "round",
			"stickyTracking": false,
			"rounded": true
		}
	}
}

I was thinking of something like the following to implement:

//PUT /some/resource/123/option/foo/bar/someproperty   body: TBD
$app->get('/some/resource/{id:[0-9]+}/option/{subproperties:.*}', function (Request $request, Response $response, $args) {
    $resource=$this->getResource($args['id']);
    $properties=explode('/', $args['subproperties']);
    //Update specific property in $resource->option using $properties
});

For this it kind of makes sense to target the specific property, but this is contrary to the earlier approach.  Or maybe I should keep with the {name: value} approach?

Link to comment
Share on other sites

Can't say I agree with that approach. It's too weird. Stick with the standard: the data in the request body.

If, however, modifying one or three specific properties is a common use case then that suggests your API should support it with a specific operation.

Link to comment
Share on other sites

12 hours ago, requinix said:

Can't say I agree with that approach. It's too weird. Stick with the standard: the data in the request body.

Just to make sure I was correctly communicating on my previous post, to change option.plotOptions.solidgauge.dataLabels.enabled from false to true, I would do one of the following requests:

PUT /some/resource/123/option/plotOptions/solidgauge/dataLabels   body: {enabled: true}
//or
PUT /some/resource/123/option/plotOptions/solidgauge/dataLabels/enabled   body: true

//If this is an acceptable approach, which request should be used?

and then get resource 123, get the option property, and finally use [plotOptions, solidgauge, dataLabels, enabled] to target the specific property.  Still too weird?

And to make sure I understand you, stick with the standard where the entire option JSON string is in the body, right?

Edited by NotionCommotion
Link to comment
Share on other sites

Yes. PUT should be the entire body, PATCH should be whatever the changes are, and POST can sorta be either.

So if you want to support a generic API for updating specific properties, use PATCH.

PATCH /some/resource/123 HTTP/1.1
Content-Type: application/json

{"option":{"plotOptions":{"solidgauge":{"dataLabels":{"enabled":true}}}}}

Unless you think a sort of "enable/disable chart label" API would make more sense, along the lines of /toggle/label/name/state:

POST /some/resource/123/toggle/label/solidgauge/enabled HTTP/1.1

 

Link to comment
Share on other sites

Ah, that is when I use PATCH!  I've never used the method, but was actually planning on using this approach but as PUT.  I even came up with the following to use in concert with xeditable.

function conv2obj(keys, value, object) {
    keys=path.split('.');
    object=object?object:{};
    var last = keys.pop();
    keys.reduce((o, k) => o[k] = o[k] || {}, object)[last] = value;
    return object;
}

var o=convert('option.plotOptions.solidgauge.dataLabels.enable', true);
//{"option":{"plotOptions":{"solidgauge":{"dataLabels":{"enable":true}}}}}

Shouldn't your second example us PUT since it is idempotent?  It doesn't replace the entire /some/resource/123 resource, but it does replace the entire /some/resource/123/toggle/label/solidgauge/enabled resource.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.