Convert Figma logo to code with AI

duct-framework logoduct

Server-side application framework for Clojure

1,135
52
1,135
12

Top Related Projects

Micro-framework for data-driven architecture

1,474

A fast data-driven routing library for Clojure/Script

1,235

managing Clojure and ClojureScript app state since (reset)

A ClojureScript framework for building user interfaces, leveraging React

Quick Overview

Duct is a data-driven framework for building server-side applications in Clojure. It provides a structured approach to application development, emphasizing modularity, configuration, and extensibility. Duct aims to simplify the process of creating robust and maintainable Clojure applications.

Pros

  • Modular architecture that promotes clean, organized code
  • Extensive configuration options for flexibility and customization
  • Built-in support for common web development tasks (routing, middleware, etc.)
  • Strong emphasis on testing and development workflows

Cons

  • Steeper learning curve for developers new to Clojure or functional programming
  • May be overkill for small, simple projects
  • Limited community resources compared to more mainstream frameworks
  • Requires understanding of Clojure's unique approach to web development

Code Examples

  1. Defining a simple route:
(defmethod ig/init-key :duct.handler/root [_ {:keys [routes]}]
  (fn [request]
    (if-let [handler (routes (:uri request))]
      (handler request)
      {:status 404, :body "Not Found"})))
  1. Configuring a database connection:
{:duct.database/sql
 {:connection-uri "jdbc:sqlite:db/example.sqlite"}}
  1. Creating a simple handler:
(defmethod ig/init-key :example.handler/greet [_ _]
  (fn [_]
    {:status 200
     :headers {"Content-Type" "text/plain"}
     :body "Hello, World!"}))

Getting Started

  1. Add Duct to your project dependencies:
[duct/core "0.8.0"]
  1. Create a new Duct project using Leiningen:
lein new duct <project-name>
cd <project-name>
  1. Start the development environment:
lein duct setup
lein repl
  1. In the REPL, start the system:
(dev)
(go)

Your Duct application is now running and ready for development.

Competitor Comparisons

Micro-framework for data-driven architecture

Pros of Integrant

  • Simpler and more flexible design, allowing for easier customization
  • Lighter weight with fewer dependencies
  • Can be used independently of web frameworks, suitable for various application types

Cons of Integrant

  • Less opinionated, requiring more manual configuration
  • Fewer built-in integrations and modules compared to Duct
  • Steeper learning curve for beginners due to its flexibility

Code Comparison

Integrant configuration:

(def config
  {:app/db   {:connection-uri "jdbc:sqlite:example.db"}
   :app/handler {:db #ig/ref :app/db}
   :app/server {:handler #ig/ref :app/handler, :port 8080}})

Duct configuration:

(def config
  {:duct.profile/base
   {:duct.core/project-ns 'example
    :duct.server.http/jetty {:port 8080}
    :duct.router/ataraxy
    {:routes {[:get "/"] [:example.handler/index]}}}})

Both Integrant and Duct are Clojure libraries for managing application configuration and lifecycle. Integrant offers more flexibility and simplicity, making it suitable for various application types. Duct, built on top of Integrant, provides a more opinionated structure with additional integrations, making it particularly well-suited for web applications. The choice between them depends on the specific project requirements and developer preferences.

1,474

A fast data-driven routing library for Clojure/Script

Pros of Reitit

  • More flexible and modular routing system
  • Better performance for large applications
  • Extensive support for data-driven routing

Cons of Reitit

  • Steeper learning curve for beginners
  • Less opinionated, requiring more configuration

Code Comparison

Reitit routing example:

(def app
  (ring/ring-handler
    (ring/router
      ["/api" {:middleware [wrap-formats]}
       ["/users" {:get get-users
                  :post create-user}]])))

Duct routing example:

(def routes
  (ataraxy/handler
    {[:get "/api/users"] [:users/list]
     [:post "/api/users"] [:users/create]}))

Summary

Reitit offers a more flexible and performant routing solution, ideal for larger applications with complex routing needs. It provides extensive support for data-driven routing but may have a steeper learning curve.

Duct, on the other hand, provides a more opinionated and structured approach, which can be beneficial for smaller projects or developers new to Clojure web development. It offers a simpler setup process but may be less flexible for complex routing scenarios.

The choice between the two depends on the project's specific requirements, team expertise, and desired level of control over the routing system.

1,235

managing Clojure and ClojureScript app state since (reset)

Pros of Mount

  • Lightweight and focused solely on configuration management
  • Flexible and can be used with any Clojure application or framework
  • Simple API with easy-to-understand concepts (states and sources)

Cons of Mount

  • Less opinionated, requiring more manual setup for larger applications
  • Lacks built-in support for component lifecycle management
  • May require additional libraries for full application structure

Code Comparison

Mount:

(mount/defstate db
  :start (create-connection config)
  :stop (disconnect db))

(mount/start)

Duct:

(defmethod ig/init-key :app/db [_ config]
  (create-connection config))

(defmethod ig/halt-key! :app/db [_ db]
  (disconnect db))

(ig/init config)

Summary

Mount is a lightweight configuration management library, while Duct is a more comprehensive web application framework. Mount offers simplicity and flexibility, making it suitable for various Clojure projects. Duct provides a more structured approach with built-in component lifecycle management and integration with other libraries.

Choose Mount for simpler projects or when you need a flexible configuration solution. Opt for Duct when building larger web applications that benefit from its opinionated structure and ecosystem integration.

A ClojureScript framework for building user interfaces, leveraging React

Pros of re-frame

  • Specifically designed for building single-page applications (SPAs) in ClojureScript
  • Provides a clear and opinionated structure for managing application state
  • Extensive documentation and a large, active community

Cons of re-frame

  • Limited to frontend development, unlike Duct's full-stack capabilities
  • Steeper learning curve for developers new to reactive programming concepts
  • May be overkill for simple applications or static websites

Code Comparison

re-frame:

(re-frame/reg-event-db
 :initialize-db
 (fn [_ _]
   {:name "re-frame"}))

Duct:

(defmethod ig/init-key :app/routes [_ {:keys [db]}]
  [["/" {:get (fn [_] {:status 200 :body "Hello, Duct!"})}]])

Summary

re-frame excels in frontend development for ClojureScript SPAs, offering robust state management and a structured approach. Duct, on the other hand, provides a more comprehensive full-stack solution for Clojure web applications. While re-frame focuses on reactive programming patterns, Duct emphasizes modularity and configuration-driven development. The choice between the two depends on project requirements and whether a full-stack or frontend-specific solution is needed.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Duct

Duct is a highly modular framework for building server-side applications in Clojure using data-driven architecture.

It is similar in scope to Arachne, and is based on Integrant. Duct builds applications around an immutable configuration that acts as a structural blueprint. The configuration can be manipulated and queried to produce sophisticated behavior.

Upgrading

See: UPGRADING.md.

Quick Start

To create a new Duct project with Leiningen:

lein new duct <your project name>

This will create a minimal Duct project. You can extend this by appending profile hints to add extra functionality.

  • +api adds API middleware and handlers
  • +ataraxy adds the Ataraxy router
  • +cljs adds in ClojureScript compilation and hot-loading
  • +example adds an example handler
  • +heroku adds configuration for deploying to Heroku
  • +postgres adds a PostgreSQL dependency and database component
  • +site adds site middleware, a favicon, webjars and more
  • +sqlite adds a SQLite dependency and database component

For example:

lein new duct foobar +site +example

As with all Leiningen templates, Duct will create a new directory with the same name as your project. For information on how to run and build your project, refer to the project's README.md file.

Concepts

The structure of the application is defined by an Integrant configuration map.

In development, Duct uses Stuart Sierra's Reloaded Workflow.

In production, Duct follows the Twelve-Factor App methodology.

Local state is preferred over global state.

Namespaces should group functions by purpose, rather than by layer.

Protocols should be used to wrap external APIs.

Structure

Duct adds a layer of abstraction on top of Integrant. In Integrant, a configuration map is initiated into a running system map.

┌────────┐   ┌────────┐
│ config ├──>│ system │
└────────┘   └────────┘

In Duct, the configuration is initiated twice. The configuration is first initiated into an intermediate configuration, which in turn is initiated into the system:

┌────────┐   ┌──────────────┐   ┌────────┐
│ config ├──>│ intermediate ├──>│ system │
└────────┘   └──────────────┘   └────────┘

In the same way that higher-order functions allow us to abstract common patterns of code, Duct's layered configurations allow us to abstract common patterns of configuration.

Keys in a Duct configuration are expected to initiate into functions that transform a configuration map. There are two broad types: profiles, which merge their value into the configuration, and modules, which provide more complex manipulation.

Documentation

Community

File structure

Duct projects are structured as below. Files marked with a * are kept out of version control.

{{project}}
├── README.md
├── dev
│   ├── resources
│   │   ├── dev.edn
│   │   └── local.edn *
│   └── src
│       ├── dev.clj
│       ├── local.clj *
│       └── user.clj
├── profiles.clj
├── project.clj
├── resources
│   └── {{project}}
│       └── config.edn
├── src
│   ├── duct_hierarchy.edn
│   └── {{project}}
│       └── main.clj
└── test
    └── {{project}}

License

Copyright © 2021 James Reeves

Distributed under the MIT license.