2

At the moment I design a RESTful API for a resource that is normally created by a cron job from existing data.

Since the cron job runs only every 10 minutes it is possible that GET: /user/{id}/resource returns a 404 Not Found. In that case the client needs to create the resource with a POST request with an empty body I think.

To make things more convenient I would like to create the resource when the client calls GET: /user/{id}/resource if it is not existent and return the freshly created resource.

Are there arguments against using GET to create the resource that later will be created automatically anyways?

Some more information on why the cron job is needed:
The resource is also consumed by another service. This service calls a route GET: /users/usersWithResource to sync users to its database.

6
  • 2
    Most software developers would not expect a GET to create a resource, so it does violate the Principle of Least Surprise. Commented Aug 12, 2023 at 12:08
  • 4
    Opposed to what others have written here, creation of a resource on demand ("just in time") is IMHO nothing very special. But when I read your scenario description, I don't understand why you still need a cron job, when creation happens automatically as soon as the resource is required. Can you please clarify?
    – Doc Brown
    Commented Aug 12, 2023 at 12:28
  • @DocBrown The cronjob is needed because another service in the system relies on the created resources. It fetches them from another endpoint.
    – Timo
    Commented Aug 12, 2023 at 12:42
  • 3
    Taking what others have said into consideration, in the end, it really depends on the semantics of your resource (i.e. what is meant by it), and on what the user expects, and also on if it's problematic to accidentally trigger the resource generation. The abstract resource can conceptually exist (perhaps as soon as the user is created), but can be currently empty, in which case 404 Not Found is not the appropriate response. It may or may not have an actual document/data backing it. The representation can be generated on the fly, or it can be derived from data, and it can change over time. Commented Aug 12, 2023 at 14:18
  • Suppose your GET endpoint gets called with a non-existing (or even a malformed) user-id, do you still want to automatically create a user record or should there be some safeguard in place. Keep in mind that your front-end is not guaranteed to be the only user of the endpoint (on the internet, it is guaranteed not to be). Commented Aug 14, 2023 at 7:48

3 Answers 3

5

The strongest argument would be that it violates HTTP Semantics.

GET is a safe method, and safe methods are "essentially read-only". That doesn't mean that there can't be side-effects. Two examples are given in the RFC. One is appending to a log file, even though append operations could cause the server to fail if it is out of storage space. Another example is charging an account when an advertisement is displayed. However, these examples are not state changes on the target resource, and the use of a safe method means that "the client does not request, and does not expect, any state change on the origin server as a result of applying a safe method to a target resource".

Creating a new resource would be unexpected behavior, to both clients and future maintainers of the system. Most clients or people developing clients would not expect server state changes on a GET request, and people maintaining the system may not expect to find such behavior implemented as a response to a GET request. It would be surprising behavior to many people. I tend to avoid surprising behavior due to the communication (between people about the behavior) and maintenance (when debugging or evolving the system) overhead.

That said, I have seen systems that do implement behavior that you describe, so it's not unheard of. However, there's not enough information to say if it makes sense in your context. I would need to understand why it is beneficial to create the resource in response to a GET request instead of allowing GET to return the current state of the server and the cron job to perform its job of creating necessary resources. The benefits could very well outweigh the costs.

9
  • Thanks! The only consumer at the moment is the front-end. They would need to create the missing resource anyway. Therefore, creating it in the GET request directly would reduce the amount of requests and the complexity on their side.
    – Timo
    Commented Aug 12, 2023 at 12:33
  • 2
    @Timo So why do you need a cron job? From a system maintainers' perspective, this is surprising behavior where not only do you create resources on request but also have a frequent cron job that also creates resources. I'd choose one over the other. And without a strong argument, I'd favor the cron job (or a POST/PATCH/PUT endpoint that lets clients explicitly create resources) over otherwise surprising behavior.
    – Thomas Owens
    Commented Aug 12, 2023 at 12:38
  • Another service of the system consumes the resources, but it uses another end point. That service relies on the cron job at the moment.
    – Timo
    Commented Aug 12, 2023 at 12:50
  • 3
    @Timo It seems like there are deeper design issues with the system. It's not clear what endpoint this other service consumes, why that endpoint can't create resources, or, if its consuming resources, why it's not using the same GET endpoint as other clients that consume resources. So far, I'm not seeing a strong argument for introducing surprising behavior to a GET request.
    – Thomas Owens
    Commented Aug 12, 2023 at 12:54
  • The RFC9110 says that you can add (one-time or always-present) side effects and/or additional behavior, as long as that satisfies some notion of "safe" for anyone or anything that can access the resource via the GET request - "What is important, however, is that the client did not request that additional behavior and cannot be held accountable for it.". So I guess the question is how surprising/unexpected the side effect is, in what ways can things go wrong, and what's the extent of the impact. Commented Aug 12, 2023 at 14:23
2

To make things more convenient I would like to create the resource when the client calls GET: /user/{id}/resource if it is not existent and return the freshly created resource.

That's fine.

The semantics of a GET request are "transfer the current selected representation for the target resource". How the server produces that representation is an implementation detail (which is not constrained by HTTP semantics).

See also: Fielding, 2002.

1

There is a security consideration here with creating data using a GET request. Semantics aside, a simple script tag on any site on the Internet could potentially carry out a DDOS attack.

<script src="https://yoursite.com/user/1/resource" defer></script>
<!-- 9,998 more of these tags -->
<script src="https://yoursite.com/user/10000/resource" defer></script>

The browser will happily send that GET request with cookies (unless you enforce CORS restrictions on those cookies).

Now imagine user IDs are sequential numbers, and there are 10,000 of these script tags on one page where the user Id begins with 1 and is increased by one on each subsequent tag. The browser will fire off a whole bunch of these requests at once. Not an issue if the person visiting that page is unauthenticated, but what happens if a user who is logged in visits this page?

This, of course, depends on how authentication is handled in your application. If using bearer tokens in the http headers, then this isn't likely an issue. User IDs which are not numbers would also mitigate this situation providing your code handles the use case where an non-existent user Id is specified in the URL. If your site uses cookie-based authentication and you don't have cookies properly restricted by domain, then blammo. Your site could get pretty busy.

In a way, I wish I could combine my answer with the one from Thomas Owens. My answer illustrates why a GET which does more than "read" information can be problematic. Sometimes the semantics of REST don't give you the full picture, and you must consider the ramifications of malicious users abusing your system to fully understand why a particular recommendation exists.

I would recommend returning a 404 Not Found and forcing the client to issue a POST to create the resource.

Conversely, if you can mitigate scenarios like the one I outlined above, then the answer by TheVoiceOfUnreason applies. You could create the resource automatically and accept that this might be surprising.

Sometimes you have a compelling reason to break or stretch semantics if it makes sense for the use case, you properly document this deviation from client expectations, and you can mitigate any cyber security issues that arise from misuse.

3
  • Isn't it possible to send a POST request in a script tag too?
    – Timo
    Commented Aug 12, 2023 at 16:47
  • @Timo, no. Browsers only send GET requests when using a script tag. Commented Aug 13, 2023 at 3:24
  • Okay in my case the user needs to be authenticated to access the endpoint. So user with id 1 can only access yoursite.com/user/1/resource. Endpoints with other user ids would return a 403 response. That is the same behavior like when the resource is not created in the GET route.
    – Timo
    Commented Aug 14, 2023 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.