yada

kwladyka 2019-01-18T17:01:45.044100Z

@borkdude hey, we were talk about exceptions on web page in yada before somewhere. So how do you deal with it https://clojurians.slack.com/archives/C0702A7SB/p1547229018025500 ?

kwladyka 2019-01-18T17:02:00.044700Z

It is happening for me for all types of “errors”

borkdude 2019-01-18T17:02:41.045300Z

this is basically what I do: https://gist.github.com/borkdude/441379ec59d8da7f72348453ee15f32a note: this code is almost 2 years old and yada might have better ways right now

kwladyka 2019-01-18T17:03:24.045700Z

But is it only for definend content-type?

borkdude 2019-01-18T17:07:49.046400Z

?

malcolmsparks 2019-01-18T17:08:38.047100Z

You can add :show-stack-traces? true to your yada resource map

kwladyka 2019-01-18T17:08:46.047400Z

I don’t see in this code option to turn off it for all errors. I see you use defmethod render-error "text/plain"

malcolmsparks 2019-01-18T17:08:48.047600Z

Or of course, :show-stack-traces? false

kwladyka 2019-01-18T17:09:01.048100Z

@malcolmsparks woo how can I know about that?

borkdude 2019-01-18T17:09:02.048200Z

I turn off stacktraces in prod.

malcolmsparks 2019-01-18T17:09:34.048900Z

all the schema is defined in yada.schema. It's a single ns that defines all possible things you can have in a yada/resource

malcolmsparks 2019-01-18T17:09:50.049300Z

there should definitely be a documentation chapter explaining it all

kwladyka 2019-01-18T17:10:08.050Z

Maybe I miss something big, but I don’t see it

malcolmsparks 2019-01-18T17:10:09.050100Z

but it's good to know where the actual source is because documentation can be out of date

borkdude 2019-01-18T17:11:11.051200Z

that was added 23rd of May 2017, I probably wrote this code before it

malcolmsparks 2019-01-18T17:11:11.051300Z

if you want to do something to multiple resources at once, the standard answer is to clojure.walk/postwalk your resources

malcolmsparks 2019-01-18T17:11:32.052Z

you can add some namespaced entries in your resources if you need to filter them, etc.

borkdude 2019-01-18T17:11:44.052300Z

@malcolmsparks we have a common resource model that we merge with overridable data per resource, that also works

malcolmsparks 2019-01-18T17:11:52.052500Z

yes, that too - it's data

kwladyka 2019-01-18T17:12:19.053Z

So I have to add this to all resource definition? No way to set it when start yada?

malcolmsparks 2019-01-18T17:12:48.053600Z

no - everything is at a resource level - this is intentional

malcolmsparks 2019-01-18T17:12:59.053900Z

sometimes you want different policies for different resources

malcolmsparks 2019-01-18T17:13:21.054400Z

and yada discourages putting policies on the global or 'route prefix' level

malcolmsparks 2019-01-18T17:13:53.055100Z

This is partly to make resources self-contained (which can help when testing them individually).

malcolmsparks 2019-01-18T17:14:29.055700Z

It's also about making it easier to reason about resources on their own

kwladyka 2019-01-18T17:15:17.056600Z

sure I understand it, but this one I would like to see as global conf 🙂 So I will ended up with function wrapper to create resource without stacktrace like everybody 😉

kwladyka 2019-01-18T17:15:25.056800Z

But I understand the concept

borkdude 2019-01-18T17:15:45.057300Z

@kwladyka like I said, you can make a “global conf” by using a global map with your default and then merge differences in per resource

kwladyka 2019-01-18T17:16:06.057900Z

Do you have other cool tips like https://github.com/juxt/yada/blob/master/src/yada/schema.clj for me? 🙂

borkdude 2019-01-18T17:16:07.058100Z

@kwladyka in our global resource map there’s for example auth stuff

malcolmsparks 2019-01-18T17:17:21.059600Z

I've begun to work more actively on yada lately, and I'm trying to add documentation to each feature as I commit. But I do have some outstanding documentation to author.

malcolmsparks 2019-01-18T17:17:33.059900Z

One good general tip is to read the source code.

borkdude 2019-01-18T17:17:52.060600Z

Also the Edge app is a good example

malcolmsparks 2019-01-18T17:18:31.062Z

Once you understand how yada works it's not that frightening. The overall design is quite simple once you understand it - it's a series of functions that are called in a sequence, acting on a single map (called the yada context)

malcolmsparks 2019-01-18T17:18:42.062400Z

once the context is fully built, the response is ready to be returned

malcolmsparks 2019-01-18T17:19:17.063500Z

The trick is that there is enough data in the yada context to figure out things like content negotiation, conditional responses and so on.

kwladyka 2019-01-18T17:19:21.063600Z

agree, as a feedback (please think about it positive! I have good intention!) in my feeling doc is too long without right value. It could be 20% of that length with the same value or better. I mean there is a lot of content which doesn’t give me any improvement.

malcolmsparks 2019-01-18T17:19:54.064300Z

thanks for the feedback

malcolmsparks 2019-01-18T17:20:16.064900Z

we are working on some Edge tutorials which may be easier to follow

kwladyka 2019-01-18T17:20:50.065400Z

I understand, it is in progress

borkdude 2019-01-18T17:21:41.066100Z

@malcolmsparks have you thought about swapping bidi for e.g. reitit to make it work with spec?

kwladyka 2019-01-18T17:21:45.066200Z

But I really like idea about yada and I am full of hope 🙂

malcolmsparks 2019-01-18T17:22:59.067500Z

@borkdude I have looked at reitit and really like it - however, it does have some constraints such as segmenting on / only.

malcolmsparks 2019-01-18T17:23:22.068200Z

There is some integration between bidi and yada to makes URI forming 'easier' which I dislike

borkdude 2019-01-18T17:24:00.068400Z

you dislike easier?

kwladyka 2019-01-18T17:29:20.069600Z

@borkdude Why reitit use [reitit.coercion.spec] instead of core one? Sorry I am asking, but I don’t know this library. Is it possible to use it with [clojure.spec.alpha :as s]?

borkdude 2019-01-18T17:29:40.069900Z

I don’t know reitit at all.

kwladyka 2019-01-18T17:29:58.070100Z

oh ok 🙂

malcolmsparks 2019-01-18T17:42:30.072700Z

@borkdude there are alternative ways of doing bidi url forming without going via the yada ctx, and I think the use of the yada ctx is a bit of an anti-pattern. I think bidi and yada should work more independently. I don't think there's any reason today why yada and reitit can't work well together. It's not really a case of 'swapping' bidi for reitit, just to support both and give the user the choice.

malcolmsparks 2019-01-18T17:42:48.073200Z

Edge could have some examples where reitit is used instead of bidi.

borkdude 2019-01-18T17:43:16.074Z

yeah. but yada also is coupled with schema right now, right?

borkdude 2019-01-18T17:43:27.074400Z

you can just turn that off by not using it I guess

borkdude 2019-01-18T17:43:40.075Z

but then the schema/spec is not part of the resource anymore

malcolmsparks 2019-01-18T17:44:35.076Z

I was thinking of swapping out schema for clojure.spec when clojure.spec first came out. But I have since reconsidered. Schema plays 2 roles in yada - the first is by checking the data given to yada resources. The second is for parameters and Swagger. I don't think clojure.spec is a good choice for either.

malcolmsparks 2019-01-18T17:45:41.077200Z

We could take schema out of yada, but then you'd lose the shorthands and they're quite handy. Not having coercions would make yada resources quite a bit more verbose.

borkdude 2019-01-18T17:45:56.077500Z

makes sense

malcolmsparks 2019-01-18T17:46:49.078500Z

I do think that the use of schema in yada parameters is a bit of a problem. I would prefer schema just be an internal thing really.

malcolmsparks 2019-01-18T17:49:11.081100Z

For parameters, I think that parameter validation (to produce 400 errors) is really a separate concern and not one that yada should be involved with. The declaration of parameters isn't part of the HTTP standards and was really driven by Swagger. I used to think it was a big advantage to have Swagger 'built-in' but now I think it would be fine if all the Swagger stuff were available as an extension and not part of yada core. That would reduce the dependencies and overall size of yada a lot.

malcolmsparks 2019-01-18T17:49:43.081700Z

(I still think parameters validation is important, but something where there should be more options rather than 'built-in')

kwladyka 2019-01-18T17:59:39.082Z

@malcolmsparks > I don’t think clojure.spec is a good choice for either. Why?

malcolmsparks 2019-01-18T18:02:57.083300Z

2. I don't think clojure.spec is designed for validation of web forms - there are more purpose-built libraries for that

kwladyka 2019-01-18T18:04:18.083700Z

Hmm I did exactly such library haha https://github.com/kwladyka/form-validator-cljs 😛

kwladyka 2019-01-18T18:04:31.084100Z

Form validator based on clojure spec

kwladyka 2019-01-18T18:04:46.084600Z

It seems to be fine, but maybe I miss something :thinking_face:

kwladyka 2019-01-18T18:05:32.085400Z

I really want to use the same code for validation on BE and FE.

dominicm 2019-01-18T18:06:15.086100Z

@kwladyka you should not run spec against data from the Internet until you have validated it.

dominicm 2019-01-18T18:07:28.088100Z

Additionally, if you want to spec that :password and :password-repeat are equal, you cannot put the error message on :password-repeat, only on the whole form.

kwladyka 2019-01-18T18:08:12.088300Z

Can you expand that?

kwladyka 2019-01-18T18:11:39.088600Z

It can be done, because you can recognise spec name (s/def ::foo/bar ...)

kwladyka 2019-01-18T18:11:48.088800Z

But fn for that purpose are probably better

kwladyka 2019-01-18T18:19:00.089Z

I mean I use spec + fn for not standard things and it works without any issue.

kwladyka 2019-01-18T18:19:35.089200Z

But the biggest advantage is I can use spec from BE on FE and be sure everything is consistent

kwladyka 2019-01-18T18:20:00.089400Z

Writing different code validation on FE and BE twice sounds bad for me

kwladyka 2019-01-18T18:21:11.089800Z

But if you can five me further input which will change my view it will be great!

kwladyka 2019-01-18T18:27:26.090400Z

But I agree spec needs support of fn for coercion

kwladyka 2019-01-18T18:27:45.090700Z

Or check things like “this username already exist”

kwladyka 2019-01-18T18:29:25.090800Z

But in practice you don’t send :password-repeat to BE, it is checking only on FE

kwladyka 2019-01-18T18:30:10.091Z

So you don’t want to have :passowrd-repeat in main spec anyway

kwladyka 2019-01-18T18:33:35.092200Z

@malcolmsparks {:show-stack-traces? false} how can I add this to for example HTTP 500? Do I have to define all HTTP responses for that purpose?

kwladyka 2019-01-18T18:33:49.092400Z

ok this was bad example probably

kwladyka 2019-01-18T18:34:11.092800Z

because 500 is about resources itself

kwladyka 2019-01-18T18:35:08.093300Z

Oh I see, if yada doesn’t find any resources it returns 204 without stacktrace

kwladyka 2019-01-18T18:35:50.093900Z

ok, never mind, I see how it works 👍

dominicm 2019-01-18T18:55:13.094100Z

It's a security risk, due to not being able to constrain the registry to only safe ones

kwladyka 2019-01-18T18:55:47.094300Z

What do you mean?

dominicm 2019-01-18T18:55:52.094500Z

I don't understand. How does this work?

kwladyka 2019-01-18T18:56:47.094700Z

While you can get reason of fail like [::form ::form-map ::password ::password-not-empty] you can get [::form ::form-map ::password-repeat ::password-not-empty] instead

kwladyka 2019-01-18T18:57:03.094900Z

so you know error is about password-repeat

kwladyka 2019-01-18T18:57:32.095100Z

all is about spec namig

kwladyka 2019-01-18T18:58:08.095300Z

code example?

dominicm 2019-01-18T18:58:30.095500Z

If a library contains a slow spec, for example, let's say it takes 1s per character. Then I can send a long string with that key, even though your endpoint doesn't accept it.

dominicm 2019-01-18T18:59:04.095700Z

E. G. {:ring/method "longstring"}, I can use that to easily dos your site

dominicm 2019-01-18T18:59:23.095900Z

Traditionally this happens with password hashing and not limiting string length

kwladyka 2019-01-18T18:59:44.096100Z

:via spec key is the point of get this info

dominicm 2019-01-18T19:00:02.096400Z

But my spec is on ::form

kwladyka 2019-01-18T19:01:39.096600Z

mmm but that is why spec are? To check lenght of that string before hashing

kwladyka 2019-01-18T19:02:38.096800Z

(ns form-validator-doc.spec
  (:require [cljs.spec.alpha :as s]
            [clojure.test.check.generators]))

(s/def ::email (s/and string? (partial re-matches #"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,63}$")))

(s/def ::password-not-empty not-empty)
(s/def ::password-length #(<= 6 (count %)))
(s/def ::password (s/and string? ::password-not-empty ::password-length))

(s/def ::form (s/keys :req-un [::email ::password]
                      :opt-un [::password-repeat]))

kwladyka 2019-01-18T19:03:25.097Z

if you create (s/def ::password-repeat ...) you can get for example [::form ::form-map ::password-repeat ::password-not-empty]

kwladyka 2019-01-18T19:04:14.097200Z

The same situation with Schema. App has to check it in right moment.

dominicm 2019-01-18T19:04:29.097400Z

But you are not validating that the fields are equal

kwladyka 2019-01-18T19:04:43.097600Z

it can be done in spec!

kwladyka 2019-01-18T19:04:54.097800Z

but i prefer fn

dominicm 2019-01-18T19:04:57.098Z

But the :via will not point at the right field

kwladyka 2019-01-18T19:05:15.098200Z

yes, then it is more complex. That is why I use spec + fn

kwladyka 2019-01-18T19:05:36.098400Z

Most of the validation can be done by spec

dominicm 2019-01-18T19:05:40.098600Z

But sure, you can do anything if you add extra validation, but then you have to put custom logic on top

dominicm 2019-01-18T19:06:09.098800Z

You lose the benefits of spec

kwladyka 2019-01-18T19:07:00.099Z

In that specific example not, because I don’t even want to have :password-repeat as part of my deep logic. It is not something what I will send to BE. It is only for UI purpose.

kwladyka 2019-01-18T19:07:35.099300Z

How would you do it better? spec + Schema? It sounds like doing work twice.

kwladyka 2019-01-18T19:08:47.099600Z

and issues about consistency

kwladyka 2019-01-18T19:08:56.099800Z

But I would love to know how you are doing that 🙂

dominicm 2019-01-18T19:09:11.100Z

I like vlad for forms

dominicm 2019-01-18T19:09:19.100200Z

The messages are good by default

kwladyka 2019-01-18T19:10:16.100400Z

lib looks like not maintained anymore

kwladyka 2019-01-18T19:10:52.100600Z

Anyway it is very interesting discussion! 🙂

kwladyka 2019-01-18T19:15:55.101100Z

I have to say after second try of yada I like it even more

👍 1
kwladyka 2019-01-18T19:16:11.101400Z

https://github.com/juxt/yada/blob/master/src/yada/schema.clj this is very helpful

dominicm 2019-01-18T19:18:58.102200Z

It's a finished library pretty much

dominicm 2019-01-18T19:19:24.102400Z

Schema use a restricted map of validations, spec uses an open map

kwladyka 2019-01-18T19:22:02.103300Z

interesting fact: after change liberator to yada I removed about half dependencies and about half code

kwladyka 2019-01-18T19:22:19.103500Z

*with the same effect

kwladyka 2019-01-18T19:24:04.103600Z

not sure what it means

borkdude 2019-01-18T19:29:32.104300Z

I had the same experience with an http-kit/ring based stack. I really like the batteries included of yada. I don’t mind the dependencies as long as it’s cohesive

borkdude 2019-01-18T19:30:51.104800Z

https://twitter.com/borkdude/status/857979807358910464

kwladyka 2019-01-18T19:31:16.105500Z

Do you know best practice example for yada + lacinia? Something what can inspire me or boost my process of learning how to glue things

borkdude 2019-01-18T19:31:46.106200Z

lacinia does have a lib for pedestal. I’m not sure what exactly it’s doing and I never used it in anger

kwladyka 2019-01-18T19:32:08.106800Z

it is just graphql library

borkdude 2019-01-18T19:32:12.106900Z

I did try lacinia once I must say, but we dropped it because the GraphQL standard was too narrow for us

kwladyka 2019-01-18T19:32:46.107400Z

My goal is to make GraphQL API with option to login by web browser + by token for integrations

kwladyka 2019-01-18T19:32:55.107700Z

There is a lot of decisions to make

borkdude 2019-01-18T19:33:16.108400Z

maybe Edge uses GraphQL

kwladyka 2019-01-18T19:33:45.109400Z

Generally when join to project this part is already done. But now I start something from 0 and I have to decide about everything. It is biggest challenge, than I thought 🙂

borkdude 2019-01-18T19:34:07.109700Z

the example I just posted uses lacinia + yada

kwladyka 2019-01-18T19:34:17.109900Z

cool, thx

kwladyka 2019-01-18T19:34:32.110300Z

Maybe I am not sure what is the best way for auth

borkdude 2019-01-18T19:35:06.111300Z

maybe auth should have its own endpoint?

kwladyka 2019-01-18T19:35:09.111400Z

I have no good idea how to do it using only GraphQL in secure way. I need this POST REST API method to login (get token based on email and password)

kwladyka 2019-01-18T19:35:47.112100Z

Maybe it should be like that or maybe it should be moved to GraphQL mutations, but then it start to confuse me how to implement it

kwladyka 2019-01-18T19:36:04.112400Z

yes, this is exactly how I am doing it now

kwladyka 2019-01-18T19:36:22.112800Z

but there is not a lot of people with who I can do brainstorm about that topic

kwladyka 2019-01-18T19:36:51.113300Z

actually I don’t know people personally with deep experience about it I think

kwladyka 2019-01-18T19:37:18.113900Z

system have REST + GraphQL, because they exited before etc.

borkdude 2019-01-18T19:37:21.114Z

maybe there’s a #graphql channel

kwladyka 2019-01-18T19:37:33.114400Z

yes, I know that channel

kwladyka 2019-01-18T19:38:14.115Z

but there is not a lot of system which based only on GraphQL without REST API I think, so people don’t have this experience

kwladyka 2019-01-18T19:38:23.115300Z

including me 😛

borkdude 2019-01-18T19:38:47.115700Z

Me neither 😉

kwladyka 2019-01-18T19:39:51.116600Z

And there are some resources like download PDF which are not GraphQL… ok it is off topic now 🙂

borkdude 2019-01-18T19:40:51.117700Z

GraphQL is designed for fetching nested data, to prevent unnecessary data sent from the sever, right? What stops you from making extra REST points together with it, that do not have that problem?

kwladyka 2019-01-18T19:40:53.117800Z

Do you know any place to talk about architecture of systems in that context?

kwladyka 2019-01-18T19:41:03.118200Z

It is something deeper than only GraphQL

kwladyka 2019-01-18T19:41:31.118600Z

yes, it could be done, but still there is a lot of decision to make. Like for example about auth.

kwladyka 2019-01-18T19:41:39.118800Z

It is about decisions 🙂

kwladyka 2019-01-18T19:42:40.119500Z

For example I started with sessions in Redis, but now I change concept to not use sessions at all

kwladyka 2019-01-18T19:43:20.120Z

instead I want to send token in each API call

kwladyka 2019-01-18T20:07:21.120800Z

How to run yada to use easy parameters from POST? curl -vs -H "Accept: application/json" --data 'query="{ game_by_id(id: "1237") { name designers { name }}}"' -X POST -i <http://localhost:3000/authentication> <- for example I want to read query parameter form POST method.

kwladyka 2019-01-18T20:07:38.121100Z

Should I use ring middlewares?

stijn 2019-01-18T22:02:02.122200Z

@kwladyka I can give you an example of yada + lacinia when I'm at the computer

stijn 2019-01-18T22:03:10.123900Z

We do authentication in http (session / token) and authorization in lacinia obviously

stijn 2019-01-18T22:04:19.124500Z

This might help you decide

kwladyka 2019-01-18T22:05:26.127Z

Thanks, example of code will definitely boost me

stijn 2019-01-18T22:05:27.127100Z

It's just much more convenient to do authentication outside of graphql because of all the web standards like cookies

stijn 2019-01-18T22:06:19.128200Z

But that also means you need at least one non graphql endpoint for login e.g.

stijn 2019-01-18T22:06:38.129Z

Gotta go, remind me later if I forget 😊

👍 1
kwladyka 2019-01-18T22:07:03.129500Z

Different topic: how do you make POST request (yada/response-for authentication :post "/authentication" {:body "{\"email\": \"<mailto:foo@example.com|foo@example.com>\", \"password\": \"qwaszx\"}"}) ? I am trying to use response-for but I can’t guess the right way 🙂

kwladyka 2019-01-18T22:08:18.129800Z

{:status 400,
 :headers {"content-length" "67", "content-type" "text/plain;charset=utf-8"},
 :body "No body present but body is expected for request.\r\n\r\n{:status 400}\n"}

kwladyka 2019-01-18T22:10:46.131300Z

curl --data 'email=foo@example.com&amp;password=qwaszx' -X POST -i <http://localhost:3000/authentication>                        Fri Jan 18 23:08:35 2019
HTTP/1.1 400 Bad Request
Content-Length: 129
Content-Type: text/plain;charset=utf-8
Server: Aleph/0.4.4
Connection: Keep-Alive
Date: Fri, 18 Jan 2019 22:09:11 GMT

Bad form fields

{:status 400,
 :error
 {:email missing-required-key,
  :password missing-required-key,
  nil disallowed-key}}
Also this issue. I assume I have to have ring middleware to make :parameteres work? But on the other hand it will be odd to add extra ring middleware on default yada things.

kwladyka 2019-01-18T22:28:25.132700Z

Seriously I have no idea how to use POST in yada after a few hours of trying 😕 I will appreciate example of code.

kwladyka 2019-01-18T22:37:53.134200Z

And for some reason it doesn’t work also with curl

:parameters {:form {:email String
                                 :password String}}
I was trying with :form and :body. It just doesn’ work.
{:status 400,
 :error
 {:email missing-required-key,
  :password missing-required-key,
  nil disallowed-key}}

kwladyka 2019-01-18T22:49:55.134500Z

Is it possible to use peridot with yada? How?

borkdude 2019-01-18T22:56:53.135Z

@kwladyka I have this in my tests:

(defn request [method url clj-body]
  {:method method
   :content-type "application/json"
   :accept "application/json"
   :as :json
   :url url
   :body (cheshire/encode clj-body)
   :throw-exceptions false})

(defmacro with-server
  "Runs resource in server and defines url for use in body"
  [url-bind resource &amp; body]
  `(with-level :level/off "yada.handler"
     (let [resource# ~resource
           vmodel# (vhosts-model [:* ["/api/foo" resource#]])
           listener# (y/listener vmodel#)
           port# (:port listener#)
           close# (:close listener#)
           ~url-bind (str "<http://localhost:>" port# "/api/foo")]
       ~@body
       (close#))))

(deftest schema-validation-error-test
  (er/define-error-renderers true)
  (with-server url
    (y/resource {:methods
                 {:post {:parameters {:body {:foo s/Str}}
                         :response (fn [ctx] {:a 1})
                         :produces #{"application/json"}
                         :consumes #{"application/json"}}}})
    (let [response (client/request
                    (request :post url {}))
          body (cheshire/decode (str (:body response)) true)]
      (is (= "missing-required-key" (-&gt; body :error :foo)))
      (is (= "Schema validation error" (-&gt; body :message))))))

kwladyka 2019-01-18T22:59:06.136400Z

Hmm I will try to translate it to (response-for ... ) yada fn

kwladyka 2019-01-18T22:59:29.136800Z

Do you have any idea why https://clojurians.slack.com/archives/C0702A7SB/p1547849446131300 ?

kwladyka 2019-01-18T22:59:54.137600Z

It looks like yada doesn’t see parameters

borkdude 2019-01-18T22:59:58.137700Z

I don’t use response-for, because it has some limitations, I can’t remember which, maybe to do with not all interceptors being present

borkdude 2019-01-18T23:00:41.138600Z

it’s been 2 years since I wrote this code. This code only tests some error logic. Most of my other API tests I run completely outside of yada, as integration tests

borkdude 2019-01-18T23:01:32.139100Z

the with-server macro starts a real aleph server, so it’s more like what you would normally see

borkdude 2019-01-18T23:03:23.139600Z

oh, I committed it to yada itself too: https://github.com/juxt/yada/blob/ba10db43e1a332f0bfd352cd8ea39f176190c4ff/src/yada/test.clj#L40

kwladyka 2019-01-18T23:09:49.140700Z

Ok I have to do small steps. Any idea why yada doesn’t see POST parameters at all?

kwladyka 2019-01-18T23:11:38.141100Z

(def authentication
  (build-resource
    {:id :authentication
     :consumes #{"application/x-www-form-urlencoded"}
     ; :access-control
     :methods {:post {:produces "application/json"
                      :parameters {:form {:email String
                                          :password String}}
                      :response (fn [{:keys [parameters] :as ctx}]
                                  (println (pr-str ctx))
                                  (println (pr-str parameters))
                                  ;(println (pr-str form))
                                  (let [{:keys [email password]} (:body parameters)]
                                    {:token "foo"
                                     :email email
                                     :password password}))}}}))
curl -d 'email=foo@example.com&amp;password=qwaszx' -X POST -i <http://localhost:3000/authentication>
HTTP/1.1 400 Bad Request
Content-Length: 129
Content-Type: text/plain;charset=utf-8
Server: Aleph/0.4.4
Connection: Keep-Alive
Date: Fri, 18 Jan 2019 23:11:04 GMT

Bad form fields

{:status 400,
 :error
 {:email missing-required-key,
  :password missing-required-key,
  nil disallowed-key}}

borkdude 2019-01-18T23:13:34.141500Z

yeah, you need get rid of the :form key in your schema

borkdude 2019-01-18T23:14:04.141800Z

I think… let me check

kwladyka 2019-01-18T23:14:05.141900Z

what should be there instead?

kwladyka 2019-01-18T23:14:39.142400Z

But the point is (println (pr-str ctx)) doesn’t show me any parameters

kwladyka 2019-01-18T23:14:58.143100Z

So something is wrong

borkdude 2019-01-18T23:15:02.143200Z

I have {:parameters {:body …}}

kwladyka 2019-01-18T23:15:09.143400Z

I was trying with that too

borkdude 2019-01-18T23:15:41.143800Z

oh I see you’re dealing with a form, let me check if I have such an example

kwladyka 2019-01-18T23:15:58.144300Z

Do you do something extra to let yada see POST parameters in request?

kwladyka 2019-01-18T23:16:45.144900Z

It doesn’t work for me with any example. I don’t have parameters in`ctx`

borkdude 2019-01-18T23:17:29.145300Z

can you try with a different consumes thing

borkdude 2019-01-18T23:17:47.145700Z

e.g. application/json and then post a JSON body

kwladyka 2019-01-18T23:17:50.145900Z

:parameters is {}

kwladyka 2019-01-18T23:18:00.146100Z

sure

kwladyka 2019-01-18T23:21:30.146300Z

the same with JSON

kwladyka 2019-01-18T23:21:41.146600Z

:parameters is {}

kwladyka 2019-01-18T23:23:14.146900Z

ok but :body should be ok now, let me check

kwladyka 2019-01-18T23:24:55.147100Z

ok it works good for JSON

kwladyka 2019-01-18T23:25:17.147600Z

but for POST application/x-www-form-urlencoded so typical form it doesn’t work

kwladyka 2019-01-18T23:27:33.148600Z

oh I see I have to have parameters in map to have them in ctx. So for POST it has to be different way than :form and :body hmm

kwladyka 2019-01-18T23:28:05.149100Z

But I have no idea how to set it then

kwladyka 2019-01-18T23:31:47.149600Z

hmm my guess is yada doesn’t know how to handle application/x-www-form-urlencoded

kwladyka 2019-01-18T23:37:37.151700Z

this is super weird:

curl -H "Content-Type: application/x-www-form-urlencoded" -X POST -i <http://localhost:3000/authentication>                  Sat Jan 19 00:35:45 2019
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Content-Length: 45
Content-Type: application/json
Server: Aleph/0.4.4
Connection: Keep-Alive
Date: Fri, 18 Jan 2019 23:36:06 GMT

{"token":"foo","email":null,"password":null}
curl -d 'email=foo@example.com&amp;password=qwaszx' -X POST -i <http://localhost:3000/authentication>                            Sat Jan 19 00:36:06 2019
HTTP/1.1 400 Bad Request
Content-Length: 129
Content-Type: text/plain;charset=utf-8
Server: Aleph/0.4.4
Connection: Keep-Alive
Date: Fri, 18 Jan 2019 23:36:56 GMT

Bad form fields

{:status 400,
 :error
 {:email missing-required-key,
  :password missing-required-key,
  nil disallowed-key}}
So when I send empty POST I don’t have any error, but when I send this fields I have error these keys are required

borkdude 2019-01-18T23:37:48.151900Z

it could be that yada doesn’t coerce the body against the schema in that content-type

kwladyka 2019-01-18T23:38:02.152300Z

for this setting

{:form {:email String
                                          :password String}}

borkdude 2019-01-18T23:38:07.152400Z

is that documented somewhere?

kwladyka 2019-01-18T23:38:15.152600Z

What exactly?

borkdude 2019-01-18T23:38:24.152800Z

form urlencoded post body

kwladyka 2019-01-18T23:38:45.153100Z

no but there are examples in the doc about POST

kwladyka 2019-01-18T23:38:51.153300Z

so it should work

borkdude 2019-01-18T23:38:56.153500Z

here’s a test: https://github.com/juxt/yada/blob/master/test/yada/form_test.clj

kwladyka 2019-01-18T23:40:35.154700Z

Looking on this test I don’t understand why it doesn’t work for me

borkdude 2019-01-18T23:40:38.154900Z

also, I can’t tell what your build-resource function returns. I’m off to bed. good luck 🙂

kwladyka 2019-01-18T23:43:01.155300Z

#yada.resource.Resource{:id :authentication,
                        :consumes [{:media-type #yada.media_type.MediaTypeMap{:name "application/x-www-form-urlencoded",
                                                                              :type "application",
                                                                              :subtype "x-www-form-urlencoded",
                                                                              :parameters {},
                                                                              :quality 1.0}}
                                   {:media-type #yada.media_type.MediaTypeMap{:name "application/json",
                                                                              :type "application",
                                                                              :subtype "json",
                                                                              :parameters {},
                                                                              :quality 1.0}}
                                   {:media-type #yada.media_type.MediaTypeMap{:name "application/edn",
                                                                              :type "application",
                                                                              :subtype "edn",
                                                                              :parameters {},
                                                                              :quality 1.0}}],
                        :methods {:post {:response #object[api.core$eval40522$fn__40524
                                                           0x41e5148f
                                                           "api.core$eval40522$fn__40524@41e5148f"],
                                         :produces [{:media-type #yada.media_type.MediaTypeMap{:name "application/json",
                                                                                               :type "application",
                                                                                               :subtype "json",
                                                                                               :parameters {},
                                                                                               :quality 1.0}}],
                                         :parameters {:form {:email java.lang.String, :password java.lang.String}}}},
                        :show-stack-traces? false}

kwladyka 2019-01-18T23:43:15.155600Z

I add there only :show-strack-traces? false

borkdude 2019-01-18T23:43:50.156100Z

try moving the consumes into the post map, like in the test

kwladyka 2019-01-18T23:44:22.156600Z

I was trying that one too

kwladyka 2019-01-18T23:46:33.157100Z

I give up. I am going sleep.

kwladyka 2019-01-18T23:46:40.157400Z

Thank you for help!