Skip to content

Conversation

@1000jobboersen
Copy link

Consider this a proposal --

This introduces a slight change to the semantics in the processing of a
request when #post_is_create? returns true, adding support for
environments where create_path cannot be determined before processing
the request.

Thus, an implementor using MongoDB can do:

class MyResource
  def create_path
    request.path_info[:id] = BSON::ObjectId.new
    "/resources/#{request.path_info[:id]}"
  end
end

While an implementor using Postgres might do:

class MyResource
  def create_path() nil end
  def accept_json
    resource = Resource.create
    response.headers['Location'] = "/resources/#{resource.id}"
    true
  end
end

Additionally, the response header's location is only set after the
accept handler has run, in case the handler fails for some other reason
(such as an incorrect content type).

With this feature and the feature guard feature #25, I'm able to get the following (very pleasing!) behavior: https://gist.github.com/1600780

@seancribbs
Copy link
Member

@bernerdschaefer I have discussed this problem with the creators of the Erlang version and we agree that this would change semantics in an undesirable way. Here's what we discussed:

  • create_path was originally envisioned as side-effect free when possible, but "light" in the worst cases. It should obviously not do the work of storing anything, instead just return a string or URI-equivalent where the resource will be created.
  • The original intent of the post_is_create + create_path flow is to treat an incoming POST as a PUT to the created path. This way your acceptor method/function doesn't have to know whether this is a new resource or not, it does its work in the exact same manner.

A way around this chicken-and-egg problem is to provisionally allocate an identifier in create_path, then use that identifier in accept_helper. This is what you did in the Mongo example. For a relational DB, you might be able to open a transaction, get the next ID on the table or counter and use that, then commit at the end of the acceptor method.

Another option is to simply look at the request body inside create_path and return a bogus path if it is known the body will not be acceptable. Also, look at the finish_request callback, which can be used for whatever purpose you desire and is always called at the end of any request processing -- this might be a place you could rollback that DB transaction if it hasn't been committed.

I know that this answer is not ideal, but I disagree that reversing the order is the right solution, it changes the semantics too much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants