Fork me on GitHub
#yada
<
2019-01-20
>
kwladyka18:01:44

I found solution:

(-> (peridot/session (yada/handler core/graphql))
      (peridot/request "/graphql"
                       :content-type "application/graphql"
                       :request-method :post
                       :body "{ game_by_id(id: \"1237\") { name designers { name }}}")
      :response
      (deref)
      :body
      (bs/to-string)
      ;(edn/read-string)
      )

kwladyka18:01:30

I would like to make a handler to bidi routes handler instead of 1 resource, but this one I don’t know how to do

kwladyka18:01:39

(-> (peridot/session (as-handler core/handler))
      (peridot/request "/graphql"
                       :content-type "application/graphql"
                       :request-method :post
                       :body "{ game_by_id(id: \"1237\") { name designers { name }}}")
      :response
      (deref)
      :body
      (bs/to-string)
      ;(edn/read-string)
      )
^ yeah, this one work perfect with routing 🙂

kwladyka19:01:59

oh there is the same issue about :body like with response-for. It is nil.

kwladyka19:01:21

It looks like it is impossible to use :post with :body for testing with yada, it needs to be with aleph server.

borkdude19:01:56

that’s why I use this macro:

borkdude19:01:29

or I use integration testing, I think that’s even better if you want to test your service as an end consumer

kwladyka19:01:25

yeah, I will probably end with one of this solution

kwladyka19:01:45

Not sure why :body is nil, but maybe I don’t have to know 🙂

borkdude19:01:15

I think because the interceptor chain doesn’t have the right interceptor which does the schema thing

borkdude19:01:43

if I remember correctly, long time ago 🙂

kwladyka19:01:19

My main issues is probably about not understanding difference between ring vs aleph + manifold.

borkdude19:01:14

one difference is that aleph is designed for asynchronous requests

kwladyka19:01:25

that one I understand 🙂

kwladyka19:01:54

probably only that one haha 😉

kwladyka19:01:14

Do you understand why Manifold is needed? I understand general description, but I don’t really understand what it is about on deeper level. Why http/get can’t return normal string instead.

borkdude19:01:04

manifold gives an abstraction over futures/promises and whatnot. it’s used in yada to have asynchronous interceptors

kwladyka19:01:10

(ytest/with-aleph url (as-handler core/handler)
                    @(http/post (str url "/graphql")))
Syntax error (ExceptionInfo) compiling at (core_test.clj:88:3).
status: 404
How to use your macro? I always have 404. I was trying use core/handler on many ways but always 404

kwladyka19:01:26

(def handler
  ["/" [["authentication" authentication]
        ["graphql" graphql]
        [true not-found]]])

mccraigmccraig20:01:29

@kwladyka yada is async/non-blocking - http/get can't return a String, that would be a blocking API, so it has to return a Promise<String> - and yada is using Manifold's Deferred as its promise implementation

mccraigmccraig20:01:01

it uses Manifold's Deferred instead of clojure's standard promise because Manifold's Deferred supports completion callbacks and therefore the composition of promise values required to implement such things as interceptor chains (and most useful non-blocking computations with promises)

👍 5
mccraigmccraig20:01:38

it could also use another non-blocking abstraction, like core.async, but that would probably lead to a very different API

mccraigmccraig20:01:06

i much prefer promises over core.async for point values

kwladyka20:01:36

“so yada is async and in the same time use promises to be even more async and give better performance”

mccraigmccraig20:01:50

core.async is ok for streams of values - although Manifold's stream plays very nicely with Deferred so is my go to on clojure

mccraigmccraig20:01:32

@kwladyka yada uses promises as its principal async abstraction, rather than to improve performance

mccraigmccraig20:01:48

it's built on aleph, which is also Deferred based, so Deferred is the natural async abstraction for yada to use

kwladyka20:01:39

Hmm I am probably not enough experienced to imagine specific situations and benefits from it, but I understand general concept 🙂

kwladyka20:01:52

resource (new-classpath-resource "static") <- it is instead of real resource, so I am not sure about real use case

kwladyka20:01:03

and this test expect 404

kwladyka20:01:08

Which is what I get 🙂

kwladyka20:01:29

But I expect something different

kwladyka20:01:19

@borkdude I saw that test, but still I don’t know how to use it

borkdude20:01:26

@kwladyka Another example:

(with-aleph 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" (-> body :error :foo)))
      (is (= "Schema validation error" (-> body :message)))))

borkdude20:01:23

note that (y/resource ...) is my custom yada resource with error handler builtin

kwladyka20:01:26

What is client/request ?

borkdude20:01:01

that’s just a random HTTP client, shouldn’t matter. but in this case it’s clj-http: [clj-http.client :as client]

borkdude20:01:55

any http client should do, since it’s just a webserver running on some port

kwladyka20:01:44

Syntax error (ClassCastException) compiling at (core_test.clj:101:3).
class clojure.lang.PersistentArrayMap cannot be cast to class [B (clojure.lang.PersistentArrayMap is in unnamed module of loader 'app'; [B is in module java.base of loader 'bootstrap')
Jan 20, 2019 9:37:23 PM io.netty.util.concurrent.DefaultPromise notifyListener0
WARNING: An exception was thrown by aleph.netty$wrap_future$reify__15341.operationComplete()
java.lang.NoClassDefFoundError: Could not initialize class manifold.deferred.Deferred$fn__2465
	at manifold.deferred.Deferred.success(deferred.clj:398)
	at manifold.deferred$success_BANG_.invokeStatic(deferred.clj:243)
	at manifold.deferred$success_BANG_.invoke(deferred.clj:240)
	at aleph.netty$wrap_future$reify__15341.operationComplete(netty.clj:199)
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485)
	at io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:424)
	at io.netty.util.concurrent.DefaultPromise.setSuccess(DefaultPromise.java:94)
	at io.netty.util.concurrent.MultithreadEventExecutorGroup$1.operationComplete(MultithreadEventExecutorGroup.java:117)
	at io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:511)
	at io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:485)
	at io.netty.util.concurrent.DefaultPromise.access$000(DefaultPromise.java:33)
	at io.netty.util.concurrent.DefaultPromise$1.run(DefaultPromise.java:435)
	at io.netty.util.concurrent.GlobalEventExecutor$TaskRunner.run(GlobalEventExecutor.java:248)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:834)
It doesn’t work for me

kwladyka20:01:32

unless your’s y/resource is much different, than yada/resource

kwladyka20:01:47

(ytest/with-aleph url core/graphql
                    (-> @(http/post url #_(str url "/graphql") {:content-type "application/json"
                                                                :body "{\"email\":\"\",\"password\":\"qwaszx\"}"
                                                                :throw-exceptions false})
                        :body
                        (slurp)))
but this work!

kwladyka20:01:09

now I have to solve how to do it with full routing

kwladyka20:01:50

And that one is harder

kwladyka20:01:51

vmodel# (vhosts-model [:* ["/" resource#]]) - oh it is probably not designed for that purpose

borkdude20:01:58

@kwladyka my y/resource is a custom yada resource, that has our interceptor chain and error interceptor chain.

borkdude20:01:10

I’m testing the behavior of the error rendering in that example

kwladyka20:01:06

Am I understand it correctly ? This macro is designed to test only 1 resource. There is no way to use it with bidi routing?

borkdude20:01:08

no, it’s only designed to test a single resource. for full testing I’d use integration testing

👍 5
kwladyka20:01:23

Do you have Docker architecture? Kubernetes for testing or something similar? If yes what do you use for integration testing?

kwladyka20:01:39

Separate Clojure app only for testing? Bash?

borkdude20:01:00

We just test against a running instance with a database with real data in it (some would call it a staging environment)

borkdude20:01:30

but it could also be done with a script which spins up your app and then starts the tests in a different process

borkdude20:01:35

however you like it

kwladyka20:01:50

sure, just like to listen other people experience 🙂

kwladyka20:01:15

Personally I will choose probably Dockerfile + bash / Clojure tests for this project on staging environment kubernetes

borkdude20:01:21

I’m doing something similar with http://re-find.it which is just a SPA without a server, there I start a webserver that serves the static content, and then start some browser tests: https://github.com/borkdude/re-find.web/blob/master/test/re_find/web_test.clj#L152

borkdude20:01:10

Docker makes sense too. But for the app we’re using yada for, it’s very resource intensive in terms of memory and needs a lot of other services. That’s why we test it “live”

kwladyka20:01:28

“live” mean on production?

borkdude20:01:44

a staging environment that’s the version before it goes to production

kwladyka20:01:07

> That’s why we test it “live” Not sure what you mean here by “live”

borkdude20:01:30

I mean, it’s an environment that’s running 100% of the time and also used for QA

borkdude20:01:40

no, scripted of course

borkdude20:01:09

I just use clojure.test + clj-http for the API tests

borkdude20:01:31

and etaoin for browser tests

borkdude21:01:34

the browser is running in a Docker container

borkdude21:01:24

all of this isn’t directly related to whether you use yada, ring, pedestal, just choices you can make

kwladyka21:01:13

Yeah, I want to make SaaS label printer as my private project. I did the job about generate labels very fast. Making Ops, GraphQL, SaaS will take me probably a few months heh

kwladyka21:01:10

Probably I will choose similar way for testing