clash
clash

Reputation: 427

What request to use to update resource without sending data

every now and then I come to this question, google around for some time without getting a definitive answer and let it be.

Problem:

I want to update an existing resource, but the logic how this update works is on the backend side.

Let's assume a product should only be visible for a set time. Keeping it simple. The time "from" is stored in the database along the product data: product.visibleFromDate and the duration (eg. 30 days) is just a variable or configured somewhere (not in DB).

Now I want to call the backend telling it to update the visibleFromDate to "now": /api/product/:id/updatevisibility In this case I don't want to send a body because the server should determine what value "now" really is.

I actually don't really care if the server answers with the updated resource or no content.

HTTP Request

GET

POST

PUT

PATCH

Of course I could just send an empty object, the whole resource or some nonsense and ignore it on the backend side, but still I feel like I am missing this "trigger" type of requests which only need the type of resource, id and action.

Upvotes: 6

Views: 3029

Answers (4)

Yılmaz Durmaz
Yılmaz Durmaz

Reputation: 3014

my other answer did not satisfy you, so i will try the same but from a different viewpoint.

you are data engineer:

  • you don't retrieve any data with this operation, so no GET.
  • you operate on already-existing data, so no POST.
  • you don't change the whole data, so no PUT.
  • you are partially changing the data, see, you just use PATCH for the operation.
  • you will send an empty body {} to be consistent

you are an operational backend engineer.

  • GET is still considered to be used to retrieve a resource.
  • you want to run a function on the server which will partially modify the resource having the id given as the parameter in the url, so just use a POST request. it is like calling a function in your programming language.
  • or try PATCH to get the sympathy of your users.
  • or use PUT to get their anger when they realized what happens.
  • it is already getting the id from the URL, so you don't have to send any body unless your frontend API forces. curl won't send a body if you don't give one, for example.

semantics are not hard-coded rules. they are there to guide you and keep you in the line as much as possible. the problem is that they don't have solid implementation details. they are also "opinions" of a group of people which has pretty fine shape anyone can accept.


PS: It is said, "POST can be used on an already-existing data to append". sure it is, but the question in scope asks about changing a field, not creating a new one.

Upvotes: -1

Yılmaz Durmaz
Yılmaz Durmaz

Reputation: 3014

You would definitely want POST over GET for authorization/authentication purposes.

You don't need to have a body for a POST request. Your endpoint will just listen for a request, it will extract :id, and then run your time update function.

PUT and PATCH are semantic equivalents to POST. Unless you programmed the backend to differentiate them, there won't be any difference. You don't even need them at all.

A single empty-body POST will be enough for your endpoint. But you may consider using empty-body PATCH just as a meaningful endpoint. In both cases, your backend will extract the :id and then just run the same function (after auth* if any)


EDIT: Seems not all people can grasp what I have, so here are a working nodejs/express backend and curl requests to use. you don't need a request body, and all behave the same, except semantics and security over GET.

this is the server code:

const express = require('express');

const app = express();
const port = 3000

const updatetime = async (id)=>{
 let newdate=Date.now();
 console.log(`updating resource ${id} to have a new date ${newdate}`);
 return Promise.resolve("done")
}

const processrequest=async (req, res) => {
 console.log(req.method);
 console.log(req.headers);
 console.log(req.headers.authorization);
 console.log(req.body)
 console.log(req.params)
  try{
    let result=await updatetime(req.params.id);
    console.log(result);
    res.status(200).send("time updated")
  }catch{
    res.status(500).send("something went wrong")
  }
}

app.get(  '/:id/updatetime', (req, res) => processrequest(req,res))
app.post( '/:id/updatetime', (req, res) => processrequest(req,res))
app.put(  '/:id/updatetime', (req, res) => processrequest(req,res))
app.patch('/:id/updatetime', (req, res) => processrequest(req,res))


app.listen(port, () => {
  console.log(`listening on port ${port}`)
})

test all endpoint without a body, all works because magic:

curl -X GET -H "Authorization: Basic" localhost:3000/123qwe/updatetime
time updated
curl -X POST -H "Authorization: Basic" localhost:3000/123qwe/updatetime
time updated
curl -X PUT -H "Authorization: Basic" localhost:3000/123qwe/updatetime
time updated
curl -X PATCH -H "Authorization: Basic" localhost:3000/123qwe/updatetime
time updated

server output for all request types are the same because it is just a magic(!) that is developers' choice of implementation:

listening on port 3000
GET/POST/PUt/PATCH
{
  host: 'localhost:3000',
  'user-agent': 'curl/7.78.0',
  accept: '*/*',
  authorization: 'Basic'
}
Basic
undefined
{ id: '123qwe' }
updating resource 123qwe to have a new date 1656495470330
done

Upvotes: 1

Itay Wolfish
Itay Wolfish

Reputation: 566

You are not required to pass a body in a request (Although the specification says so), PATCH will be your best option here since semantically it is updating an “part of existing resource” while PUT is meant for "updating the entire resource".

Upvotes: 0

Behrooz
Behrooz

Reputation: 1734

Depending on the mutability of the data it should either be POST(immutable) or PATCH(mutable). It doesn't depend on what You're sending or not sending.
If You really want to do it by the book then you should send a '{}' when there are no fields to send. If any is added later you will just add it like '{"duration":"30"}'

Upvotes: 1

Related Questions