{"id":15010645,"url":"https://github.com/valpackett/octohipster","last_synced_at":"2025-12-12T01:06:59.907Z","repository":{"id":6765338,"uuid":"8012018","full_name":"valpackett/octohipster","owner":"valpackett","description":"[UNMAINTAINED] A hypermedia REST HTTP API library for Clojure","archived":true,"fork":false,"pushed_at":"2015-07-12T17:10:11.000Z","size":480,"stargazers_count":76,"open_issues_count":0,"forks_count":6,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-12-17T01:58:52.975Z","etag":null,"topics":["clojure","swagger","webmachine"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/valpackett.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-02-04T17:14:20.000Z","updated_at":"2024-05-31T07:49:26.000Z","dependencies_parsed_at":"2022-08-25T10:30:58.107Z","dependency_job_id":null,"html_url":"https://github.com/valpackett/octohipster","commit_stats":null,"previous_names":["myfreeweb/octohipster"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Foctohipster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Foctohipster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Foctohipster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/valpackett%2Foctohipster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/valpackett","download_url":"https://codeload.github.com/valpackett/octohipster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235184249,"owners_count":18949250,"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":["clojure","swagger","webmachine"],"created_at":"2024-09-24T19:35:11.533Z","updated_at":"2025-10-03T20:31:28.235Z","avatar_url":"https://github.com/valpackett.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"Current [semantic](http://semver.org/) version:\n\n```clojure\n[octohipster \"0.2.1-SNAPSHOT\"]\n```\n\n# octohipster [![Build Status](https://travis-ci.org/myfreeweb/octohipster.png?branch=master)](https://travis-ci.org/myfreeweb/octohipster) [![unlicense](https://img.shields.io/badge/un-license-green.svg?style=flat)](http://unlicense.org)\n\nOctohipster is\n\n- a REST library/toolkit/microframework for Clojure\n- that allows you to build HTTP APIs\n- in a declarative [Webmachine](https://github.com/basho/webmachine/wiki/Overview)-like style, using [Liberator](https://github.com/clojure-liberator/liberator)\n- powered by [Ring](https://github.com/ring-clojure/ring); you can add [rate limiting](https://github.com/myfreeweb/ring-ratelimit), [authentication](https://github.com/cemerick/friend), [metrics](http://metrics-clojure.readthedocs.org/en/latest/ring.html), [URL rewriting](https://github.com/ebaxt/ring-rewrite) and more with just middleware\n\nIt allows you to make APIs that\n\n- support hypermedia ([HAL+JSON](http://stateless.co/hal_specification.html), [Collection+JSON](http://amundsen.com/media-types/collection/) and Link/Link-Template HTTP headers; works with [Frenetic](http://dlindahl.github.com/frenetic/))\n- support multiple output formats (JSON, EDN, YAML and any custom format)\n- have [Swagger](https://github.com/wordnik/swagger-core/wiki) documentation \n- use [JSON Schema](http://json-schema.org) for validation *and* documentation\n- have pagination\n\n## Concepts\n\n- a **resource** is a single endpoint that accepts requests and returns responses\n- a **group** is a collection of resources with a single URL prefix (eg. a group /things contains resources /things/ and /things/{id}) and zero or more shared properties (usually the schema)\n- a **documenter** is a function that returns a resource which documents regular resources (Swagger, HAL root, etc)\n- a **mixin** is a function that is applied to multiple resources to give them shared behavior (eg. collection or entry behavior)\n- a **response handler** is a function that is used to encode response data to a particular content-type (JSON, EDN, YAML, etc.)\n- a **params handler** is a function that is used to decode incoming data from a particular content-type (JSON, EDN, YAML, etc.)\n\n## Usage\n\n```clojure\n(ns example\n  (:use [octohipster core routes mixins pagination]\n        [octohipster.documenters swagger schema]\n        org.httpkit.server)\n  (:import org.bson.types.ObjectId)\n  (:require [monger.core :as mg]\n            [monger.query :as mq]\n            [monger.collection :as mc]\n            monger.json))\n\n(mg/connect!)\n(mg/set-db! (mg/get-db \"octohipster-example\"))\n\n;;;; The \"model\"\n;;;;  tip: make it a separate namespace, eg. app.models.contact\n(def contact-schema\n  {:id \"Contact\"\n   :type \"object\"\n   :properties {:name {:type \"string\"}\n                :phone {:type \"integer\"}}\n   :required [:name]})\n\n(defn contacts-count [] (mc/count \"contacts\"))\n(defn contacts-all []\n  (mq/with-collection \"contacts\"\n    (mq/find {})\n    (mq/skip *skip*)\n    (mq/limit *limit*)))\n(defn contacts-find-by-id [x] (mc/find-map-by-id \"contacts\" (ObjectId. x)))\n(defn contacts-insert! [x]\n  (let [id (ObjectId.)]\n    (mc/insert \"contacts\" (assoc x :_id id))\n    (mc/find-map-by-id \"contacts\" id)))\n(defn contacts-update! [x old] (mc/update \"contacts\" old x :multi false))\n(defn contacts-delete! [x] (mc/remove \"contacts\" x))\n\n;;;; The resources\n;; with shared pieces of documentation\n(def name-param\n  {:name \"name\", :dataType \"string\", :paramType \"path\", :required \"true\", :description \"The name of the contact\", :allowMultiple false})\n\n(def body-param\n  {:dataType \"Contact\", :paramType \"body\", :required true, :allowMultiple false})\n\n(defresource contact-collection\n  :desc \"Operations with multiple contacts\"\n  :mixins [collection-resource]\n  :clinks {:item ::contact-item}\n  :data-key :contacts\n  :exists? (fn [ctx] {:contacts (contacts-all)})\n  :post! (fn [ctx] {:item (-\u003e ctx :request :non-query-params contacts-insert!)})\n  :count (fn [req] (contacts-count))\n  :doc {:get {:nickname \"getContacts\", :summary \"Get all contacts\"}\n        :post {:nickname \"createContact\", :summary \"Create a contact\"}})\n\n(defresource contact-item\n  :desc \"Operations with individual contacts\"\n  :url \"/{_id}\"\n  :mixins [item-resource]\n  :clinks {:collection ::contact-collection}\n  :data-key :contact\n  :exists? (fn [ctx]\n             (if-let [doc (-\u003e ctx :request :route-params :_id contacts-find-by-id)]\n               {:contact doc}))\n  :put! (fn [ctx]\n          (-\u003e ctx :request :non-query-params (contacts-update! (:contact ctx)))\n          {:contact (-\u003e ctx :request :route-params :_id contacts-find-by-id)})\n  :delete! (fn [ctx]\n             (-\u003e ctx :contact contacts-delete!)\n             {:contact nil})\n  :doc {:get {:nickname \"getContact\", :summary \"Get a contact\", :parameters [name-param]}\n        :put {:nickname \"updateContact\", :summary \"Overwrite a contact\", :parameters [name-param body-param]}\n        :delete {:nickname \"deleteContact\", :summary \"Delete a contact\", :parameters [name-param]}})\n\n;;;; The group\n(defgroup contact-group\n  :url \"/contacts\"\n  :add-to-resources {:schema contact-schema}  ; instead of typing the same for all resources in the group\n  :resources [contact-collection contact-item])\n\n;;;; The handler\n(defroutes site\n  :groups [contact-group]\n  :documenters [schema-doc schema-root-doc swagger-doc swagger-root-doc])\n\n(defn -main [] (run-server site {:port 8080}))\n```\n\nAlso, [API Documentation](http://myfreeweb.github.com/octohipster) is available.\n\n## Contributing\n\nBy participating in this project you agree to follow the [Contributor Code of Conduct](http://contributor-covenant.org/version/1/1/0/).\n\nPlease take over the whole project!  \nI don't use Clojure a lot nowadays.  \nTalk to me: \u003cgreg@unrelenting.technology\u003e.\n\n## License\n\nThis is free and unencumbered software released into the public domain.  \nFor more information, please refer to the `UNLICENSE` file or [unlicense.org](http://unlicense.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalpackett%2Foctohipster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvalpackett%2Foctohipster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvalpackett%2Foctohipster/lists"}