         took (- stop start)]
     (assoc result :took took)))
 
-(defn- find-references
+(def extension->mime-type
+  "A map of URL file extensions to the mime type they represent."
+  {"json" "application/json"
+   "xml" "application/xml"
+   "echo10" "application/echo10+xml"
+   "iso_prototype" "application/iso_prototype+xml"
+   "smap_iso" "application/iso:smap+xml"
+   "iso19115" "application/iso19115+xml"
+   "dif" "application/dif+xml"
+   "csv" "text/csv"})
+
+(defn- parse-concept-type-w-extension
+  "Parses the concept type and extension (\"granules.echo10\") into a pair of concept type keyword
+  and mime type"
+  [concept-type-w-extension]
+  (let [[_ concept-type extension]
+        (filter
+          identity
+          (re-matches #"^(.+)s(?:\.(.+))?$" concept-type-w-extension))
+        mime-type (extension->mime-type extension)]
+    (when (and (nil? mime-type) (some? extension))
+      (svc-errors/throw-service-error
+        :bad-request (format "The URL extension [%s] is not supported." extension)))
+    [(keyword concept-type)
+     mime-type]))
+
+(defn- get-search-results-format
+  "Returns the requested search results format parsed from headers or from the URL extension"
+  [ext-mime-type headers]
+  (let [mime-type (or ext-mime-type (get headers "accept"))]
+    (mt/validate-request-mime-type mime-type sr/supported-mime-types)
+    (mt/mime-type->format mime-type)))
+
+(defn- find-concepts
   "Invokes query service to find references and returns the response"
-  [context concept-type params headers query-string]
-  (let [result-format (get-search-results-format headers)
+  [context concept-type-w-extension params headers query-string]
+  (let [[concept-type ext-mime-type] (parse-concept-type-w-extension concept-type-w-extension)
+        params (dissoc params :concept-type-w-extension)
+        result-format (get-search-results-format ext-mime-type headers)
         params (assoc params :result-format result-format)
         pretty? (= (get params :pretty) "true")
         _ (info (format "Searching for %ss in format %s with params %s." (name concept-type) result-format (pr-str params)))

     :headers {"Content-Type" "application/xml; charset=utf-8"}
     :body (:metadata concept)}))

(defn- build-routes [system]
  (routes
    (context (get-in system [:search-public-conf :relative-root-url]) []
      (context "/collections" []
        (GET "/" {params :params headers :headers context :request-context query-string :query-string}
          (find-references context :collection params headers query-string))
        (POST "/" {params :params headers :headers context :request-context body :body-copy}
          (find-references context :collection params headers body)))
      (context "/granules" []
        (GET "/" {params :params headers :headers context :request-context query-string :query-string}
          (find-references context :granule params headers query-string))
        (POST "/" {params :params headers :headers context :request-context body :body-copy}
          (find-references context :granule params headers body)))
      (context "/concepts/:cmr-concept-id" [cmr-concept-id]
        (GET "/" {headers :headers context :request-context}
          (find-concept-by-cmr-concept-id context cmr-concept-id headers)))

      ;; reset operation available just for development purposes
      ;; clear the cache for search app

            [ring.middleware.json :as ring-json]
            [cmr.common.log :refer (debug info warn error)]
            [cmr.common.api.errors :as errors]
            [cmr.common.services.errors :as svc-errors]
            [cmr.common.mime-types :as mt]
            [cmr.search.services.query-service :as query-svc]
            [cmr.system-trace.http :as http-trace]
            [cmr.search.api.search-results :as sr]
            [cmr.search.services.parameters.legacy-parameters :as lp]))


(defn- measure-query-time
  "Executes the query function measuring how long it takes. Adds a :took key to the results map
