julianbirch / cljs-ajax Goto Github PK
View Code? Open in Web Editor NEWsimple asynchronous Ajax client for ClojureScript and Clojure
simple asynchronous Ajax client for ClojureScript and Clojure
just a suggestion.
Thanks for your cljs-ajax
On IE 6 , the error with message "Console is not difined." happens.
The problem is in core.cljs : Line 37
(.log js/console "WRITE JSON" data)
This is going to break @jonpither, but I'd like to change this for 0.2.0. My reason for doing this is that I'd like to have it have the same API and wrap-json-body
in [ring-json] [1].
You'd still be able to override to the unsafe behaviour, but it would be good if our default was safe. Prefix should probably be while(1);
which would mean that the default also worked against google APIs.
I had to manually set the headers to "application/transit+json", otherwise the request had a default of "text/html".
Problem occurs on Firefox.
Apologies for the newbie question.
I'm doing a GET and the response is a list of items (json). I can see the result in the network tab. When I print the result I see it is a cljs.core.PersistentVector. When I map over the result each item is a cljs.core.PersistentHashMap. However, I can't access the items inside the map (e.g. (:key map-item)). If I print the keys and vals of the each map I can see the correct items are there, so I'm very confused as to why __(:key ma-item) is not working. I'm pretty sure I'm missing something basic. Would appreciate some pointers.
Sorry for posting this basic question here, have been googling for hours and couldn't find a solution.
I have just upgraded a project that depended on v0.2.6 to v0.3.3.
I was using the ajax-request defn rather than the GET macro. I have changed my code to use the GET macro because one of the defns that I was using, json-format, is no longer in the code.
Trying to use the documentation as a guide, I couldn't find the codec defn either.
I have a Restful API that, following the HTTP spec, it returns a status code of 201
when a new resource is created, and the URL of the just created resource in the Location
header of the response.
How can I get this header using cljs-ajax?
More a question than an issue: should the API be redesigned to use channels?
I have a use-case where I need the JSON from the .getResponseJson to remain in JSON format. When I used :response-format :json it still gets converted to EDN. In this case I need it in JSON format so I can pass it to another library.
Is this something you could support?
Otherwise I have to convert the EDN back into JSON which feels wasteful, or use goog.xhrio directly. :(
Hi,
I've been looking into using cljs-ajax for a smaller project of mine, but I need to be able to access the request's response headers.
My idea was to implement a new handler that would forward the response headers, but they seem to get swallowed in base-handler
/js-handler
.
What would be the best way to modify this project to expose the response headers?
(GET "/users" {:handler handle-users
:error-handler handle-error
:headers {"X-api-key" "my-app-key"
"Accept" "application/edn"}})
I get a 404 because it tried to send a request method of OPTIONS
instead of GET
.
If I leave out :headers
it does in fact issue a GET
request, but it fails on the server for obvious reasons; there is no request header of X-api-key
.
Here is my implementation of the GET function:
(defn send-to-say [message]
(GET "/say" {:params {:greeting message}
:handler (fn [response]
(.log js/console (str response)))}))
The output from the GET handler function, to the console, is <p>You
, the first "word" only.
The response from the server, as seen in the chrome network tab is:
<p>You said: test</p>
with headers:
HTTP/1.1 200 OK
Date: Sat, 07 Jun 2014 15:07:47 GMT
Content-Type: text/html;charset=UTF-8
Content-Length: 21
Server: Jetty(7.6.8.v20121106)
It looks like the server side is behaving correctly.
Here is my action using compojure and hiccup:
(defn say [params]
(html [:p (format "You said: %s" (get params "greeting"))]))
I must be missing something. Thanks for your help.
The code needs one.
I noticed that you hadn't implemented HTTP DELETE. Any particular reason? Is that something that you can put in?
HTTP method definitions are here.
The README (and the docstrings for GET and POST functions) says that :format
indicates the response format. Shouldn't this indicate the request format actually? This ClojureScript code running in the browser doesn't know which will be the format of the server response (at most it can specify a preferred format using the HTTP Accept:
header), but it can choose how to format the request.
On the other hand, the only way to specify the data to send according to the README is the :params
option, but I found that the contents of :params
is not affected by the value of :format
, and it's always sent as application/x-www-form-urlencoded
. Digging through the code I finally found that I could get the expected behaviour (i.e. data sent encoded in the specified format) if the data to send is specified in a :data
option (instead of :params
), which is not mentioned in the README. I also see that the data to send can be specified in a third way, using a :body
option. Why these 3 different ways?
Finally, I guess a component is needed in the server-side to parse EDN or JSON, isn't it? Something like ring-edn and ring-json?
Commit 799e256 changed the keyword-response-format function and it seems keyword formats no longer work.
The cond line (ifn? format) also matches keywords, should be (fn? format).
PATCH is a HTTP verb. Perhaps it could be added to the easy-api's.
(m/easy-api PATCH)
I think this is a one-liner but perhaps there's more to it. I note that the Django REST Framework documentation talks about PATCH as a browser enhancement.
I would like to know how cljs-ajax handles an ajax request where the server might take several seconds to respond, or never respond at all. Does the rest of the cljs app block (does the JS stop execution) while waiting? XHR can be either sync or async and I'm curious how cljs-ajax handles this.
The following call
(DELETE "http://localhost:3000"
{:format (json-request-format)})
makes an http DELETE request with the request-body null
and Content-Length
4 even if no :params
are specified.
This is problematic at least on Google App Engine as the web server won't allow a body in DELETE
requests
It might be an idea to provide a key like :csrf-token
that would be used to pass a CSRF token in the request. Since ring-defaults enables CSRF protection by default, and the token should be format independent, it would be nice to be compatible with the ring-anti-forgery middleware format.
It would be useful to be able to specify the HTTP Accept header used in the request, especially for REST resources.
It would be nice if ajax-request
followed this guideline from the Library Coding Standards:
Unroll optional named arguments. Callers should not have to wrap optional named arguments in a map literal:
(release-sharks 2 :laser-beams true) ; good (release-sharks 2 {:laser-beams true}) ; bad
I looked to see if I could easily submit a PR for this, and noticed there's an undocumented fourth parameter to ajax-request
, used in one of the tests. Can this be made an option, or, if it's only for internal/testing use, maybe use with-redefs
in the test instead?
I made a simple server that returns this:
HTTP/1.1 200 OK
Content-Length: 43
Content-Type: application/edn; charset=utf-8
Date: Sat, 05 Jul 2014 15:44:29 GMT
Server: http-kit
{:s "string", :l 42, :k :keyword, :d 1.337}
In my ClojureScript client I get this with:
(GET "/data" {:handler show-result})
In Chrome, Firefox and IE10 I get the expected result, but in IE8 the value of :i is 0
.
Versions:
[org.clojure/clojurescript "0.0-2234"]
[cljs-ajax "0.2.6"]
Compiled with :whitespace
optimisation.
Amazing what you see when you code-review something you wrote two weeks ago.
I'm trying to do a file upload and handle progress events, but experiencing weird behaviour where the error handler is spuriously called and the success handler is called multiple times. I've created a minimal reproducing example project based on the reagent-figwheel template here: https://github.com/rsslldnphy/cljs-ajax-fileupload-issue.
The most relevant part is in cljs-ajax-fileupload-issue.core
, which I'll reproduce here:
(defn do-upload
[e]
(let [f (first (array-seq (.-files (.-target e))))
filename (.-name f)
form-data (js/FormData.)
xhr (js/XMLHttpRequest.)]
(.append form-data "filename" filename)
(.append form-data "file" f)
(-> xhr
.-upload
(.addEventListener "progress"
#(.log js/console "Made progress") false))
(ajax/POST "/uploads" {:api xhr
:processData false
:params form-data
:handler #(js/alert "Finished file upload")
:error-handler #(js/alert "Failed file upload")})))
(defn page []
[:div [:h1 "Upload file below"]
[:input {:type "file" :on-change do-upload}]])
When I upload a file using this code, I see:
I'm guessing it's perhaps something to do with me using XMLHttpRequest
? Maybe it calls the handler with some extra events which get interpreted as success or failure?
Oh - and I just changed the error-handler to console log the response, and it appears to have a status of 0 if that helps.
Hi, this library works nicely, but I'm wondering if it is possible to turn off the logging to the browser console that says XHR finished loading?
After requiring ajax.core module I catch errors in my console:
Uncaught TypeError: undefined is not a function useragent.js:31
Uncaught TypeError: undefined is not a function disposable.js:81
Uncaught TypeError: undefined is not a function listener.js:110
Uncaught TypeError: undefined is not a function events.js:146
Uncaught TypeError: undefined is not a function json.js:33
Uncaught TypeError: undefined is not a function functions.js:277
Uncaught TypeError: undefined is not a function debug.js:30
Uncaught TypeError: undefined is not a function logrecord.js:104
Uncaught TypeError: undefined is not a function logbuffer.js:64
Uncaught TypeError: undefined is not a function logger.js:105
Uncaught TypeError: undefined is not a function log.js:34
Uncaught TypeError: undefined is not a function xmlhttp.js:49
Uncaught TypeError: undefined is not a function xhrio.js:222
Uncaught TypeError: undefined is not a function xhrio.js:71
It seems goog.define
is not being defined. Removing [ajax.core :refer [GET POST]]
solves problem.
Can finally also receive the response?
My use-case is adding some interceptors which dispatch on certain http statuses.
(GET "/data"
{:params {:a ["a", "b", "c"]}})
Generates request to
/data?a=a&a=b&a=c
While it should generate a request to (although i still can't find an RFC, but that's what many people do)
/data?a%5B%5D=a&a%5B%5D=b&a%5B%5D=c
Any hints?
When you run the tests, you get a warning that ajax.core.AjaxImpl is not a protocol.
I can't figure out what on earth causes this error to happen, I've asked on IRC, still no idea.
I'd be very glad if someone could figure out what I'm doing wrong on this.
No-one's needed it so far, but sooner or later someone will. A good candidate for a pull request. Make ajax-request return a value that can later be cancelled.
The code now has support for setting a timeout parameter, but I haven't tested how timeout feedback works, so this is not really finished.
Maybe also allow empty responses to be EDN instead of EOF while reading Format should have been EDN (default)
Sometimes only the successful response is enough and the error response has content.
I'm trying to implement a simple AJAX-query to get a map structure from server.
This is my request:
(GET "/search" {:handler handler
:params {:q (:text (deref data))}
:format :transit
:response-format :transit
:error-handler (fn [data] (println 123123))})
And this is handler:
(defn handler [response]
(.log js/console "11111")
(.log js/console (str response)))
Handler gets nothing:
I also can see a good response in Network tab:
Suggestion: Add a key to the options map which contains a function which is always called after the response/error handler.
I find myself duplicating code in the end of the normal handler and error handler to re-enable form buttons and change classes in the DOM which visualized that an action was waiting for a response. But I supposed it would have other use cases.
The key could be called finally
(like when working with exceptions).
Should have an option to keywordize-keys when parsing a JSON response? not sure how this goes down with EDN
I'd like to help but the tests are failing. Installed Phantomjs 1.9.7 on osx + Clojurescript.Test and getting this message
$ lein test
Compiling ClojureScript.
Compiling "target/main.js" from ["src"]...
Compiling "target/main.js" failed.
clojure.lang.ExceptionInfo: {:tag :cljs/analysis-error}
at clojure.core$ex_info.invoke(core.clj:4327)
at cljs.analyzer$error.invoke(analyzer.clj:268)
at cljs.analyzer$analyze.invoke(analyzer.clj:1522)
at cljs.analyzer$analyze.invoke(analyzer.clj:1519)
at cljs.compiler$parse_ns$fn__5022$fn__5023.invoke(compiler.clj:959)
at cljs.compiler$parse_ns$fn__5022.invoke(compiler.clj:959)
at cljs.compiler$parse_ns.invoke(compiler.clj:954)
at cljs.compiler$parse_ns.invoke(compiler.clj:949)
at cljs.compiler$to_target_file.invoke(compiler.clj:1037)
at cljs.compiler$compile_root.invoke(compiler.clj:1069)
at cljs.closure$compile_dir.invoke(closure.clj:341)
at cljs.closure$eval5363$fn__5364.invoke(closure.clj:381)
at cljs.closure$eval5300$fn__5301$G__5291__5308.invoke(closure.clj:292)
at cljs.closure$eval5350$fn__5351.invoke(closure.clj:395)
at cljs.closure$eval5300$fn__5301$G__5291__5308.invoke(closure.clj:292)
at cljsbuild.compiler.SourcePaths$fn__5559.invoke(compiler.clj:44)
at clojure.core$map$fn__4207.invoke(core.clj:2485)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:60)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$apply.invoke(core.clj:617)
at clojure.core$mapcat.doInvoke(core.clj:2514)
at clojure.lang.RestFn.invoke(RestFn.java:423)
at cljsbuild.compiler.SourcePaths._compile(compiler.clj:44)
at cljs.closure$build.invoke(closure.clj:955)
at cljs.closure$build.invoke(closure.clj:923)
at cljsbuild.compiler$compile_cljs$fn__5570.invoke(compiler.clj:58)
at cljsbuild.compiler$compile_cljs.invoke(compiler.clj:57)
at cljsbuild.compiler$run_compiler.invoke(compiler.clj:158)
at user$eval5696$iter__5699__5703$fn__5704.invoke(form-init2101836119125145764.clj:1)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:60)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$dorun.invoke(core.clj:2780)
at clojure.core$doall.invoke(core.clj:2796)
at user$eval5696.invoke(form-init2101836119125145764.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6619)
at clojure.lang.Compiler.eval(Compiler.java:6609)
at clojure.lang.Compiler.load(Compiler.java:7064)
at clojure.lang.Compiler.loadFile(Compiler.java:7020)
at clojure.main$load_script.invoke(main.clj:294)
at clojure.main$init_opt.invoke(main.clj:299)
at clojure.main$initialize.invoke(main.clj:327)
at clojure.main$null_opt.invoke(main.clj:362)
at clojure.main$main.doInvoke(main.clj:440)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
at cljs.core$import_macros$fn__5761.invoke(core.clj:49)
at clojure.core$map$fn__4207.invoke(core.clj:2485)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:60)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$map$fn__4211.invoke(core.clj:2490)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:67)
at clojure.lang.RT.seq(RT.java:484)
at clojure.core$seq.invoke(core.clj:133)
at clojure.core$concat$cat__3925$fn__3926.invoke(core.clj:687)
at clojure.lang.LazySeq.sval(LazySeq.java:42)
at clojure.lang.LazySeq.seq(LazySeq.java:60)
at clojure.lang.Cons.next(Cons.java:39)
at clojure.lang.RT.next(RT.java:598)
at clojure.lang.Compiler.eval(Compiler.java:6606)
at clojure.lang.Compiler.load(Compiler.java:7064)
at clojure.lang.RT.loadResourceScript(RT.java:370)
at clojure.lang.RT.loadResourceScript(RT.java:361)
at clojure.lang.RT.load(RT.java:440)
at clojure.lang.RT.load(RT.java:411)
at clojure.core$load$fn__5018.invoke(core.clj:5530)
at clojure.core$load.doInvoke(core.clj:5529)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at cljs.analyzer$load_core.invoke(analyzer.clj:210)
at cljs.analyzer$analyze$fn__4037.invoke(analyzer.clj:1528)
at cljs.analyzer$analyze.invoke(analyzer.clj:1524)
... 49 more
Tests failed.
I notice when using JSON, js->clj
is used to convert over to cljs data structures. According to this using a transit JSON reader would be faster. It does mean the keys have to be strings though which might be a deal breaker.
What do you think? I'm not sure this is a good idea, so I figured I'd throw it out there for discussion.
An alternative is to just set cljs-ajax to transit mode, and have the server return plain JSON anyway. I think that should work. The only caveat there is the server needs to be ready for accept containing application/transit+json
.
Hi @yogthos,
I'm using edn as the data format for the req and response of a get request, but because the data is added to the query string, two problems occur:
wrap-edn-params
middleware interprets them as strings (keyword keys make it across just fine)nil
values are appended as "null", which on the server ends up as the string "null"
As a work around I added some ring middleware to get the actual params, but I wanted to know whether the behavior I just described is expect or whether a patch to change it would be considered.
Thanks,
Tom
Hi,
Is it possible to add support for the application/transit content type?
See here: https://github.com/cognitect/transit-format for more information.
Currently, the documentation tells you the wrong thing.
I have a simple event handler that works like this:
(defn attempt-to-sign-in! [event]
(.preventDefault event)
(let [email (.-value (.getElementById js/document "email-field"))
password (.-value (.getElementById js/document "password-field"))
handler #(set! (.. js/window -location -href) "/")]
(POST "/api/authenticate" {:params {:email email :password password}
:keywords? true
:response-format :json
:handler handler})))
When I examine the payload that this request creates, it's this:
["^ ","~:email","[email protected]","~:password","password123"]
This seems very wrong. Is it my fault or is this a bug?
I'm new to clj & cljs and I can't find the way to require POST ans GET method, when I use the readme samples I can't use POST nor GET
(:require [ajax.core :refer [GET POST]])
request-ajax is fine.
Even looking at src code didnt help me
I'm using the "0.3.0-SNAPSHOT" (I need the file upload support).
According to docs, if :response-format
is left blank, the format is detected from the Content-Type header. However,
(ajax.core/POST "/upload" {:params (js/FormData. form-node)})
; =>
; Uncaught Error: unrecognized response format:
; get_response_format
; ajax_request
; easy_ajax_request
; POST__delegate
If the :response-format
is added then it works, ex.
(ajax.core/POST "/upload" {:params (js/FormData. form-node
:response-format :edn)})
cljs-ajax's readme is mostly pretty comprehensive (well done everyone!) but it does not seem to mention how it handles non-HTTP errors, such as timing out waiting for a response, or failing to contact the destination server at all.
What does cljs-ajax do then? Throw? Return some kind of error object? I'd like to see this in the readme (forgive me if I missed it).
There are no good use cases for EDN on the browser with the advent of transit. Move EDN formats into a separate namespace and remove EDN from format detection.
This would be a breaking change, so 0.4.0 at the earliest.
At some point, EDN support should be removed entirely.
It's a minor issue, but it'd be really useful if you could make the license for the project a bit more obvious. I know that you specify the Eclipse public license in your project.clj, but it'd be great if you could include that in the README and/or include a LICENSE file.
Thanks!
It would be nice to have support for setting the withCredentials
attribute on the XHR object so the ajax request can set and read cookies etc.
Looking around the Google Closure API docs, this can either be done with an argument passed to the XhrIo
constructor or by calling setWithCredentials(true)
on it preflight.
I have tried to do this myself but I can't make it work. I'll issue a PR if I get anywhere.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.