{"id":15637165,"url":"https://github.com/oliyh/pedestal-api","last_synced_at":"2025-10-06T15:25:23.490Z","repository":{"id":62434253,"uuid":"50683144","full_name":"oliyh/pedestal-api","owner":"oliyh","description":"Easily build APIs in Pedestal using Schema and Swagger","archived":false,"fork":false,"pushed_at":"2024-03-30T22:50:59.000Z","size":91,"stargazers_count":111,"open_issues_count":9,"forks_count":13,"subscribers_count":9,"default_branch":"master","last_synced_at":"2025-03-30T07:11:15.203Z","etag":null,"topics":["api","api-server","clojure","http","http-server","pedestal","pedestal-api","swagger"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oliyh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["oliyh"]}},"created_at":"2016-01-29T18:42:41.000Z","updated_at":"2025-02-07T02:20:16.000Z","dependencies_parsed_at":"2024-06-20T00:07:06.272Z","dependency_job_id":"db5c41c8-50dd-4c3e-9583-f032c4a86696","html_url":"https://github.com/oliyh/pedestal-api","commit_stats":{"total_commits":92,"total_committers":3,"mean_commits":"30.666666666666668","dds":0.06521739130434778,"last_synced_commit":"09b2fcf742531c4626664f066ea88285dd32c7de"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliyh%2Fpedestal-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliyh%2Fpedestal-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliyh%2Fpedestal-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliyh%2Fpedestal-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oliyh","download_url":"https://codeload.github.com/oliyh/pedestal-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457801,"owners_count":20941906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","api-server","clojure","http","http-server","pedestal","pedestal-api","swagger"],"created_at":"2024-10-03T11:10:33.022Z","updated_at":"2025-10-06T15:25:23.412Z","avatar_url":"https://github.com/oliyh.png","language":"Clojure","funding_links":["https://github.com/sponsors/oliyh"],"categories":[],"sub_categories":[],"readme":"# pedestal-api\nA batteries-included API for Pedestal using Swagger.\n\n**pedestal-api** is a library for building APIs on the pedestal web server.\nIt implements the parts of HTTP that are useful for APIs and allows you to document your handlers and middleware\nusing idiomatic Clojure and generate a compliant Swagger specification.\n\n[![Clojars Project](https://img.shields.io/clojars/v/pedestal-api.svg)](https://clojars.org/pedestal-api)\n\nThe [example code](https://github.com/oliyh/pedestal-api/tree/master/example) can be seen at https://pedestal-api.oliy.co.uk\n\n## Features\n\n* A [Swagger](http://swagger.io) API with input and output validation and coercion as provided by [route-swagger](https://github.com/frankiesardo/route-swagger).\n* Content deserialisation, including:\n  * `application/json`\n  * `application/edn`\n  * `application/transit+json`\n  * `application/transit+msgpack`\n  * `application/x-www-form-urlencoded`\n* Content negotiation, including:\n  * `application/json`\n  * `application/edn`\n  * `application/transit+json`\n  * `application/transit+msgpack`\n* Human-friendly error messages when schema validation fails\n  * e.g. `{:error {:body-params {:age \"(not (integer? abc))\"}}}`\n* Convenience functions for annotating routes and interceptors\n\n## Flexibility\n\npedestal-api is built on top of [route-swagger](https://github.com/frankiesardo/route-swagger) which can still\nbe used directly if more flexibility is needed. Interceptors are provided but not wired in, allowing you to choose\nthose which suit you best.\n\n## Example\n\nThe [example code](https://github.com/oliyh/pedestal-api/tree/master/example) (reproduced below)\ncan be seen running on Heroku at https://pedestal-api.oliy.co.uk\n\n```clojure\n(ns pedestal-api-example.service\n  (:require [io.pedestal.http :as bootstrap]\n            [io.pedestal.interceptor.chain :refer [terminate]]\n            [io.pedestal.interceptor :refer [interceptor]]\n            [pedestal-api\n             [core :as api]\n             [helpers :refer [before defbefore defhandler handler]]]\n            [schema.core :as s])\n  (:import java.util.UUID))\n\n(defonce the-pets (atom {}))\n\n(s/defschema Pet\n  {:name s/Str\n   :type s/Str\n   :age s/Int})\n\n(s/defschema PetWithId\n  (assoc Pet (s/optional-key :id) s/Uuid))\n\n(def all-pets\n  \"Example of annotating a generic interceptor\"\n  (api/annotate\n   {:summary     \"Get all pets in the store\"\n    :parameters  {:query-params {(s/optional-key :sort) (s/enum :asc :desc)}}\n    :responses   {200 {:body {:pets [PetWithId]}}}\n    :operationId :all-pets}\n   (interceptor\n    {:name  ::all-pets\n     :enter (fn [ctx]\n              (assoc ctx :response\n                     {:status 200\n                      :body {:pets (let [sort (get-in ctx [:request :query-params :sort])]\n                                     (cond-\u003e\u003e (vals @the-pets)\n                                       sort (sort-by :name)\n                                       (= :desc sort) reverse))}}))})))\n\n(def create-pet\n  \"Example of using the handler helper\"\n  (handler\n   ::create-pet\n   {:summary     \"Create a pet\"\n    :parameters  {:body-params Pet}\n    :responses   {201 {:body {:id s/Uuid}}}\n    :operationId :create-pet}\n   (fn [request]\n     (let [id (UUID/randomUUID)]\n       (swap! the-pets assoc id (assoc (:body-params request) :id id))\n       {:status 201\n        :body {:id id}}))))\n\n;; Example using the defbefore helper\n(defbefore load-pet\n  {:summary    \"Load a pet by id\"\n   :parameters {:path-params {:id s/Uuid}}\n   :responses  {404 {:body s/Str}}}\n  [{:keys [request] :as context}]\n  (if-let [pet (get @the-pets (get-in request [:path-params :id]))]\n    (update context :request assoc :pet pet)\n    (-\u003e context terminate (assoc :response {:status 404\n                                            :body \"No pet found with this id\"}))))\n\n;; Example of using the defhandler helper\n(defhandler get-pet\n  {:summary     \"Get a pet by id\"\n   :parameters  {:path-params {:id s/Uuid}}\n   :responses   {200 {:body PetWithId}\n                 404 {:body s/Str}}\n   :operationId :get-pet}\n  [{:keys [pet] :as request}]\n  {:status 200\n   :body pet})\n\n(def update-pet\n  \"Example of using the before helper\"\n  (before\n   ::update-pet\n   {:summary     \"Update a pet\"\n    :parameters  {:path-params {:id s/Uuid}\n                  :body-params Pet}\n    :responses   {200 {:body s/Str}}\n    :operationId :update-pet}\n   (fn [{:keys [request]}]\n     (swap! the-pets update (get-in request [:path-params :id]) merge (:body-params request))\n     {:status 200\n      :body \"Pet updated\"})))\n\n(def delete-pet\n  \"Example of annotating a generic interceptor\"\n  (api/annotate\n   {:summary     \"Delete a pet by id\"\n    :parameters  {:path-params {:id s/Uuid}}\n    :responses   {200 {:body s/Str}}\n    :operationId :delete-pet}\n   (interceptor\n    {:name  ::delete-pet\n     :enter (fn [ctx]\n              (let [pet (get-in ctx [:request :pet])]\n                (swap! the-pets dissoc (:id pet))\n                (assoc ctx :response\n                       {:status 200\n                        :body (str \"Deleted \" (:name pet))})))})))\n\n(s/with-fn-validation\n  (api/defroutes routes\n    {:info {:title       \"Swagger Sample App built using pedestal-api\"\n            :description \"Find out more at https://github.com/oliyh/pedestal-api\"\n            :version     \"2.0\"}\n     :tags [{:name         \"pets\"\n             :description  \"Everything about your Pets\"\n             :externalDocs {:description \"Find out more\"\n                            :url         \"http://swagger.io\"}}\n            {:name        \"orders\"\n             :description \"Operations about orders\"}]}\n    [[[\"/\" ^:interceptors [api/error-responses\n                           (api/negotiate-response)\n                           (api/body-params)\n                           api/common-body\n                           (api/coerce-request)\n                           (api/validate-response)]\n       [\"/pets\" ^:interceptors [(api/doc {:tags [\"pets\"]})]\n        [\"/\" {:get all-pets\n              :post create-pet}]\n        [\"/:id\" ^:interceptors [load-pet]\n         {:get get-pet\n          :put update-pet\n          :delete delete-pet}]]\n\n       [\"/swagger.json\" {:get api/swagger-json}]\n       [\"/*resource\" {:get api/swagger-ui}]]]]))\n\n(def service\n  {:env                      :dev\n   ::bootstrap/routes        #(deref #'routes)\n   ;; linear-search, and declaring the swagger-ui handler last in the routes,\n   ;; is important to avoid the splat param for the UI matching API routes\n   ::bootstrap/router        :linear-search\n   ::bootstrap/resource-path \"/public\"\n   ::bootstrap/type          :jetty\n   ::bootstrap/port          8080\n   ::bootstrap/join?         false})\n```\n\n## Build\n[![Circle CI](https://circleci.com/gh/oliyh/pedestal-api.svg?style=svg)](https://circleci.com/gh/oliyh/pedestal-api)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliyh%2Fpedestal-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foliyh%2Fpedestal-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliyh%2Fpedestal-api/lists"}