This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-29
Channels
- # announcements (2)
- # babashka (2)
- # beginners (76)
- # boot (6)
- # calva (7)
- # cider (12)
- # clara (4)
- # clj-kondo (11)
- # cljdoc (9)
- # cljs-dev (21)
- # cljsrn (7)
- # clojure (72)
- # clojure-dev (158)
- # clojure-europe (2)
- # clojure-italy (3)
- # clojure-losangeles (3)
- # clojure-nl (5)
- # clojure-spec (29)
- # clojure-uk (93)
- # clojurescript (40)
- # cursive (7)
- # data-science (1)
- # datomic (28)
- # defnpodcast (5)
- # duct (5)
- # emacs (7)
- # events (2)
- # figwheel-main (5)
- # fulcro (55)
- # graalvm (2)
- # instaparse (1)
- # jobs (5)
- # juxt (1)
- # luminus (3)
- # nyc (2)
- # pathom (3)
- # planck (25)
- # re-frame (2)
- # reagent (4)
- # reitit (23)
- # shadow-cljs (381)
- # spacemacs (6)
- # sql (19)
- # tools-deps (7)
- # xtdb (4)
I am running into a problem with Muuntaja it seems, when I return this from a handler:
{:status 200
:headers {"Content-Type" "application/transit+json"}
:body {:foo "bar"}}
Without the content-type it always returns json and with the conten-type header with transit it gives me:
java.lang.IllegalArgumentException: No implementation of method: :write-body-to-stream of protocol: #'ring.core.protocols/StreamableResponseBody found for class: clojure.lang.PersistentArrayMap
at clojure.core$_cache_protocol_fn.invokeStatic(core_deftype.clj:583)
at clojure.core$_cache_protocol_fn.invoke(core_deftype.clj:575)
at ring.core.protocols$eval22168$fn__22169$G__22159__22178.invoke(protocols.clj:8)
at ring.util.servlet$update_servlet_response.invokeStatic(servlet.clj:106)
at ring.util.servlet$update_servlet_response.invoke(servlet.clj:91)
at ring.adapter.jetty$async_proxy_handler$fn__22292$fn__22293.invoke(jetty.clj:38)
at reitit.http$ring_handler$fn__21792$respond_SINGLEQUOTE___21795.invoke(http.cljc:155)
at sieppari.core$deliver_result.invokeStatic(core.cljc:63)
at sieppari.core$deliver_result.invoke(core.cljc:56)
at sieppari.core$execute.invokeStatic(core.cljc:81)
at sieppari.core$execute.invoke(core.cljc:75)
at reitit.interceptor.sieppari$reify__26267.execute(sieppari.clj:18)
at reitit.http$ring_handler$fn__21792.invoke(http.cljc:158)
at clojure.lang.AFn.applyToHelper(AFn.java:160)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.AFunction$1.doInvoke(AFunction.java:31)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invokeStatic(core.clj:665)
at clojure.core$apply.invoke(core.clj:660)
at avisi.topdesk.cloud.server$fn__52550.invokeStatic(server.clj:17)
at avisi.topdesk.cloud.server$fn__52550.doInvoke(server.clj:17)
at clojure.lang.RestFn.invoke(RestFn.java:436)
at ring.adapter.jetty$async_proxy_handler$fn__22292.invoke(jetty.clj:35)
at ring.adapter.jetty.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)
at org.eclipse.jetty.server.Server.handle(Server.java:503)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103)
at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683)
at java.lang.Thread.run(Thread.java:748)
And I am using this interceptor in [:data :interceptors]
;;; Content-negotiation
(muuntaja/format-interceptor)
Oh lol I get why I get the error, muuntja now thinks that i already made the body transit
Ah and the call sends accept: */*
So false alarm please ignore
so @ikitommi i tried doing the lazy array parsing for jsonista, but got stuck... i'd make a deserializer class that takes a clojure function (ifn) that just creates a lazy-seq, but for some reason the jsonparser is closed when wrapped by lazy-seq
-- something that doesn't seem to happen in cheshire. i'm kinda lost...
public class LazyVectorDeserializer extends StdDeserializer<LazySeq> {
private final IFn func;
public LazyVectorDeserializer(IFn func) {
super(List.class);
this.func = func;
}
@Override
@SuppressWarnings("unchecked")
public LazySeq deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
JsonDeserializer<Object> deser = ctxt.findNonContextualValueDeserializer(ctxt.constructType(Object.class));
p.nextToken();
return (LazySeq) func.invoke(p);
}
}
(defn ^clojure.lang.LazySeq parse-element
[^com.fasterxml.jackson.core.JsonParser my-parser]
(println (.isClosed my-parser))
(lazy-seq
(loop [chunk-idx 0, buf (chunk-buffer *chunk-size*)]
(if (identical? (.getCurrentToken jp) JsonToken/END_ARRAY)
(chunk-cons (chunk buf) nil)
(do
(chunk-append buf (.getCurrentToken jp))
(println (.isClosed jp))
(.nextToken jp)
(let [chunk-idx* (unchecked-inc chunk-idx)]
(if (< chunk-idx* *chunk-size*)
(recur chunk-idx* buf)
(chunk-cons
(chunk buf)
(parse-element jp )))))))))
first isParse (outside the lazy-seq) returns true but the one inside is false so the nextToken throws a nullpointer.i figure it gets closed because deserialize returned a value so jackson thinks its job is done, instead of letting the clojure function create a closure with it
i can try, but i think it's more of a clojure issue. after all it does work when cheshire wraps it in lazy-seq
can you parse a intermediate object within a lazy-seq with object-mappers json parser or does it too close the stream?
i couldn't get it not to close the stream so far... cheshire's architecture is very different from how you're doing things in jsonista, so just taking their lazy parse function isn't very obvious
later i'll try doing it a different way, "parsing" all the array but making the parsing of the elements lazy.
How would I tell swagger that I expect a bearer token for some APIs? Is this possible so that it's reflected in the UI? I found [this](https://swagger.io/docs/specification/2-0/authentication/api-keys/) but I'm unsure how the data flows from reitit
I don't know if using apiKey
is supported at this point, but adding :parameters {:header {:authorization ::spec/bearer-token}}
should work. With a spec like (s/and string? #(re-matches #"Bearer .+" %))
For swagger-ui, you need to add the :securityDefinitions
manually under :swagger
, to here: https://github.com/metosin/reitit/blob/master/examples/http-swagger/src/example/server.clj
would be relatively easy (and handy) to have a security-middleware
& security-interceptor
that both enforces the api-keys and writes the swagger-spec data so the UI is in sync. All the needed extension points already exist, just needs someone to do those..
Here's an example mw that contributes to swagger docs: https://github.com/metosin/reitit/blob/master/modules/reitit-middleware/src/reitit/ring/middleware/muuntaja.clj#L64