(ns app (:require [reitit.ring]) [ring.util.response :as response] (defn secret-route [] ["/secret" {#_ ...stuff}]) (defn public-resource-route [] ["public/*" (reitit.ring/create-resource-handler)])]) (defn spa-fallback-handler [] (fn [request] (or (response/resource-response (:uri request) {:root "public"}) (-> (response/resource-response "index.html" {:root "public"}) (response/content-type "text/html"))))) (defn router [] (reitit.ring/router [(public-resource-route) (secret-route)])) ;; option 1 - doesn't seem to work (defn app [req] (-> req ((reitit.ring/ring-handler (router) (reitit.ring/routes (reitit.ring/create-resource-handler {:path "/"}) (reitit.ring/create-default-handler)))))) ;; option 2 - works (defn app [req] (-> req ((reitit.ring/ring-handler (router) (reitit.ring/routes (spa-fallback-handler) (reitit.ring/create-default-handler)))))) (comment ;; using option 1 (app {:request-method :get :uri "/ping"}) ; => {:status 200, :body "pong"} (app {:request-method :get :uri "/"}) ; => {:status 302, :headers {"Location" "/index.html"}, :body ""} (app {:request-method :get :uri "/public/index.html"}) ; => {:status 200, :headers {"Content-Length" "667" ... "Content-Type" "text/html"}, :body ..."]} ;; using option 2 (app {:request-method :get :uri "/ping"}) ; => {:status 200, :body "pong"} (app {:request-method :get :uri "/"}) ; => {:status 200, :headers {"Content-Length" "667" ... "Content-Type" "text/html"}, :body ..."]} (app {:request-method :get :uri "/public/index.html"}) ; => {:status 200, :headers {"Content-Length" "667" ... "Content-Type" "text/html"}, :body ..."]} (app {:request-method :get :uri "/login"}) ; => {:status 200, :headers {"Content-Length" "667" ... "Content-Type" "text/html"}, :body ..."]} :end)