Time |
S |
Nick |
Message |
00:00 |
|
fumanchu_ |
there are even cases where PATCH collection/ with {id: null} is better than DELETE collection/item, again because it invalidates the correct URL |
00:02 |
|
BlueProtoman |
So then when would I even use PUT, then? |
00:02 |
|
fumanchu_ |
well PATCH doesn't create resources |
00:03 |
|
fumanchu_ |
PUT is most useful when creating a resource where you allow the client to name it |
00:03 |
|
fumanchu_ |
(whereas if the server needs to name it, POST to the collection instead) |
00:04 |
|
BlueProtoman |
Why not support PATCH and PUT/DELETE pairs at once? |
00:04 |
|
BlueProtoman |
Or, what if I want to only query whether or not I'm following a particular user (e.g. I'm looking at their profile page and want to know what icon to show) |
00:04 |
|
fumanchu_ |
you mean for the same entity URL? that's occasionallly useful |
00:06 |
|
fumanchu_ |
to know what icon to show, GET users/{me}/subscribed/. If it contains a link to users/{that-guy}/, show the "following" icon, otherwise, don't. |
00:07 |
|
fumanchu_ |
give users/{me}/subscribed a long cache lifetime, expecting that a) it will be hit often, and b) only {me} can change it and cares about immediate invalidation |
00:12 |
|
BlueProtoman |
New tangentially related question. If my users will be able to name their artworks, a sensible API would be /api/users/{author}/work/{slug-cased-name}. But what if they give multiple works the same name, or ones whose differences are lost when slug-casing? |
00:12 |
|
fumanchu_ |
...or want to rename the work without breaking all the links? |
00:13 |
|
BlueProtoman |
That, too. Or, hell, want to rename themselves? |
00:13 |
|
fumanchu_ |
that's why most APIs either use an opaque id (works/0b4f822a3/) or freeze the slug but allow the full name to vary |
00:14 |
|
BlueProtoman |
Ooh, the last one's good. |
00:14 |
|
fumanchu_ |
then you just have to check for collisions when forming slugs |
00:14 |
|
BlueProtoman |
I wanna have friendly-looking URLs. |
00:14 |
|
fumanchu_ |
sure |
00:15 |
|
fumanchu_ |
that at least allows you to defer the Rewrite-All-State-That-Might-Refer-To-This-ID logic |
00:16 |
|
fumanchu_ |
which you will run into if you're doing something version-control-y |
00:16 |
|
BlueProtoman |
Maybe I'll just submit works with POST instead of PUT... |
00:17 |
|
fumanchu_ |
let the server add trailing underscores and return 200 OK instead of 409 What Were You Thinking You Copyright Infringer You |
00:18 |
|
BlueProtoman |
Updated routes http://pastebin.com/1qq2wsVu |
00:19 |
|
BlueProtoman |
(The controllers routed to aren't really sensible yet, I'm just focused on the URLs) |
00:20 |
|
fumanchu_ |
I find "works/" meaning "a collection of works" vs. "users/" meaning "just one user--me" to be pretty confusing |
00:21 |
|
BlueProtoman |
Oooh, do HTTP caches care about query strings? |
00:21 |
|
BlueProtoman |
E.g. /something?wow=doge |
00:21 |
|
fumanchu_ |
yes; different query strings are different URL's |
00:21 |
|
fumanchu_ |
and will be cached/invalidated separately |
00:22 |
|
fumanchu_ |
in addition, several of the more popular caches are configured by default to not cache any URL that has a query string |
00:22 |
|
fumanchu_ |
e.g. Squid on the server side and IE on the client |
00:22 |
|
fumanchu_ |
(although I think IE might have relaxed that a hair in the last few years--not sure) |
00:31 |
|
|
quimrstorres joined #rest |
00:32 |
|
BlueProtoman |
fumanchu_: How about now? http://pastebin.com/XTn8AgE5 |
00:33 |
|
BlueProtoman |
Note that "remixing" does not mutate an existing work, it copies it. So maybe PATCH isn't the most appropriate way to express that? |
00:33 |
|
fumanchu_ |
correct |
00:34 |
|
BlueProtoman |
I'm thinking either POST or PUT |
00:34 |
|
fumanchu_ |
you have a few alternatives, but I would tend to POST to api/users/{me}/works/ with a payload that had the URL of the work I wanted to copy somewhere meaningful in it |
00:35 |
|
BlueProtoman |
Ooh, good idea |
00:47 |
|
|
quimrstorres joined #rest |
01:00 |
|
BlueProtoman |
fumanchu_: New question. "/api/users/something" and "/api/works/somethingElse" respectively signify that "something" operates on a user, and "somethingElse" operates on a work? Where would something like creating a new work fit in? |
01:01 |
|
fumanchu_ |
"operates on"? |
01:01 |
|
BlueProtoman |
Operates on or retrieves from, etc. |
01:02 |
|
fumanchu_ |
I find it's best to consider URL's as data hierarchies. api/ is all the data. api/users/ is all the users. api/users/{id}/ is one user. api/users/{id}/works/ is all the works for that user. and so on. |
01:02 |
|
BlueProtoman |
What if I want to get all the users who've liked a specific work? |
01:03 |
|
fumanchu_ |
I'd offer api/works/{work}/likes, which would have links to each of the users who've liked that work |
01:04 |
|
BlueProtoman |
Shouldn't that be /api/works/{user}/{work}/likes? |
01:04 |
|
BlueProtoman |
Because different people may give different works the same name, or one may remix another's |
01:04 |
|
fumanchu_ |
only if api/works/{user}/ is meaningful. I can't immediately see how |
01:04 |
|
fumanchu_ |
oic |
01:05 |
|
fumanchu_ |
then api/users/{id}/works/{id}/likes |
01:05 |
|
fumanchu_ |
whatever it takes to uniquely identify the subset of data you're talking about |
01:07 |
|
* fumanchu_ |
goes afk for a bit while Selenium takes over his desktop |
01:13 |
|
|
tbsf joined #rest |
01:16 |
|
|
tbsf joined #rest |
01:37 |
|
BlueProtoman |
fumanchu_: Still there? Got one more revision to show you. I appreciate your feedback and advice on all of this, by the way. http://pastebin.com/VD9AVd6X |
01:45 |
|
|
tbsf joined #rest |
01:47 |
|
|
quimrstorres joined #rest |
02:49 |
|
|
quimrstorres joined #rest |
04:02 |
|
|
fumanchu joined #rest |
04:16 |
|
|
fumanchu_ joined #rest |
07:16 |
|
|
_ollie joined #rest |
07:45 |
|
|
nesselbosch joined #rest |
07:48 |
|
|
interop_madness joined #rest |
07:48 |
|
|
interop_madness joined #rest |
07:56 |
|
|
DracoBlue joined #rest |
08:18 |
|
|
graste joined #rest |
08:29 |
|
|
quimrsto_ joined #rest |
08:31 |
|
|
gigo1980 joined #rest |
09:13 |
|
|
quimrstorres joined #rest |
09:17 |
|
|
GriffinHeart joined #rest |
09:27 |
|
GriffinHeart |
Hi everyone, how do you handle cases where creating a resource it has the side effect of creating other resources, specifically in the response. |
09:28 |
|
GriffinHeart |
example to make sense POST /world, creates a new world and this will also create a /house/3 and /car/4, my naive approach is something like { data { world }, extra { house/3, house/4 } } in response |
09:30 |
|
trygvis |
I would assume that the world resource would include links to either a "houses" list or the individual houses |
09:31 |
|
trygvis |
so after creating a world resource I would return the created resource (with a Content-Location header) |
09:31 |
|
trygvis |
or you can respond with 201 without a body, but with a Location header |
09:32 |
|
GriffinHeart |
so all these side effects should be part of the resource representation? |
09:37 |
|
trygvis |
that depends on how your want your resources to be used |
09:41 |
|
GriffinHeart |
hmmm...yeah, not entirely sure its mostly because these might happen or not when creating a world, so I guess the heart of the question is how do I tell, in a RESTful way, that other resources were created as a result of this one. |
09:42 |
|
_ollie |
You return the location of the most fundamental one you created and the representation of that would contain links to the related resources created. |
09:42 |
|
trygvis |
you often don't, you create a new resource R, the client does a GET for R and R points to what is useful from that context |
09:45 |
|
GriffinHeart |
Yeah thanks, that seems to be the way, something wasn't sitting right with me, if they're important to the resource world then they should be inside/linked in its representation |
09:46 |
|
trygvis |
sometimes I've a POST create two separate resource A and B that are important to the client, then I've said that the POST returns a special resource that points to A and B |
09:46 |
|
trygvis |
but in your case (worlds and houses) it sounds like there is a natural relationship between the resources |
09:47 |
|
GriffinHeart |
unrelated question, is POST /world/run as in "run this world" a valid way of representing a operation/slash command? (doesn't result in creating a resource) |
09:48 |
|
GriffinHeart |
or that would be better handled by something like PUT /world body: { run: true } |
09:48 |
|
GriffinHeart |
sorry with id in the uri, of course. |
09:48 |
|
trygvis |
I would include a relation from the world resource pointing to where the client do a request |
09:53 |
|
GriffinHeart |
@trygvis Thanks, definitely in this case they have a relationship, the two separate resource was the one I was intrigued and begged the question |
09:53 |
|
|
gigo1980_ joined #rest |
09:54 |
|
GriffinHeart |
I was thinking its not very restful because you're returning in the body of the response something that is not a resource it self |
09:55 |
|
trygvis |
I don't know how you're modelling your executions, but the POST could easily create a new "execution" resource that the client could poll to see the current status, and/or end result and then delete later on |
09:58 |
|
GriffinHeart |
@trygvis in more abstract how do you handle a command vs an edit? Something that has business logic to it. |
10:05 |
|
trygvis |
I would create a relation from a resource and POST stuff there |
10:06 |
|
trygvis |
the documentation specifies what the request should look like |
10:08 |
|
GriffinHeart |
so the operations would be like resources but only with the C of CRUD?! only POST world/1/run would be valid not GET world/1/run |
10:09 |
|
trygvis |
unless something is telling the client that world/1/run is a place to go, no client will do a GET there |
10:09 |
|
trygvis |
and REST != CRUD |
10:12 |
|
GriffinHeart |
I see |
10:16 |
|
GriffinHeart |
Thanks @trygvis very useful |
10:18 |
|
|
Coldblackice_ joined #rest |
10:47 |
|
|
gigo1980_ joined #rest |
11:00 |
|
|
Macaveli joined #rest |
11:21 |
|
|
quimrsto_ joined #rest |
12:46 |
|
|
DracoBlue joined #rest |
13:39 |
|
|
gigo1980__ joined #rest |
14:38 |
|
|
Macaveli_ joined #rest |
14:42 |
|
|
wsiqueir joined #rest |
14:49 |
|
|
tbsf joined #rest |
14:50 |
|
|
quimrstorres joined #rest |
15:10 |
|
|
gigo1980 joined #rest |
15:49 |
|
|
tbsf joined #rest |
16:57 |
|
|
BlueProtoman joined #rest |
16:58 |
|
|
quimrstorres joined #rest |
17:00 |
|
|
DracoBlue joined #rest |
17:27 |
|
|
quimrstorres joined #rest |
17:27 |
|
|
DracoBlue joined #rest |
18:39 |
|
|
Devastator_ joined #rest |
18:46 |
|
|
quimrstorres joined #rest |
19:18 |
|
|
Devastator_ joined #rest |
19:50 |
|
|
quimrsto_ joined #rest |
19:51 |
|
|
quimrsto_ joined #rest |
20:34 |
|
|
gigo1980 joined #rest |
22:49 |
|
|
Coldblackice joined #rest |