Search code examples
proxyclojureleiningenhttp-kitpedestal

How can I forward part of requests to another server in Clojure?


Summary

I am developing a server to be like a sort of a proxy in Clojure, with pedestal service + lein as a base:

  • Receive requests
  • Forward requests to external servers
  • Make multiple requests server-to-server to feed a bigger json and return as a single request to the client

It's easy to code and there are many resources on how to serve a route,
however I could not find any easy way, how to have a Clojure pedestal rest
service together with forwarding routes

Example

  • Client calls [GET] /billing => proxy-clojure-server
  • proxy-clojure-server authenticate request with client credentials => auth-server
  • proxy-clojure-server fills json with billing data => billing-server
  • proxy-clojure-server fills json with customer data => customer-server
  • proxy-clojure-server returns 200 with complete JSON resolved

Setup

  • I have a project with a similar structure as doing: lein new pedestal-service my-app

What I've been trying

Example:

(ns your-ns
  (:require [tailrecursion.ring-proxy :refer [wrap-proxy]]))

(def app
  (-> routes
      (wrap-proxy "/remote" "http://some.remote.server/remote")))

I am just not able to mix routing system from pedestal with this proxy solution, routes are different, seems like, maybe I will need to do it with a different approach

Disclaimer

  1. I know basic forwarding can be done by nginx, varnish, any other load balancer also. But my idea here is to fill up data from different servers making it simplified for the client
  2. I am a newbie with Clojure, as you may have noticed. And I ran out of options, because google about that is also complicated, sometimes useless

Solution

  • Take a look at ring-request-proxy over here. From the docs:

    (ns myapp.core
      (:require [ring-request-proxy.core :as proxy])
    
    ; Middleware format: Delegates request to handler when request can't be forwarded
    (def app (-> not-found-handler
                 (proxy/proxy-request {:identifier-fn :server-name
                                       :host-fn {"my-server" "http://my-internal-server"}})))
    

    You should be set it as a middleware for all routes you want to proxy.