This is part one of a series of blog posts that tries to teaches you Clojure from scratch.
It assumes that you have little or no experience with programming.
By the end of the series you'll have your own Clojure website deployed to production: a homepage, an interactive page, and a blog.
Some of it will be hard, and you won't understand everything we do to get there. Try to trust the process. My primary goal is to help you experience success early (in the form of having your own website) in the hope that it motivates you to continue your learning journey. If you are curious and persistent, you should be able to complete this. Good luck!
In this first part we'll build a very small program and run it.
What you need
- Clojure installed on your computer
- Visual Studio Code installed on your computer
To check that Clojure is installed, open a terminal and run:
If it prints a version number, you're ready.
Clojure runs on the JVM (Java Virtual Machine), and the installation guide walks you through getting that too, so there is nothing extra to download if the command above works. This series is written with macOS and Linux terminals in mind, but Windows should work too.
Create a project folder
Create an empty folder on your computer and call it my-site.
Open Visual Studio Code, click File > Open Folder, and choose my-site.
You'll see an empty file explorer on the left. Everything you make in this series will live here.
Now click Terminal > New Terminal.
A panel opens at the bottom of the window.
A terminal is a place where you give your computer instructions by typing them.
This one starts "inside" your my-site folder, which is exactly where you want it.
Optional: open the Extensions panel (the squares icon on the left), search for Calva, and install it. It will make it easier to work with Clojure files and will allow you to do REPL-driven development in the future.
Step 1: Tell Clojure about your project
Create a new file called deps.edn in the root of your project
(hover over the file explorer and click the "New File" icon).
Paste or type this in:
You don't have to understand all of this yet, but here is a quick tour:
:paths ["src"]says "my code lives in a folder calledsrc".:depslists the libraries this project uses. Clojure itself is one of them. The other is http-kit, a library that speaks HTTP, the language of web browsers.:aliasesdefines shortcuts.:runis a shortcut that means "start the program whose entry point is calledapp.core".
The whole file is a map: a collection of keys (the keywords starting with :) and the values that go with them.
Make sure to save the file before moving to the next step.
Step 2: Write the program
Create a new file at src/app/core.clj.
That's a folder called src (src is short for source), with a folder called app inside it, with a file called core.clj inside that.
(If you type src/app/core.clj as the file name, VS Code will create the folders for you.)
The name app.core in deps.edn matches this path: src/app/core.clj.
Clojure uses the folders and file name to find your code.
One thing to know before we start: Clojure uses lots of parentheses.
Almost everything is written as (something and-then-its-arguments):
the first word says what to do, and the rest is what to do it with.
For example, (println "Hello") means "print the text Hello".
Every ( needs a matching ), and the same goes for [ with ] and { with }.
VS Code highlights matching pairs as you type, and if you lose one, Clojure will tell you. We'll try that on purpose near the end.
We'll write the file in three small pieces.
Piece 1: Define a namespace and require some code
ns is short for namespace.
The first line of your Clojure file defines the namespace you are working on (app.core) and the code it needs from other places in order to work.
Here we require org.httpkit.server from http-kit and give it the nickname http so we don't have to type the long name every time.
Piece 2: Handle requests
Add this at the bottom:
A website is like a conversation: a browser sends a request and the server sends back a response.
browser your program
--------- ------------------
GET / ---- request ------> handler
<--- response ------ {:status 200 ...}
handler is the function that handles what to send back.
A function is a named piece of code that takes something in, does some work, and gives something back.
Here, handler takes in the request and gives back the response.
defndefines a function. Here you named ithandler.[_req]is the thing the function receives: the request from the browser. The leading underscore is a convention that means "I'm not using this yet".- The
{...}is a map that defines the response::statusis a code (200 means "OK"),:headersdescribes the format of the response, and:bodyis what shows up on the screen.
Notice that in Clojure, calling a function returns whatever its last expression evaluates to. handler return the map with :status, :headers and :body.
Piece 3: Create a main function and start the server
Add this at the bottom:
-main is the function that runs when you start your program.
It prints a message, then starts a server with your handler.
& _args is for words typed after the program's name on the terminal. We're not using any, so ignore it for now.
8080 is a port, which you can think of as a numbered door on your computer.
Browsers will knock on door 8080 to talk to your program.
Here is the complete file:
Save it. Your project should now look like this:
my-site/
deps.edn
src/
app/
core.clj
Run it
In the terminal at the bottom of VS Code, type this and hit enter:
The first time, Clojure downloads the libraries from deps.edn. It can take a minute.
When it's done you'll see the message:
Server running on port 8080
The terminal now looks stuck, with no prompt coming back. That's correct: your server is running and waiting for visitors.
Open http://localhost:8080 in your browser.
localhost is a name that basically means "this computer".
You should see:
Hello, World!
Checkpoint: you just wrote a program that serves a web page. It works only on your computer, but you created a real (and very simple) web page!
Change something
Go back to src/app/core.clj and change the body from "Hello, World!" to "Hello, Clojure!". Save the file and refresh your browser.
Nothing changed. That's expected: the running program loaded the old code and doesn't know that the file changed.
Go to the terminal, press Ctrl+C to stop the server, then run clojure -M:run again and refresh the browser.
This is the rhythm for the next few parts: edit, stop, start, refresh. (Clojure has a smarter way of working called REPL-driven development. We'll start using it in a future post.)
Break it on purpose
Reading errors is a good portion of programming, and it's easier when you know what broke. To get some practice, delete the very last character of the :body line (the ) right after the }), save, stop the server, and start it again.
You'll get an error that starts with Syntax error reading source and says EOF while reading, starting at line 4.
It's Clojure telling you "I reached the end of the file (EOF) and something that opened on line 4 was never closed".
Line 4 is where handler begins, so that's the place to look.
Put the ) back, restart, and you're back in business.
When you see a wall of error text, don't panic. The useful part is usually in the first or second line.
If something went wrong
clojure: command not found: Clojure isn't installed yet, or the terminal was opened before the install finished. Close VS Code, reopen it, and try again.Address already in use: another program, or an earlier run of this one, is using port 8080. You'll still seeServer running on port 8080just before the error, because the message prints before the server tries to claim the port. Find the terminal where it's still running and pressCtrl+C. Alternatively, change your code to use another port (say 8081).- An error mentioning
Could not locate app/core: the file isn't atsrc/app/core.clj. Check the folder and file names. - The browser says it can't connect: the server isn't running. Look at the terminal for an error, or for the prompt coming back, which means the program exited.
What you learned
- Your website works like a conversation: a browser sends a request, and your program sends back a response.
- A function takes something in, does some work, and returns something.
handler, for example, takes the request and gives back a map describing the response. deps.ednsays what the project needs and creates aliases (likeclojure -M:run).src/app/core.cljholds the code for yourhandler(what to say) and-main(the starting point).- An error message is Clojure telling you where it got lost. Start reading the first and second lines before you panic.
Next
In a future blog post we'll make handler smarter and we'll make a few small changes so the same program can run on someone else's computer via the internet.
Bonus: now that you are technically a Clojure developer, why not join the Clojurians community on Slack?