Fork me on GitHub
#clojure-uk
<
2018-01-24
>
thomas08:01:23

moin moin morning

otfrom08:01:52

I love Amsterdam, but the last time I was there Amsterdam inside Singel was just made of hassle and stag/hen parties

thomas08:01:17

yes, that is a problem in Amsterdam.

danm09:01:04

My wife went there for a conference and said it was lovely once she got outside the 'tourist' zones

yogidevbear09:01:35

Morning :wind_blowing_face:

thomas10:01:41

looks like I am going this Friday to Amsterdam to see a customer.

maleghast11:01:10

Hello All - Morning, morning! 😄

maleghast11:01:48

I liked Amsterdam when I tried it out, but it’s been over 10 years… My wife has visited the city many times and has a particular love for the place.

maleghast11:01:21

I reckon that it gets more than its share of stag / hen action, but just staying out of the Red Light negates 80% of that action, I reckon…

maleghast11:01:28

(I have a friend who’s been living there for a long time who I recently re-acquainted myself with as he was in Manila on business a couple of times while we were out there and he’s very positive about the “local” scene, i.e. what’s there that’s not for the tourists…)

thomas12:01:23

I think Amsterdam is trying to get less stag/hen parties these days and the red-light district is a lot smaller these days as well.

maleghast12:01:32

@thomas - Yeah, I think that’s been a conscious move by the City, from what I hear. It’s always going to have that underbelly and there are always going to be people that visit it for that, but it has so much more to it as a place, and I was only there for 3 nights! (I was with a friend for her birthday and coffee shops were not an option as she was vehemently anti-drug!)

maleghast12:01:07

Anyone got a recommendation for creating v5 UUIDs in ClojureScript?

maleghast12:01:21

(SHA-1 + namespaced)

guy12:01:09

Not sure if this is still maintained but i’ve seen this before https://github.com/danlentz/clj-uuid

maleghast12:01:12

(I have just realised that I need to create them on both sides, client and server, and would prefer to be able to create v5 ones - will fall back to something else if necessary)

maleghast12:01:45

@guy - Yeah, I am totally hoping to use that on the server / Clojure side

guy12:01:57

oh sorry cljs i missread

maleghast12:01:27

and I could__ do an XHR call for any UUIDs I need from the server, but having a client-side equivalent library would be fab

maleghast12:01:48

If there isn’t one I will make an endpoint in my API to fetch one when needed and use that 🙂

mccraigmccraig13:01:20

@maleghast we use v1 and v5 UUIDs, but i never found a js lib which could produce them, so we generate all v1 and v5 UUIDs server-side

maleghast13:01:47

Thanks @mccraigmccraig - I am assuming that I need to do the same and I am debugging my utility endpoint that returns a UUID now…

maleghast13:01:13

I do have another Q though… Why does my function return exactly the same result for every v5 UUID..?

mccraigmccraig13:01:33

uh - what is your function doing ?

maleghast13:01:49

(uuid/v5 uuid/+namespace-url+ uuid-namespace)

maleghast13:01:03

where uuid-namespace is a configured value

mccraigmccraig13:01:13

v5 UUIDs are deterministic

mccraigmccraig13:01:17

same inputs, same output

mccraigmccraig13:01:41

it's a way of taking a random (v1, v4) UUID and namespacing it

maleghast13:01:49

I had totally missed that.

maleghast13:01:02

So, I need to pass a v1 UUID in?

mccraigmccraig13:01:46

v1 UUIDs are time-based - if you use cassandra, and maybe other dbs, they will sort timewise... they aren't very random though - it's got your MAC address and timestamp and a counter in

mccraigmccraig13:01:58

v4 UUIDs are almost all random bits

mccraigmccraig13:01:10

so depends on what you want to use the uuid for

mccraigmccraig13:01:18

e.g. we use v4 UUIDs for auth tokens and v1 UUIDs for message identifiers

maleghast13:01:27

v1 is going to be fine - I just want reliably unique ids for data

maleghast13:01:47

and I don’t want to use an incrementing integer or similar

mccraigmccraig13:01:52

but you can generate v4 uuids in js...

mccraigmccraig13:01:14

as long as you don't care about sort order or namespacing, that will be fine for unique ids

maleghast13:01:36

Well, I am going to want v5s for auth tokens later on, so learning how to do this is going to be useful anyway, but that might be a better approach for this particular use-case.

mccraigmccraig13:01:10

why do you want v5s for auth tokens ?

maleghast13:01:29

I thought v5 allows UUIDs to be namespaced, so you can have UUIDs that are valid only in a particular context..?

maleghast13:01:47

It’s entirely possible that I have misunderstood them more than even I had considered

maleghast13:01:50

… Yeah, I have misunderstood them completely it would appear… (I did some re-reading)

maleghast13:01:43

v4 UUIDs would be fine for what I want, in fact v1 UUIDs would almost certainly be fine for the specific thing I am doing right_now__

maleghast13:01:13

I don’t need randomness, there is no security aspect to the UUIDs I need for what I am dealing with right now, all I NEED is uniqueness and the time dimension of v1 UUIDs will give me that, job done.

maleghast13:01:25

Don’t know what I was thinking…

maleghast14:01:41

Does yada cache responses by default..?

maleghast14:01:04

I have an endpoint that is returning the same result over and over, but when I run the underlying function (that creates the response for the Yada Resource) in my REPL I get what I expect, a different result time after time.

maleghast14:01:14

(asked in #yada as well)

maleghast14:01:28

(but this channel is a little more “busy” 😉 )

mccraigmccraig14:01:08

yada does not cache responses @maleghast

mccraigmccraig14:01:24

make sure that you are not executing the code to define the response when you declare the response - if you give yada a static value as a response (rather than a fn) it will repeatedly return that

maleghast14:01:33

I am doing this:

:methods
    {:get
     {:response
      (create-uuid)}}

maleghast14:01:42

in the resource definition

maleghast14:01:29

Should I wrap that call to my uuid function in an anonymous function..?

maleghast14:01:27

So, like this:

:methods
    {:get
     {:response
      (fn [] (create-uuid))}}
instead

maleghast14:01:14

Yep! Totally it. I really am n00b-ing it up today… facepalm

shan14:01:22

would just having create-uuid work? (without the parens)

maleghast14:01:07

@shan - I don’t know… Want me to try..?

maleghast14:01:46

@shan - I tried it, it does not work, in fact I get this error:

{:response
 {:headers {},
  :vary #{},
  :produces
  {:media-type
   {:name "application/edn",
    :type "application",
    :subtype "edn",
    :parameters {},
    :quality 1.0},
   :charset {:alias "UTF-8", :quality 1.0}}},
 :resource yada.resource.Resource,
 :error #error {
 :cause "Wrong number of args (1) passed to: admin/create-uuid"
 :via
 [{:type clojure.lang.ArityException
   :message "Wrong number of args (1) passed to: admin/create-uuid"
   :at [clojure.lang.AFn throwArity "AFn.java" 429]}]
 :trace
 [[clojure.lang.AFn throwArity "AFn.java" 429]
  [clojure.lang.AFn invoke "AFn.java" 32]
  [yada.methods$eval24714$fn__24715 invoke "methods.clj" 153]
  [yada.methods$eval24683$fn__24684$G__24674__24691 invoke "methods.clj" 138]
  [yada.methods$eval24723$fn__24730$fn__24739 invoke "methods.clj" 192]
  [manifold.deferred$eval18026$chain___18047 invoke "deferred.clj" 863]
  [clojure.lang.AFn applyToHelper "AFn.java" 165]
  [clojure.lang.RestFn applyTo "RestFn.java" 132]
  [clojure.core$apply invokeStatic "core.clj" 661]
  [clojure.core$apply invoke "core.clj" 652]
  [manifold.deferred$eval18026$chain___18047$fn__18051 invoke "deferred.clj" 889]
  [manifold.deferred.Listener onSuccess "deferred.clj" 219]
  [manifold.deferred.Deferred$fn__17825 invoke "deferred.clj" 378]
  [clojure.lang.AFn run "AFn.java" 22]
  [io.aleph.dirigiste.Executor$Worker$1 run "Executor.java" 62]
  [manifold.executor$thread_factory$reify__17228$f__17229 invoke "executor.clj" 44]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 745]]}}

maleghast14:01:31

I admit that I am not completely clear as to why this happens, but having the parens makes it work, so I will leave them in for now and worry about the “why?” in a little while…

mccraigmccraig15:01:28

probably yada is passing the request context to the create-uuid fn @maleghast

mccraigmccraig15:01:48

a typical :response fn looks like

(fn [ctx]
         (case (:method ctx)
           :options (yada.context/->Response)
           :get (generate-string api-version)))

shan15:01:41

I wonder why the (fn [] ... version works

guy15:01:43

i thought the same thing 😅

maleghast15:01:45

I have this:

(yada/resource
   {:id :foundation.resources/fetch-uuid
    :description "API call for getting v5 UUIDs generated on the server and returned to the front end."
    :parameters {}
    :produces [{:media-type #{"application/edn"}
                :charset "UTF-8"}]
    :methods
    {:get
     {:response
      (fn [] (create-uuid))}}})
so the type of request is filtered before the response is handled / created

maleghast15:01:29

but I imagine__ that it’s synonymous

maleghast15:01:46

(I copied my approach to Yada resources from the current version of juxt/edge)

thomas15:01:37

that sounds very reasonable @maleghast

thomas15:01:03

as that is the purpose of Edge... a working example of Yada.

maleghast15:01:31

Yeah, absolutely

maleghast16:01:13

If I have a function that is talking to the server from ClojureScript, how do I block on the response..?

mccraigmccraig16:01:10

@maleghast you don't block - it's javascript!

maleghast16:01:26

Ok, so I want to fetch a UUID from the server and bind it to a local symbol inside a let binding at the top of a function containing a component.

maleghast16:01:15

At the moment the function works (if I println the function I get a UUID from the server), but the local val in the let is nil

maleghast16:01:40

I assume that this means the function has not returned from the server fast enough to resolve the value

maleghast16:01:48

So how do I “wait” for the value?

maleghast16:01:21

Here’s my fetch:

(defn fetch-uuid
  "Function to retrieve a new UUID"
  []
  (let [response (atom nil)]
    (doto
      (new js/XMLHttpRequest)
      (.open "GET" "/admin/util/uuid")
      (.setRequestHeader "Accept" "application/edn")
      (.addEventListener
       "load"
       (fn [evt]
         (reset! response (read-string evt.currentTarget.responseText))))
      (.send))
    (when @response
     @response)))

mccraigmccraig16:01:17

it's async land @maleghast - rather than wait, you schedule something to happen when the value arrives. i tend to prefer promises (promesa is a good lib) and many people use core.async

maleghast16:01:36

(I know I can do the UUIDs client-side based on earlier conversation, but I want to understand how to do this anyway)

maleghast16:01:45

Ah ok, so if the above were wrapped in a promise, I could pass the promise back to my component function and whenever the data was present the value would be resolved..?

mccraigmccraig16:01:47

not really - you can schedule a then operation to be called when the value resolves (promises), or use a go block to do something when your response channel gets an item

mccraigmccraig16:01:40

if you are using reagent you would use the then or go to update your state somewhere... with re-frame you would dispatch an event to update your state

maleghast16:01:19

So, if I make the request and then updated the app-state the component would only render when the change to app-state happens?

maleghast16:01:50

ok, that I can do.

mccraigmccraig16:01:00

are you using re-frame or reagent ?

maleghast16:01:06

reagent at the moment

maleghast16:01:13

I am prototyping

maleghast16:01:36

it may end up being re-frame in the near future…

maleghast16:01:50

@mccraigmccraig - I am going to read that in a bit; for now your advice has got me moving again so I want to see how much more progress I can make before I stop for dinner, but I will__ read that article and I am definitely open to adopting re-frame.

mccraigmccraig16:01:08

in summary - if you aren't expecting your app to ever be anything more than simple, stick with reagent. if it's going to grow and grow, do your future self a favour and choose something else. i've been happy with re-frame, but there seem to be a couple of other reagent based thingies now too

maleghast17:01:52

Sounds like good advice to me. If you’re having good experiences / results from re-frame I don’t imagine I will look any further. I will wait for a lot of people to be “pushing” something else before I think about anything different 🙂

dominicm17:01:12

For our small/medium front-end, I've found it more of a burden to work with event passing. Swapping into an atom was simpler, although tests were somewhat easier with events.

maleghast18:01:41

I can see that there are trade-offs, for sure…

maleghast18:01:59

Can anyone point me at a user-friendly / easy guide to handling forms in Reagent..?

maleghast18:01:39

I want to swap the data into the app-state and send the data to the back-end for persistence, by stepping in and preventDefault-ing the submit event.

maleghast18:01:07

All I can find by Google-Fu failure is stuff from 2-3 years ago, and I am hoping__ that it’s gotten simpler…

dominicm18:01:47

I do something a bit different for this common case

dominicm18:01:21

In onSubmit use this: https://github.com/ccfontes/form-juice &preventDefault

maleghast18:01:47

hold on a sec…

dominicm18:01:28

I do it slightly differently, as I run the function in the onSubmit for the form, but it's the same effect.

dominicm18:01:25

Basically it reads the form as data (DOM state), rather than re-rendering for every attempt at input. It has limitations, but it's very easy.

maleghast18:01:21

Looks as though it will work very nicely for what I want / need 🙂 Thanks 🙂

dominicm18:01:26

It's Saved me a bit of work :)

maleghast18:01:48

Yeah, I can imagine!

maleghast18:01:45

So, if I just hand the “e” of the event to a function that then grabs the form data by using the “squeeze” function in the namespace provided..?

maleghast18:01:45

OMG that is MAGIC!

maleghast18:01:52

❤️ ❤️ ❤️

dominicm18:01:12

You might be able to simplify by accepting formencoded on the server for submission, and not doing the funky conversion to a cljs map.

dominicm18:01:34

Best of all, this is a fairly reusable function :)