WE OFFER A FREE CONSULTATION
Add file
DEVELOPMENT, 8 min Read

Clojure programming world: frameworks and other tools

May 6, 2019
Vladimir Pavlyuk
With the vibrant tech community, Clojure language has a good core of libraries, their collections and other ready-to-use tools. According to the 2019 year survey, 25% of Clojure users create or maintain open source solutions. Some programmers also check and fix issues (17%), or report on them (15%).
Clojure users
Although all these libs aim to simplify Clojure programming tasks, they may confuse a beginner. Sometimes, it's difficult to understand how to put all of them together and find an optimal solution for a specific task. So, now I want to show you my favorite tools for programming in Clojure. We will talk about:
  • working with web server and endpoints
  • interaction with web server and database
  • routing on server
  • using GraphQL in Clojure programming
  • support of modular architecture
Let's start our trip to the Clojure programming world!
Note: Moving from Java and other similar languages you should know that there aren't any traditional frameworks in Clojure. Everything is based on libs and their collections. This makes the language more flexible and multi-purpose.

Clojure ecosystem includes libs of different complexity. Some of them are only a set of additional functions (for example, a library for working with time). Meanwhile, system libs provide a platform for creating the entire framework. Such libraries allow the programmer to present an application as a set of components, describe the connections between them, and so on. The library itself ensures the creation of dependency graphs. For example, it can convert components into more understandable things, like functions.

1. Ring

Purpose: convenient work with web server and endpoints
Code: https://github.com/ring-clojure/ring

The HTTP server abstraction is a key element of Clojure web stack. It enables simple work with web server and endpoints, which is essential for successful app development. Created in analogy with WSGI (Python) and Rack (Ruby), Ring abstracts the information of HTTP into a clear, unified API. As a result, the web developer can build modular systems consisted of components and share these components among various servers and applications.

How does Ring work?

It gets HTTP requests and returns HTTP responses. So, Ring isn't a so-called web application framework.

Reasons for using Ring

As a dominant web library in Clojure programming, Ring is a nice choice for beginners. First of all, its main function is to provide a convenient interface for a wide range of web-servers. From this point of view, the technology is extremely useful and works perfectly.

Another Ring feature is providing a set of modules ('middleware'). So, it allows you to use different pre-written libraries, compatible with each other.

Most of Clojure programmers choose Ring for endpoints because of its ability to use middlewares. For instance, these modules allow transforming required parameters from an URL to the Clojure code map. A web developer can easily write new middleware and integrate it into the ecosystem. For example, using the cemerick/friend library, you can fully manage the authorization process, apply different strategies (starting from the login and password, ending with oAuth), etc. Ring middleware helps to conveniently describe and start the process. It closes all endpoints that are prohibited for unauthorized users.

Experience in using Ring is important for working with other Clojure technologies. It is the first thing you can use to get an app moving.

2. Http-kit

Purpose: server start up
Code: https://github.com/http-kit/http-kit

The event-driven, highly effective HTTP server/client library includes WebSocket, as well as asynchronous support.

How does Http-kit work?

It's a library for organizing a proper web server interaction. Http-kit is suitable for highly concurrent asynchronous or synchronous applications. As for WebSocket and HTTP long polling/streaming, it's better to feature a unified API.

Reasons for using Http-kit

Flexible solution
Http-kit provides an opportunity of working both with sync and async systems. The first option is simple, while the second works faster. So, you can make a choice based on your specific purpose. Moreover, you can use the library with Ring. It works almost like the Jetty adapter.

Convenient usage
The library ensures support for WebSockets, as well as perfect handling of long-held HTTP requests. So, creating a real-time app becomes easier. What is more, it's an open source project. The library is available on GitHub under the Apache License Version 2.0.

Excellent results
HTTP-kit shows high performance and works fast in spite of great loads. At the same time, each connection requires only a few kB of memory. A client/server that is written from scratch is available as a single ~90kB JAR with 0 dependencies and ~3k lines of clear code.

Many software developers consider HTTP-kit as a basic tool for Clojure programming.

3. COMPOJURE and BIDI

Both Compojure and Bidi are technologies for routing in web apps. The first library is quite popular among the community, while the second one is known as a handy solution for writing in ClojureScript.

How do Compojure and Bidi work?

These small libraries ensure routing on a web server. As a result, a software developer can write applications that are composed of several separate parts.

What's the difference between them?

The 2 libraries perform the same function. But, unlike Compojure, Bidi:

  • supports both clj and cljs
  • is isomorphic and extensible

The main difference is that in Bidi routes are data structures. There are no macros here. So, the library provides a convenient bi-directional approach and other advantages. Some web developers prefer Bidi because it shows each route of a particular handler. Moreover, there is an opportunity to read the routes from a configuration file, generate and transform them by functions and introspect. They work independently from handled requests. So, the developer can match on things that aren't necessarily handlers (for example, keywords).

4. Lacinia

Purpose: implementation of GraphQL in Clojure programming
Code: https://github.com/walmartlabs/lacinia

This popular Clojure library is useful for those, who want to implement GraphQL while working with web APIs.

How does Lacinia work?

Originally, GraphQL is written in JavaScript. Lacinia is an official reference to this implementation. It is written in analogy with the initial specification. It can be called a backend-agnostic GraphQL query execution engine. So, the library provides contact between your data and the GraphQL client.

Reasons for using Lacinia

Using GraphQL, you can easily get a richer, more complicate Web API. Lacinia simplifies API development because it supports inline/named query fragments, GraphQL Schema Introspection, subscriptions, interfaces, unions, enums, inputs and custom scalars.

Written in an EDN-based schema language, the library perfectly works with GraphQL queries. It is built on Antlr4. Lacinia helps to rich efficient asynchronous query execution. You can plug it into any Clojure HTTP pipeline and use the companion library lacinia-pedestal for HTTP support.

6. HoneySQL and HugSQL

Purpose: successful database interaction
Code: https://github.com/jkk/honeysql, https://github.com/layerware/hugsql

Many web programmers feel more comfortable working with SQL technologies, such as Oracle, MS SQL, MySQL, PostgreSQL, SQLite, etc. HoneySQL and HugSQL are query builders that provide stable access to SQL databases in Clojure applications.

How do HoneySQL and HugSQL work?

Both libraries ensure embracing SQL in Clojure programming. So, you will be able to write SQL database commands even in Clojure web apps.

What's the difference between them?

Using HugSQL, you start with writing separate SQL files and putting them in your application. The query constructor is inspired by another popular library, YeSQL. It not only parses SQL files into Clojure functions but is also suitable for more use cases than YeSQL. HugSQL is actively maintained. It has protocol-based adapters supporting multiple database libs.

HugSQL has several advantages due to 2 fundamental features:

  • the queries are written directly, one query for each required function;
  • the queries are written in SQL.

HugSQL pros

HugSQL provides separation of Clojure syntax and SQL semantics (WHAT and HOW).
  1. We describe WHAT to do in Clojure
(get-user-emails-by-username "Alexandr Petrov") ;-> ["[email protected]" "[email protected]"]

2. We describe HOW to do this in SQL
-- :name get-user-emails-by-username :? :*
select user_emails.email from user_emails where user_emails.user_id = :id

As a result, we can change the logic of getting the data directly in SQL, without rewriting Clojure code. It's useful when a database schema is changed, and the old query doesn't return the needed structure.
Moreover, SQL itself is a much more powerful tool for working with a specific DBMS. It allows writing large complex queries with "join", aggregations and Window Functions, which can be extremely difficult in Clojure.

Furthermore, SQL allows using benefits of a specific DBMS (for example, Postgres). It's important if you are sure the database won't be changed.

HugSQL cons

  • It's difficult to change DBMS in the middle of the project. It will be necessary to check a lot of requests and carefully test syntax support and specific output.
  • You can pass parameters to SQL queries. But, in some cases, the parts of the queries must be depended on certain conditions. Although HugSQL snippets allow completing this task, more often you need to do this using Clojure.

HoneySQL doesn't provide such separation of SQL and Clojure code. You will see the queries as a map.

HoneySQL pros

  • It's independent of a specific implementation of the DBMS because it usually avoids direct SQL queries. Instead of them, it uses specific DSL.
  • It allows maintaining your own DSL based on Clojure functions/macros. You can also create a query builder with saving intermediate requests on the Clojure side. For example, if you need to define a user by ID or other complex logic, you can save part of the HoneySQL structure. It will show that we need exactly the user, not the goods or other data. This "fragment" can be substituted into the necessary queries. As a result, you will get a shorter code.

HoneySQL cons

  • It can be challenging to use benefits of a specific DBMS, as well as to write complex queries (for example, with Window Functions)
  • The Clojure programmer needs to separate the code for retrieving data and the code for processing this data. The separation leads to additional work on refactoring.

6. danielsz/system

Purpose: support of modular architecture
Code: https://github.com/danielsz/system

Helpful technology for developing highly modular applications in Clojure. The framework supports effective interaction between modules and has good compatibility with other parts of the varied Clojure ecosystem.

How does danielsz/system work?

The library allows a web programmer to use a component-based approach. So, you can build an application using modules/components and the connections between them. Each component is a special object. It has its own life cycle. The programmer describes how it starts, what it needs to start, and how it stops.

For example, our application consists of a web server and a database. It makes no sense to start the web server before the database is activated. We describe the database component, describe the server component, and the server's dependency on the database. When launching the project, we indicate that we need to start the web server. The library will automatically try to activate the database. Then, if possible, it will start the server and transfer the finished activated database component to the web server component. Then, if necessary, the system will be stopped.

Reasons for using danielsz/system

Unlike the description of the entire application with a set of ordinary Clojure functions, the project description as components makes it easy to replace one component with another. For example, when testing an application, replacing one database with another, or turning it off completely, replacing it with the current data.

In the case of functions, you would change old functions with new ones. They will have the same name, which often causes bugs. danielsz/system is a ready-made set of solutions (for a web server, database, and much more), organized as a set of components.

I hope, now you better understand how to use Clojure and what tech solutions should be implemented in your project. My further articles will include the benefits of this powerful and beautiful language, as well as some tips on development of web applications, services, and APIs. So, subscribe to FreshCode blog, if you want to learn more about Clojure programming world.
1
2
3
4
5
Tech and business insights
Get valuable content once a week!
THE MOST popular POSTS
Show more