     (str/join "/")
     (str "/")))
 
-(defn default-path-item-object-constructor
+;; Revisit order of parameters in these for ease of ->> threading; should swagger-object always be the last?
+
+(defn default-path-params-injector
+  "Identifies each path parameter and adds a value for it to the swagger-object at the path defined by params-key."
+  [swagger-options swagger-object routing-entry params-key]
+  (let [path-ids (->> routing-entry :path (filter keyword?))
+        reducer (fn [so path-id]
+                  (update-in so params-key
+                             conj {:name     path-id
+                                   :in       :path
+                                   :required :true}))]
+    (reduce reducer swagger-object path-ids)))
+
+(defn default-query-params-injector
+  "Identifies each query parameter via the :query-schema metadata and injects it."
+  [swagger-options swagger-object routing-entry params-key]
+  (if-let [schema (-> routing-entry :meta :query-schema)]
+    ;; Assumes that the schema is a map.
+    (let [reducer (fn [so [key-id key-schema]]
+                    (cond-let
+                      ;; Just ignore these, they are a convinience for the caller ("be generous in what you accept").
+                      (= s/Any key-id)
+                      so
+
+                      [[k required] (cond (s/optional-key? key-id)
+                                          [(.k key-id) false]
+
+                                          (s/required-key? key-id)
+                                          [(.k key-id) true]
+
+                                          (keyword? key-id)
+                                          [key-id true]
+
+                                          :else
+                                          (throw (ex-info (format "No idea what to do with query schema key %s." key-id)
+                                                          {:routing-entry routing-entry
+                                                           :key-id        key-id
+                                                           :key-schema    key-schema})))]
+
+                      :else
+                      (update-in so params-key
+                                 conj {:name     k
+                                       :in       :query
+                                       :required required})))]
+      (reduce reducer swagger-object schema))
+    ; no :query-schema
+    swagger-object))
+
+(defn schema->swagger-schema
+  [swagger-options schema]
+  ;; To be done!
+  (medley/remove-vals nil?
+                      {:required   []
+                       :description (-> schema meta :doc)
+                       :properties {}}))
+
+(defn to-schema-reference
+  "Converts a schema to a schema reference; the schema must be named.  Returns a tuple
+  of the possibly updated swagger object and a string reference to the schema within the swagger object
+  (as a path string)."
+  ;; TODO: return the {:schema {"$ref" ...}} map instead?
+  [swagger-options swagger-object schema]
+  (cond-let
+    [schema-name (s/schema-name schema)
+     schema-ns (-> schema meta :ns)]
+
+    (or (nil? schema-name) (nil? schema-ns))
+    (throw (ex-info "Unable to create a Swagger schema from an anonymous Prismatic schema."
+                    schema))
+
+    ;; Avoid forward slash in the swagger name, as that's problematic.
+    [swagger-name (str schema-ns \: schema-name)
+     swagger-reference (str "#/definitions/" swagger-name)
+     swagger-schema (get-in swagger-object [:definitions swagger-name])]
+
+    (some? swagger-schema)
+    [swagger-object swagger-reference]
+
+    [new-schema (schema->swagger-schema swagger-options schema)
+     swagger-object' (assoc-in swagger-object [:definitions swagger-name] new-schema)]
+
+    :else
+    [swagger-object' swagger-reference]))
+
+(defn default-body-params-injector
+  "Uses the :body-schema metadata to identify the body params."
+  [swagger-options swagger-object routing-entry paths-key]
+  (if-let [schema (-> routing-entry :meta :body-schema)]
+
+    ;; Assumption: it's a map and named
+    (let [[swagger-object' schema-reference] (to-schema-reference swagger-options swagger-object schema)]
+      (update-in swagger-object' paths-key
+                 conj {:name     :request-body
+                       :in       :body
+                       :required true
+                       :schema   {"$ref" schema-reference}}))
+    ; no schema:
+    swagger-object))
+
+(defn default-path-item-object-injector
+  "Injects a PathItemObject based on a routing entry.
+
+  The paths-key is a coordinate into the swagger-object where the PathItemObject should be created.
+
+  Returns the modified swagger-object. "
   [swagger-options swagger-object routing-entry paths-key]
   (let [{endpoint-meta :meta} routing-entry
         swagger-meta (:swagger endpoint-meta)
         description (or (:description swagger-meta)
                         (:doc endpoint-meta))
-        summary (:summary swagger-meta)]
-    (assoc-in swagger-object paths-key
-              (medley/remove-vals nil?
-                                  {:description description
-                                   :summary summary
-                                   :operation-id (:function endpoint-meta)}))))
-
-(defn default-route-converter
+        summary (:summary swagger-meta)
+        path-params-injector (:path-params-injector swagger-options default-path-params-injector)
+        query-params-injector (:query-params-injector swagger-options default-query-params-injector)
+        body-params-injector (:body-params-injector swagger-options default-body-params-injector)
+        params-key (concat paths-key ["parameters"])]
+    (as-> swagger-object %
+          (assoc-in % paths-key
+                    (medley/remove-vals nil?
+                                        {:description  description
+                                         :summary      summary
+                                         :operation-id (:function endpoint-meta)}))
+          (path-params-injector swagger-options % routing-entry params-key)
+          (query-params-injector swagger-options % routing-entry params-key)
+          (body-params-injector swagger-options % routing-entry params-key)
+          (update-in % params-key #(sort-by :name %)))))
+
+(defn default-route-injector
   "The default route converter.  The swagger-options may contain an override of this function.
 
   swagger-options

  (:require [schema.core :as s]
            [clojure.string :as str]
            [medley.core :as medley]
            [io.aviso.toolchest.collections :refer [pretty-print]]
            [clojure.tools.logging :as l]))


  [swagger-options routing-table]
  (let [{:keys [skeleton route-converter]
         :or   {skeleton        default-swagger-skeleton
                route-converter default-route-injector}} swagger-options]
    (->> routing-table
         vals
         (apply concat)
         (map routing-entry->map)
         ;; Add the :no-swagger meta data to edit it out.
         (remove #(-> % :meta :no-swagger))
         (reduce (partial route-converter swagger-options) skeleton))))