Fork me on GitHub
#yada
<
2017-05-24
>
Rachel Westmacott13:05:41

is it normal/required in yada (or HTTP) for the response for an endpoint and the error messages for an endpoint to have the same content-type?

malcolmsparks13:05:23

Hmm. Well, yada renegotiates the content type against a (currently fixed) set of error content types. So no.

Rachel Westmacott14:05:25

so if I say that my endpoint is eg “text/csv” I can return other types of errors?

malcolmsparks14:05:18

Or rather, see the existing set in handler.clj

malcolmsparks14:05:25

Needs work from me

malcolmsparks14:05:36

To make it more configurable

Rachel Westmacott14:05:36

ah, is that in case of exceptions?

Rachel Westmacott14:05:07

I’m manually checking some things and then returning a {:status 400 :body ...}

malcolmsparks14:05:16

Yes. But you can replace the exception interceptor chain with your own

malcolmsparks14:05:33

Ah. Then you must also set Content-Type in your reponse. Or better still, use yada's conneg functions to neg one

Rachel Westmacott14:05:59

got that working, thank you!

borkdude15:05:34

@peterwestmacott The way I did it is a bit hacky, but works as well:

(intern 'yada.handler 'error-representations
        (ys/representation-seq
         (ys/representation-set-coercer
          [{:media-type #{"your/content-type"
                          "application/transit+json"
                          "application/json;pretty=true;q=0.96"
                          "text/plain;q=0.9"
                          "text/html;q=0.8"
                          "application/edn;q=0.6"
                          "application/edn;pretty=true;q=0.5"}
            :charset charset/platform-charsets}])))
Then override/define defmethod render-error “your/content-type”.

borkdude15:05:51

But responding an error with text/csv is a bit weird maybe

jonathanj15:05:51

Has anyone explored the idea of avoiding side-effect-y/mutate-y code in the method handler?

jonathanj15:05:25

The phonebook example, for example, does (db/add-entry db ...) somewhere in the :post handler.

dominicm15:05:19

@jonathanj where would you do it?

jonathanj15:05:45

I haven’t really thought about this super hard, so don’t presume I have anything resembling a good idea. 😉

jonathanj15:05:55

Well, somewhere else.

jonathanj15:05:29

If the handler returns data that describes what it expects to happen, something else could take that and actually do the work.

dominicm15:05:45

ah, I see. :thinking_face:

jonathanj15:05:00

[:add-entry {:name "Bob" :number "+1234"}] or some such thing.

dominicm15:05:06

I think you'd be hard pressed to find such a DSL that applied to every domain.

borkdude15:05:08

Re-frame on the server, I knew it 😉

dominicm15:05:15

But, you could ^^ yeah, essentially this.

jonathanj15:05:18

@borkdude That’s basically where the idea stemmed from.

jonathanj15:05:29

Except it’s redux, not reframe because I’ve never used reframe.

dominicm15:05:37

@jonathanj you might be interested in looking at event sourcing as a pattern 🙂

jonathanj15:05:41

A speed bump I ran into was what if you need to fetch something from the database?

jonathanj15:05:33

If there was a function that was handed the request and returned some kind of query/selector data that the handler was called with (eventually) that sort of approaches a solution.

jonathanj15:05:11

Kind of resembles om.next’s approach, I suppose.

borkdude15:05:41

@jonathanj I’m not entirely sure of your problem, but isn’t Manifold deferred something you could utilize here?

jonathanj15:05:46

Testing something like this and avoiding leaking all manner of business logic into HTTP handlers (that you may forget to do somewhere else) seems a lot easier.

jonathanj15:05:32

I’m not sure how manifold fits in here, @borkdude. Sorry if I’m being daft.

borkdude15:05:50

Maybe you could explain the flow of your request/response some more

jonathanj15:05:07

Have you seen om.next’s interfaces?

jonathanj15:05:14

Okay, well when you implement your component you can implement an IQuery interface that is called (by om.next’s internal machinery) and should return a piece of data that describes your query (with some kind of datalog-ish looking syntax), internally it gives the query to something (you specified elsewhere), and eventually the data is passed to your component’s render function.

jonathanj15:05:28

It was just a thought that popped up in my head, in terms of: HTTP request -> handler declares what data it would like to receive -> something realises that query -> your HTTP handler is called with that data -> return some data that describes what the handler intends to happen -> something realises that

borkdude15:05:11

HTTP handler = resource in Yada’s terms. Resource declares what data it would like to receive. This depends on the request. It can be realized anywhere using an interceptor?

jonathanj15:05:37

Hmm, unfortunately the interceptors portion of the manual seems quite incomplete.

borkdude15:05:00

An interceptor is just a function from context to context. You can insert them anywhere into an existing chain.

jonathanj15:05:31

What can an interceptor return?

jonathanj15:05:57

In particular, how do you spell “eventually” with interceptors?

borkdude15:05:58

E.g. I made this interceptor to manipulate the Schema to allow an extra parameter:

(defn allow-response-filter-in-schema
  [ctx]
  (if (rb/body-schema ctx)
    (update-in ctx [:resource :methods
                    (:method ctx) :parameters :body]
               (fn [schema]
                 (if (map? schema)
                   (assoc schema
                          (s/optional-key :response/filter)
                          s/Any)
                   schema)))
    ctx))

borkdude15:05:38

And I inserted it like this:

(insert-interceptor
         i/process-request-body
         allow-response-filter-in-schema)

borkdude15:05:44

Don’t know if this is helpful, but just to illustrate interceptors.

jonathanj15:05:00

Definitely gives me something to think about, thanks.