How to return json data from message! handler in clojure liberator?

How to return json data using Clojure Liberator? This code does not work:

(defresource poster [] :allowed-methods [:post :options] :available-media-types ["application/json"] :post! (fn [ctx] (println "posting...")) :handle-created (fn [ctx] {:created "ok"})) 

Should a handle be called after publication?

+5
source share
3 answers

Key related function :post! is not a function of the handler. The Liberator documentation calls this an action function.

Action Functions Keys: post!,: Put! and: delete! Provide points that are good for taking side effects. As long as they are evaluated as functions of a decision, the logical value has no effect, and the next decision-making step is constant. Context update works exactly the same as for the decision function.

Thus, you cannot generate an HTTP response directly from a function related to :post! .

Key related function :post! , can return something and something will be combined in context.

Context updating works exactly the same as for decision functions.

Then the handler function can subsequently pull something out of context and use it to form an HTTP response. It is possible that any of the handler functions associated with these keys could be executed later:: :handle-ok :handle-created :handle-no-content :handle-see-other :handle-multiple-representations

This decision graph determines which handler will execute.

It's probably best to simply reply with a location header pointing to your newly created resource and without a body, but here is one example of creating a response with a JSON body and status 201.

 (POST "/foo" [] (resource :allowed-methods [:post] :available-media-types ["application/json"] :handle-created {:created "ok"})) 

Attempt:

 curl -X POST "localhost/foo" {"created":"ok"} 

You can see which JSON library library is using in its project.clj file. If you want to generate JSON strings yourself, you can do it like this:

 :handle-created (fn [ctx] (liberator.representation/ring-response {:status 201 :body "{created:\"ok\"}"})) 

Mentioned here

+3
source

This is how I do it - it seems to work, but I just started using Liberator, so there may be better or more correct ways to do this!

I think you need a handler created by the handle. For instance -

 (defresource shopping-calc :allowed-methods [:post] :available-media-types ["application/json"] :malformed? (fn [context] (let [params (get-in context [:request :params])] (or (empty? params) (is-malformed? params)))) :handle-malformed (fn [context] (let [params (get-in context [:request :params])] (generate-string (handle-malformed-calc params)))) :handle-created (fn [context] (let [params (get-in context [:request :params])] (generate-string (calculate-total params))))) 

and I have a handler created by a handler like this

 (defn calculate-total [params] {:total (calc params)}) 

I also use ring / json middleware and in my dev environment, add a liberator trace facility. The Liberator tracking tool is very convenient as it adds headers to the answer, which shows the decision points for Liberator. Thus, for you, the problem would probably show that Liberator used a default handler that simply returns the headers. To return your own json, you need to define a handler.

Note that I do not use this post! method. This is due to the fact that in this example, I actually do not create some new object / element, for example, adding an entry to some store. If you do this, then what you could do is use a post! to add a record and create a specific descriptor, then to get a new record (possibly with other new fields, such as record identifier or timestamp, etc.) and return it.

I use: malformed? and handle incorrectly to perform basic error checking. If: wrong? returns true, the header with the wrong expression is called, which returns the error status and the error message in the json package. I find this helps a lot so that your errors also return to json so that you can process everything on the client side sequentially.

The following are the definitions of my handlers and middleware. Please note: since I serve both applications and api routes, they are a bit more complicated because I want some middleware to be applied to some routes and other middleware applied to others. There is also a small error in the ring / ring-default settings, which after fixing will change things, because at the moment I can not use the site-api middleware to migrate by default. Check out the middleware for transferring the trace.

 (def app (if (env :dev) (routes (-> api-routes (wrap-reload) (wrap-routes wrap-json-params) (wrap-routes wrap-defaults api-defaults) (wrap-routes wrap-trace :header :ui)) (-> app-routes (wrap-routes wrap-error-page) (wrap-routes wrap-exceptions))) (routes (-> api-routes (wrap-routes wrap-json-params) (wrap-routes wrap-defaults api-defaults)) app-routes))) 
+1
source

The 201 created code is used to return links to a newly created resource in the body along with the location header. If you want to return the newly created resource to the body, you must use 200 ok . By default , Liberator will end at 204 no-content after POST. Do you need to install :respond-with-entity? true :respond-with-entity? true

The resource definition will look like this:

 (defresource poster [] :allowed-methods [:post :options] :available-media-types ["application/json"] :malformed? (fn [ctx] [false {::resource (parse-json (get-in ctx [:request :body]))}]) :post! (fn [ctx] (persist (::resource ctx))) :handle-ok (fn [ctx] (generate-json (::resource ctx)))) 

I recommend Ceshire to parse and generate JSON.

+1
source

Source: https://habr.com/ru/post/1211756/


All Articles