 
     [[method pathvec verb-fn pipeline]
      [method' (into pathvec pathvec') verb-fn' pipeline']
-     ...]."
+     ...].
+
+  Entries may also take the alternative form of
+
+    [pathvec pipeline? & entries],
+
+  In which case pathvec and pipeline? (if present) will provide a
+  context pathvec and a default pipeline for the nested entries
+  without introducing a separate route."
   [dispatch-table]
-  (letfn [(unnest-entry [[method pathvec verb-fn pipeline
-                          & nested-table
-                          :as entry]]
-            (if nested-table
-              (into [[method pathvec verb-fn pipeline]]
-                (unnest-table pathvec nested-table))
-              [entry]))
-          (unnest-table [context-pathvec entries]
+  (letfn [(unnest-entry [default-pipeline [x :as entry]]
+            (cond
+              (keyword? x)
+              (let [[method pathvec verb-fn pipeline & nested-table] entry]
+                (if nested-table
+                  (into [[method pathvec verb-fn
+                          (or pipeline default-pipeline)]]
+                    (unnest-table pathvec nested-table))
+                  (cond-> [entry]
+                    (nil? pipeline) (assoc-in [0 3] default-pipeline))))
+
+              (vector? x)
+              (let [[context-pathvec & maybe-pipeline+entries] entry
+                    pipeline (if-not (vector? (first maybe-pipeline+entries))
+                               (first maybe-pipeline+entries))
+                    entries  (if pipeline
+                               (next maybe-pipeline+entries)
+                               maybe-pipeline+entries)]
+                (unnest-table context-pathvec pipeline entries))))
+          (unnest-table [context-pathvec default-pipeline entries]
             (mapv (fn [[_ pathvec :as unnested-entry]]
                     (assoc unnested-entry 1 (into context-pathvec pathvec)))
-              (mapcat unnest-entry entries)))]
-    (unnest-table [] dispatch-table)))
+              (mapcat (partial unnest-entry default-pipeline) entries)))]
+    (unnest-table [] nil dispatch-table)))
 
 (defn keywords->symbols
   "Converts keywords in xs to symbols, leaving other items unchanged."

  (:require [clojure.core.match :refer [match]]
            [clojure.string :as string]
            [clojure.pprint :as pp]
            [io.aviso.rook.internals :as internals]))

(defn pprint-code [form]
  (pp/write form :dispatch pp/code-dispatch))

#_
(defmacro define-dispatch-table [name & opts-and-entries]
  (def ~name `(compile-dispatch-table ~@opts-and-entries)))

(defn default-pipeline [handler]
  (-> handler
    rook/wrap-with-function-arg-resolvers
    sv/wrap-with-schema-validation))

(defn namespace-dispatch-table
  "Examines the given namespace and produces a dispatch table in a
  format intelligible to compile-dispatch-table."
  ([ns-sym]
     (namespace-dispatch-table [] ns-sym))
  ([context-pathvec ns-sym]
     (namespace-dispatch-table context-pathvec ns-sym default-pipeline))
  ([context-pathvec ns-sym pipeline]
     (try
       (require ns-sym)
       (catch Exception e
         (throw (ex-info "failed to require ns in namespace-dispatch-table"
                  {:context-pathvec context-pathvec
                   :ns              ns-sym
                   :pipeline        pipeline}
                  e))))
     (let [context-pathvec ((fnil conj [])
                            context-pathvec
                            (peek (string/split (name ns-sym) #"\.")))]
       [(->> ns-sym
          ns-publics
          (keep (fn [[k v]]
                  (if (ifn? @v)
                    (if-let [route-spec (or (:route-spec (meta v))
                                            (get default-mappings k))]
                      (conj route-spec (symbol (name ns-sym) (name k)))))))
          (list* context-pathvec pipeline)
          vec)])))
