Mirror of the Rel4tion website/wiki source, view at <http://rel4tion.org>
Clone
HTTPS:
git clone https://vervis.peers.community/repos/yEzqv
SSH:
git clone USERNAME@vervis.peers.community:yEzqv
Branches
Tags
2.mdwn
[[!template id=ticket class=task]]
[[!meta title=“Routes for operations”]]
Issue
Suppose I have route /#!Text
for user pages, and routes /new
and /delete
for creating and deleting users respectively. How can /new
make sure the user created isn’t named new
or delete
? If I hardcode the check, I’ll have the path pieces in 2 places and I’ll have to remember to keep them in sync manually, which is very error-prone.
Plan
I asked on IRC, haven’t asked in MLs yet. Ideas I see are:
- Use a route that isn’t a valid username, e.g.
/_new
- Get some TH output generated from routes file, and use it to get a list of names to avoid
- Use a different piece name, e.g.
/user/#Text
and/user_new
- See if HTTP verbs can do it, since Yesod is meant to be RESTful. For example, if something like POST to
/users/john
creates a new userjohn
, I don’t need to worry about checking because/users/new
has just GET, and even if it has POST, it’s a separate POST with a separate handler.
Therefore:
(x)
Read about REST in Wikipedia( )
Finish reading about routes in the Yesod book( )
Read about forms in the Yesod book( )
Reading should hopefully provide enough info to solve this issue
REST
I read about [[!wikipedia REST]].
For a given user, HTTP verbs commonly work as follows. See the wikipedia link for more details.
GET /u/alice
retrieves a representation, without causing any side effectsGET /u
lists the users, perhaps with some info about themPUT /u/bob
replaces bob’s data with new data provided, or creates a new userbob
if it doesn’t exist yetPOST /u
creates a new user with auto-generated new URIDELETE /u/cindy
deletes usercindy
There are also other HTTP methods, such as PATCH
. When to use POST, when to use PUT? What if just few settings are changed? Let’s see some Yesod app examples. Looking in Hackage…
- [[!hackage Yablog]] uses POST and PUT, but it’s unclear. Some of the PUTs are simply undefined or redirect to POSTs.
- [[!hackage git-annex]] uses GET and POST, and not exactly RESTful
- [[!hackage hledger-web]] uses a single POST
- [[!hackage informative]], like git-annex, uses verb-based URLs with GET and POST
I’m reading [[!wikipedia “Patch verb”]] too. The idea is that:
- PUT supplies a modified version of the resource
- PATCH supplies a list of changes to perform on the resource
- POST can be used too for updating a resource, but needs specific application support and isn’t a generic update method like PATCH
PATCH seems to come from Ruby on Rails and involves extra complexity which Yesod doesn’t seem to have anything to do with. I can use the typical GET-PUT workflow. Here’s an initial suggestion:
- GET returns a form with details you can change
- PUT sends a possibly modified form input and the server changes the object
- POST can be used for custom inputs unrelated to RESTful entities, such as login forms or on-the-fly creation of tags etc.
What is the URL of the form though? When using JS, the form can be displayed anywhere, say the resource URL. But without eyecandy, the resource GET request returns a view, not a form with fields. So we need an additional, GET-only URL which returns a form with a button that PUTs it to the resource URL.
Do I still need to handle overlaps with this setup? Let’s see. Since Yesod picks the first route that matches in case of overlap, I could have something like this:
[[!format haskell """ /u PeopleR GET – Show list of people /u/!new AddPersonR GET – Supply new person registration form /u/#Text PersonR GET PUT – Show person or register person """]]
Is there a danger a user named “new” is created? While you can’t GET the details of such a user, you also can’t PUT them because the second route in the list will be matched, and it doesn’t have a POST handler. So you should get error 404. Hopefully.
I’m not done yet with reading about Yesod forms, but if forms must make a POST request and not PUT, I can support both PUT and POST, and simply make the POST handler be defined to the PUT handler.
Here’s a simple initial naming convention:
- Creation form URLs will look like
/u/new
- Update form URLs will look like
/u/update
- Deletion form URLs, if needed, will look like
/u/delete
Ah, the Yesod book actually has a page called “RESTful Content”! Reading now.
Hmmm problem: PUT must use an existing resource state to modify. The target URL of a form is fixed. User creation needs to use a fixed route, not a PUT based on user ident. I asked on IRC and looked in Wikipedia again. Here’s a new scheme:
[[!format haskell """ /u PeopleR GET POST – Show list of people or create new person /u/!new AddPersonR GET – Supply new person registration form /u/#Text PersonR GET PUT – Show person or update person """]]
Result
Continue here…