joaotavora / snooze

Common Lisp RESTful web development
207 stars 22 forks source link

Nested Resources? #19

Open oladon opened 4 years ago

oladon commented 4 years ago

Hi João!

I like the premise of Snooze — nice work! I've run into a bit of a snag, though...

Say I have the resource "dogs". I want to support:

GET /dogs/4 (get a dog by ID) POST /dogs (make a new dog)

When I try to do that with Snooze:

(defroute dogs (:get :text/html id)
  "Retrieve a dog by ID")

(defroute dogs (:post :text/plain)
  "Make a new dog.")

... Lisp complains (with good cause) because the number of arguments differ between the two methods.

I've looked through the docs and can't seem to find anything to support this use case. I've also tried specializing the defroute method on a null argument, but that doesn't seem to get passed along to defmethod correctly.

Could you help me understand what I'm missing?

oladon commented 4 years ago

Nevermind — I realized I can accomplish this using &optional parameters, of course. :)

oladon commented 3 years ago

Well, I'm back... :)

I'm hoping for some design help. I've read through this issue, and it seems like what I'm wanting should be doable, but I'm not sure the best way to go about it.

So as mentioned previously, I want to enable nested resources, like so:

GET /dogs GET /dogs?breed=malinois POST /dogs GET /dogs/1 (i.e. /dogs/:id) POST /dogs/1/foo

I'd previously closed this because designating parameters as optional solves part of this... but only if there are no query parameters allowed, because you can't have both &optional and &key. I can't seem to figure out a way to support this using Snooze.

Do any suggestions come to mind?

BenedictHW commented 2 years ago

I'm a beginner who was also wondering about this. I had to look back to Practical Common Lisp's section on 'Mixing Different Parameter Types' . It gave the design advice to not mix &optional and &key, for keywords can be mistaken as optional parameters. I suppose if we included an identifier while passing &optional arguments we would have re-invented keywords. Hence Seibel's later design recommendation to convert &optional to &key as the solution.

I'm also not creative enough to see a way for Snooze to support this mixture without also replicating the surprising behaviour. And to do so while remaining faithful to CL semantics. Not very helpful, but nonetheless I hope that helped.

Been loving snooze, thanks Joao.

hyotang666 commented 2 years ago

I use URI-TO-ARGUMENTS for such things as below.

(defresource dogs (http-method content-type &key))

(defroute dogs (:get :text/html &key id nested)
  "Retrieve a dog by ID" 
  (cond
    (nested :nested)
    (id :id)
    (t :otherwise)))

(defroute dogs (:post :text/plain &key)
  "Make a new dog.")

(defmethod uri-to-arguments ((resource (eql #'dogs)) uri)
  (multiple-value-bind (plain-args keyword-args)
      (call-next-method)
    (values nil
        (case (length plain-args)
          (0 keyword-args)
          (1 ; id
           (pairlis '(:id) plain-args keyword-args))
          (2 ; /:id/foo
           (pairlis '(:id :nested) plain-args keyword-args))))))

Do not know the best way though.