Quickie: Using figwheel and leiningen as a proxy server for fun and profit

Overview:

Leiningen is an awesome part of the Clojurescript landscape, doing live reloading of code and CSS. It even offers a static-file server, if you happen to be developing a client-only application.

Less appreciated is that you can plug in your own Ring handler. A particularly convenient use-case that I’ve recently discovered is to plug in a proxy server, which has uses beyond client-only applications.

There’s three main use-cases justifying it for me:

How-To:

There is a sample project in the leiningen repo, but essentially all you need to do is define your handler, and specify it in the :ring-handler entry of your :figwheel configuration in project.clj .

You have a few options for Ring proxy handlers, but the one I went with is this one: tailrecursion/ring-proxy.

To use it, grab the leiningen sample and extend it for your needs:

(ns com.etbwc.dev-handlers
  (:require [compojure.core :refer [defroutes GET]]
            [compojure.route :as route]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]
            [ring.util.response :as response]
            [tailrecursion.ring-proxy :refer [wrap-proxy]]))

(defroutes app-routes
  ;; NOTE: this will deliver all of your assets from the public directory
  ;; of resources i.e. resources/public
  (route/resources "/" {:root "public"})
  ;; NOTE: this will deliver your index.html
  #(GET "/" [] (-> (response/resource-response "index.html" {:root "public"})
                  (response/content-type "text/html")))
  (route/not-found "Not Found"))


(def app (-> app-routes
             (wrap-defaults site-defaults)
             ;; Use a django API on a different localhost port:
             (wrap-proxy "/api" "http://localhost:8000/api")
             ;; Use the django static-files if you need for eg the admin site:
             (wrap-proxy "/static" "http://localhost:8000/static")
             ;; Proxy requests to a third-party API without CORS enabled:
             (wrap-proxy "/pq" "http://third.party.com/pq")))

Now to use the handler simply mention it in project.clj:

(defproject "etbwc-example" "0.1.0-SNAPSHOT"
  ;;...

  :figwheel {:http-server-root "public"
             :server-port      3451
             :nrepl-port       7892
             ;; Boom:
             :ring-handler     com.etbwc.dev-handlers/app
             :css-dirs         ["resources/public/css"]}

  ;;...
  )
Mark Hepburn 12 June 2017
blog comments powered by Disqus