Fork me on GitHub
#beginners
<
2020-03-09
>
Santiago08:03:13

I’m using ring-jetty to build an API and I can’t respond with an integer in the body

java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #'ring.core.protocols/StreamableResponseBody found for class: java.lang.Integer
my ns
1 (ns myapi.core                                                                                      
    2   (:gen-class)                                                                                                
    3   (:require                                                                                                   
    4   ¦ [myapi.graphql :as graphql]                                                                     
    5   ¦ [myapi.db :as db]                                                                               
    6   ¦ [reitit.ring :as ring]                                                                                    
    7   ¦ [ring.adapter.jetty :as jetty]                                                                            
    8   ¦ [ring.middleware.reload :refer [wrap-reload]]                                                             
    9   ¦ [jsonista.core :as json]                                                                                  
   10   ¦ [ring.middleware.params :refer [wrap-params]]                                                             
   11   ¦ [ring.middleware.keyword-params :refer [wrap-keyword-params]]                                             
-- 12   ¦ [raven-clj.core :refer [capture]]                                                                         
-- 13   ¦ [raven-clj.ring :refer [wrap-sentry]]                                                                     
   14   ¦ [reitit.ring.coercion :as rrc]                                                                            
-- 15   ¦ [reitit.ring.middleware.exception :as exception]                                                          
   16   ¦ [schema.core :as s]                                                                                       
   17   ¦ [reitit.coercion.schema]))  
and the handler
(defn handler 
  [request]
  (let [params (:params request)
        customer-uuid (:customer_uuid params)
        debtor-uuid (:debtor_uuid params)
        limit (trust-limit customer-uuid 
                           (n-complete-invoices! customer-uuid debtor-uuid))]
    {:status 200 
     :body (int limit)}))
am I missing some middleware? responding with a string works

hindol08:03:32

Did you try making the :body a map? i.e. :body {:value (int limit)}?

Santiago08:03:28

java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #'ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap
maybe it needs to be encoded first into json somehow? it should be possible to respond to a GET request with just a number though, right?

Santiago08:03:56

yep works if I encode as JSON first 🙂

hindol08:03:52

Yeah, then that will be it. There should a middleware that does this.

ikitommi14:03:57

you could add muuntaja.middleware/wrap-format for example to get content negotiation and auto-encoding of response body

ikitommi14:03:31

if you use reitit, there are some examples which have basic set of middleware pre-configured, like: https://github.com/metosin/reitit/tree/master/examples/ring-swagger

👍 4
Shima09:03:09

Hi everyone I have a (probably very simple) question How can I use async/mult asynchronize?

Oskar12:03:44

Would the clojuredocs example answer that? https://clojuredocs.org/clojure.core.async/mult

erwin13:03:14

Do you mean async input or output? You can make the input channel a buffer (https://clojuredocs.org/clojure.core.async/buffer) which would buffer to everyone.

fabrao16:03:27

hello all, how to convert this {"service" {"lj" {}}, "setup" {"interval" "5"}} to hash-map with keyword?

delaguardo16:03:22

(defn keywordize [m]
  (if (map? m)
    (reduce-kv
     (fn [acc k v]
       (assoc acc (keyword k) (keywordize v)))
     {}
     m)
    m))

delaguardo16:03:30

something like this mb?

delaguardo17:03:07

or clojure.walk/keywordize-keys

delaguardo17:03:50

then

(defn keywordize [m]
  (cond
    (map? m)
    (reduce-kv
     (fn [acc k v]
       (assoc acc (keyword k) (keywordize v)))
     {}
     m)

    (instance? java.util.Hashtable m)
    (reduce
     (fn [acc k]
       (assoc acc (keyword k) (keywordize (.get m k))))
     {}
     (.keySet m))

    :else
    m))
this should work for Hashtable too

fabrao16:03:48

I tried with keywordize-keys but the result is only with one level, like service and setup , not with interval or lj

bfabry16:03:44

if you have a function like keywordize-keys:

(clojure.walk/postwalk #(if (map? %) (keywordize-keys %) %) m)

bfabry17:03:04

that will traverse down vectors and lists as well as maps, btw

delaguardo17:03:53

clojure.walk/keywordize-keys already does recursive walk

bfabry17:03:55

oh ignore me

bfabry17:03:07

yeah I didn't even know about that fn because it's not on the clojure cheat sheet

fabrao17:03:21

@delaguardo even if it is hashtable instead of hashmap?

delaguardo17:03:59

what is hashtable?

fabrao17:03:13

java.util.Hashtable

bfabry17:03:19

if you mean java.util.HashMap, then no, as that's not a map?

bfabry17:03:55

oh there is a Hashtable class. ditto

fabrao17:03:07

I did type in this interop java structure and it shows java.util.Hashtable

fabrao17:03:58

I thought it was the same, but keywordize only convert once

bfabry17:03:17

either way, clojure.walk walks clojure data structures. not java ones

delaguardo17:03:27

no, my versions of keywordize will not work for Hashtable

fabrao17:03:12

so, maybe hashtable -> hashmap convert?

bfabry17:03:23

it's going to be basically impossible to support all arbitrary java data structures. I would convert anything you get into a clojure data structure at the edge if possible

bfabry17:03:02

yes, converting the java Hashtable into a clojure map first would make keywordize-keys work

delaguardo17:03:12

this is one way, or you could implement clojure.lang.IPersistentMap interface for Hastable class

bfabry17:03:06

I would be wary of making a change that changes how clojure/java interact for the whole system in order to make something work in one case

ghadi17:03:39

let me guess.... AWS Lambda?

delaguardo17:03:07

I just figured that out (

fabrao17:03:11

this is what I did

(defn key-string->keyword [config]
  (into {} 
        (for [[k v] config]
          (do
            (if (= (type v) java.util.Hashtable)
              [(keyword k) (key-string->keyword v)]
              [(keyword k) v])))))

fabrao17:03:28

{"service" {"lj" {}}, "setup" {"interval" "5"}} -> {:service {:lj {}}, :setup {:interval 5}}

fabrao17:03:54

@ghadi no, it´s other system that resturns from configuration file a java.util.Hashtable

bfabry17:03:30

that'll work. fwiw I would've done:

(walk/keywordize-keys (walk/postwalk #(if (and (not (map? %)) (instance? java.util.Map %)) (into {} %) %) m))

fabrao17:03:24

@bfabry it didn´t work

bfabry17:03:48

weird. does for me

user=> (def m {"service" (java.util.Hashtable. {"lj" {}}), "setup" (java.util.Hashtable. {"interval" "5"})})
#'user/m
user=> (walk/keywordize-keys (walk/postwalk #(if (and (not (map? %)) (instance? java.util.Map %)) (into {} %) %) m))
{:service {:lj {}}, :setup {:interval "5"}}

fabrao17:03:07

Thanks for help

fabrao17:03:20

keywordize worked 2

Alex18:03:20

I have an api that expects a clojure.spec.alpha/coll-of string? however when there's a single value being sent it treats it as only a string and says it does not does not satisfy coll? What's the best way to ensure that a single value still gets treated as a single value collection?

hiredman18:03:54

Make it a single value collection

hiredman18:03:33

(a single value collection and a single value are not the same thing)

Dennis Tel22:03:52

hi! I’m just starting with clojure and looking for some resources/sites with some exercises to practice clojure and preferebly also goes into some testing. any tips?

kelveden22:03:38

http://www.4clojure.com/ is an easy starting point as it's web-based but personally I tend to recommend https://github.com/functional-koans/clojure-koans more as it encourages one to get familiar with running Clojure and using and editor/IDE.

👍 8
kelveden22:03:14

Also, if you've not already found it, http://clojuredocs.org/ is a good community-driven function reference - it's particularly useful as it provides practical examples of usage for most of the functions.

👍 8
practicalli-johnny15:03:17

Exercism and Codewars are both test oriented challenges. Exercism has lots of nice challenges, not too difficult, so you can focus on the language. Codewars seems to be more about mathematics the further you progress. I have published videos of solving some of the challenges from those sites and about 60 of the 4clojure challenges https://practicalli.github.io/