-
-
Save weavejester/b999f5cd1365cd7bc4b7 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; I'd begin by using protocols to define the I/O boundaries of the endpoint. | |
;; The protocols can be extended to support the database and mailer component | |
;; when in production, and for testing a mock implementation can be used instead. | |
(defprotocol UsersDatabase | |
(authenticate [db credentials]) | |
(create-user [db user])) | |
(defprotocol Mailer | |
(send-email [mailer email])) | |
;; The most straightforward way to pattern the login and register functions | |
;; would be to have two arguments: | |
(defn login [{:keys [db]} request] ...) | |
(defn register [{:keys [db mailer]} request] ...) | |
;; So the first argument is the map of components map, and the second argument | |
;; the Ring request map. | |
(defn accounts-endpoint [{:keys [db] :as components}] | |
(routes | |
(POST "/login" [] | |
(-> (partial login components) | |
(wrap-credentials-pass? db) | |
(wrap-validates? LoginRequest))) | |
(POST "/users" [] | |
(-> (partial register components) | |
(wrap-taken? db) | |
(wrap-validates? RegisterRequest))))) | |
;; However, this design involves functions being given more information than | |
;; they strictly need. We don't need to give every function all the components, | |
;; nor do they require the entire request map in order to formulate a response. | |
;; Ideally we want functions to be passed only the information they need. So | |
;; with that in mind, we can rewrite the function signatures: | |
(defn login [db credentials] ...) | |
(defn register [db mailer user] ...) | |
;; And the endpoint: | |
(defn accounts-endpoint [{:keys [db mailer]}] | |
(routes | |
(POST "/login" {body :body} (login db body)) | |
(POST "/users" {body :body} (register db mailer body)))) | |
;; Like the protocols, this establishes a boundary in the application. The | |
;; login and register functions are given only the information necessary | |
;; for their operation. | |
;; This design does preclude the use of Ring middleware to extend the | |
;; controller functions, as in your original design. But I'm not sure that | |
;; middleware is not necessarily the right choice in this case. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment