Hello, I am trying to understand how nREPL, my application code and the webserver such as Jetty are working together. Here is an outline of how I understand roughly what's happening when I run my web app with nREPL:
1. Start nREPL session
2. I send some command to start the web server (something like (run-jetty #'hdlr {...}) to nREPL).
3. Step 2 above will initiate preparation of my app (I expect this would involve loading java classes, clj namespaces, etc.) and run the server
4. Now, suppose I change hdlr code and reload the file via nREPL, then new changes will be reflected in the JVM
5. When I make a new request to the webserver, hdlr var will be dereferenced and I'll receive response generated by the new handler
Would it be correct to say that nREPL is a client server program running on a JVM that can receive clojure code from external processes such as editors and, somehow run them in the same JVM it is running on? And it can also send back the results to the external editor.
If I were to run my app on some remote machine, that would mean I will have to somehow sync my local environment (app code + all dependencies) on that remote machine as well. And nREPL along with my app will run in the JVM on that remote machine.
I'd would appreciate corrections or anything that will help me understand better or more accurately. Thanks!
You're very close to correct. nREPL is a server program. Something like cider-nrepl (or whatever else is used in your IDE) is the client that connects to it.
> I will have to somehow sync my local environment (app code + all dependencies) on that remote machine as well.
One common way to deploy Clojure web apps is to build a Java JAR file, which you copy to your remote machine and run it there with java -jar. Boom, Clojure code running.
If that code starts up an nREPL server, then you can connect to that nREPL from your local machine. When you do so you'll be connected to the remote process's live environment.
Evaluating code in that nREPL session will run in that remote process. This includes (re-)evaluating function definitions, which will override the existing functions. So the next time that function (like hdlr) is called, the new definition will be used. This is how you can make live changes to a running program, just like you would in a local nREPL.
With great power comes great responsibility. πΈοΈ
Thanks walterl. I can see now why I wouldn't have to sync the two envs.
For production, I like to use Socket REPL (for troubleshooting) https://clojure.org/reference/repl_and_main
What are the pro and cons of using Socket REPL? May I know?
@pyi.so.80 the socket REPL included in Clojure is much more primitive, and doesn't have any "protocol". It is like typing on the terminal repl and getting whatever is printed on it but over a socket. So for example telling apart the result of an expression from the outputs written by a println is on the socket client. The pros are the simplicity and that it is already included in Clojure, and you can connect to it using programs like telnet if you want. On the other side nREPL has many features, it is a request<->multi-response protocol, the messages can be encoded in many formats, it has support for server middlewares to extend its capabilities, so it's the preferred repl server for tooling.
How to write prismatic schema for below schema I am stuck in this from a day!
[:a {:f :user-preference
:l "Select your preferred notification method"
:c {:f {:account-type "premium"}}
:r true}
[:b {:l "Email Notifications"
:f :notify-email
:v "email"
:c {:f {:email-verified true}}}]
[:b {:l "SMS Notifications"
:f :notify-sms
:v "sms"
:c {:f {:phone-verified true}}}]
[:b {:l "Push Notifications"
:f :notify-push
:v "push"}]]Yes, That is a form field used in clojure script
I see, so similar to Hiccup, just higher level. Something like this?
(s/defschema OptionAttrs
{:l s/Str
:f s/Keyword
:v s/Str
(s/->OptionalKey :c) {s/Keyword {s/Any s/Any}}})
(s/defschema Option
[(s/one s/Keyword "option marker")
(s/one OptionAttrs "option attrs")])
(s/defschema FieldAttrs
{:l s/Str
:f s/Keyword
:r s/Bool
:c {s/Keyword {s/Any s/Any}}})
(s/defschema Field
[(s/one s/Keyword "field marker")
(s/one FieldAttrs "field attrs")
Option])
I tried (s/defschema Cond {:f {s/Any s/Any}}) ;; condition entry placeholder (s/defschema OptionItem [(s/one (s/eq :b) "Option Item") (st/merge {:l s/Str :f s/Keyword} (st/optional-keys {:v s/Str :c (s/cond-pre [Cond] Cond)}))]) (s/defschema OptionGroup [(s/one (s/eq :a) "Option Group") (st/merge {:f s/Keyword :l s/Str} (st/optional-keys (merge abc {:c (s/cond-pre [Cond] Cond)}))) [OptionItem]]) but did not helped
Hi. I removed your cross post - there was really no need for it. People who want to help beginners are already all here. :)
As for your question - are you absolutely sure that the data has to be in that shape? FWIW, it's not unheard of but is still very unusual to have vectors that are that heterogenic - a keyword, a map, and a bunch of other vectors.