{"id":15010347,"url":"https://github.com/akeboshiwind/tg-clj-server","last_synced_at":"2026-02-01T12:32:59.494Z","repository":{"id":226022265,"uuid":"767489852","full_name":"Akeboshiwind/tg-clj-server","owner":"Akeboshiwind","description":"A more framework-y library for use with tg-clj inspired by ring web-servers.","archived":false,"fork":false,"pushed_at":"2024-05-31T10:09:50.000Z","size":48,"stargazers_count":3,"open_issues_count":3,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T01:15:14.043Z","etag":null,"topics":["clojure","framework","telegram","telegram-bot","telegram-bot-api"],"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/Akeboshiwind.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"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}},"created_at":"2024-03-05T11:42:06.000Z","updated_at":"2025-03-02T11:38:12.000Z","dependencies_parsed_at":"2024-03-05T14:25:17.170Z","dependency_job_id":"8bd73557-02f9-423e-a442-9644b6d57633","html_url":"https://github.com/Akeboshiwind/tg-clj-server","commit_stats":null,"previous_names":["akeboshiwind/tg-clj-server"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akeboshiwind%2Ftg-clj-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akeboshiwind%2Ftg-clj-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akeboshiwind%2Ftg-clj-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akeboshiwind%2Ftg-clj-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Akeboshiwind","download_url":"https://codeload.github.com/Akeboshiwind/tg-clj-server/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246009988,"owners_count":20709043,"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","framework","telegram","telegram-bot","telegram-bot-api"],"created_at":"2024-09-24T19:33:40.054Z","updated_at":"2026-02-01T12:32:59.489Z","avatar_url":"https://github.com/Akeboshiwind.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tg-clj-server\n\nA more framework-y library for use with [tg-clj](https://github.com/Akeboshiwind/tg-clj) inspired by [ring](https://github.com/ring-clojure/ring) web-servers.\n\n\u003cp\u003e\n  \u003ca href=\"#installation\"\u003eInstallation\u003c/a\u003e |\n  \u003ca href=\"#getting-started\"\u003eGetting Started\u003c/a\u003e |\n  \u003ca href=\"examples/\"\u003eExamples\u003c/a\u003e |\n  \u003ca href=\"docs/intro.md\"\u003eIntroduction\u003c/a\u003e |\n  \u003ca href=\"docs/defaults.md#simple-store\"\u003ePersistent Storage\u003c/a\u003e |\n  \u003ca href=\"https://github.com/Akeboshiwind/tg-clj\"\u003etg-clj\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e [!CAUTION]\n\u003e `tg-clj-server` and `tg-clj` are considered alpha!\n\u003e\n\u003e I'll put a warning in the [changelog](/CHANGELOG.md) when a breaking change happens.\n\u003e This warning will be removed once I consider the API stable.\n\n\n\n## Why\n\nWhen writing a bot that's more complicated than a few `:sendMessage`s, it's much\nnicer (and more testable) to build it out of modular components:\n\n```clojure\n(defn hello-handler [{u :update}]\n  {:op :sendMessage\n   :request {:text \"Hi! 🤖\"\n             :chat_id (get-in u [:message :chat :id])}})\n\n(defn reply-handler [{u :update}]\n  (-\u003e {:op :sendMessage\n       :request {:text \"Message received 📨\"}}\n      (u/reply-to u)))\n\n(def routes\n  [[\"/hello\" #'hello-handler]\n   [(constantly true) #'reply-handler]])\n\n;; The client timeout must be greater than the getUpdates timeout (default to 30s)\n(let [client (tg/make-client {:token \"\u003cyour token\u003e\" :timeout 35000})\n      app (defaults/make-app routes)]\n  (def stop (tg-poll/run-server client app)))\n```\n\nFor the full bot see `/examples/simple.clj`.\n\n\n\n## Installation\n\nUse as a dependency in `deps.edn` or `bb.edn`:\n\n```clojure\nio.github.akeboshiwind/tg-clj-server {:git/tag \"v0.4.0\" :git/sha \"dfb7160\"}\n```\n\n\n\n## Getting Started\n\nTo get things setup you'll need some routes:\n\n```clojure\n(require '[tg-clj-server.utils :as u])\n\n(defn poll? [request]\n  (get-in request [:update :message :poll]))\n\n(def routes\n  [; A route is made up of:\n   ; - A predicate that takes a request\n   ; - Route-data which must contain a `:handler` function\n   [poll?\n    {:handler (fn [{u :update}]\n                ; Return a map with an :op key to automatically call `tg-clj/invoke`\n                (-\u003e {:op :sendMessage\n                     :request {:text \"Woah, that's a poll!\"}}\n                    ; We have a handy util for replying to a message directly\n                    (u/reply-to u)))}]\n   ; As syntactic sugar:\n   ; - A handler function\n   [\"/command\"\n    (fn [{u :update}]\n      (-\u003e {:op :sendMessage\n           :request {:text \"Woah, that's a command!\"}}\n          (u/reply-to u)))]])\n```\n\nThen you'll need to create an `app` with those routes:\n\n```clojure\n(require '[tg-clj-server.defaults.poll :as defaults])\n\n(def app\n  (defaults/make-app routes {; You can supply additional middleware here\n                             :middleware []\n                             ; You can set options on provided middleware like so\n                             ; (The store is in-memory only by default)\n                             :store/path \"/path/to/store.edn\"}))\n```\n\n`defaults/make-app` provides some handy middleware like [simple-router](docs/intro.md#routing) and [invoke](docs/included-middleware.md#invoke). It's not required, see `examples/no_defaults.clj`\n\nThen finally you can run the server with a client:\n\n```clojure\n(require '[tg-clj.core :as tg]\n         '[tg-clj-server.poll :as tg-poll])\n\n(def client (tg/make-client {:token \"\u003cyour token\u003e\" :timeout 35000}))\n(def stop (tg-poll/run-server client app))\n\n; Block forever\n@(promise)\n```\n\nFor graceful shutdown on Ctrl+C:\n\n```clojure\n(def stop (tg-poll/run-server client app))\n(.addShutdownHook (Runtime/getRuntime) (Thread. stop))\n@(promise)\n```\n\nAnd that's it! Try out your new bot 🤖\n\nFor some complete bots take a look at the `/examples` folder.\n\nIf you want to learn more start at the [intro](docs/intro.md).\n\n\n\n## Dev\n\n`clj -M:dev`\n\nTo run tests:\n\n`clj -X:dev:test`\n\n\n\n## Releasing\n\n1. Tag the commit `v\u003cversion\u003e`\n2. `git push --tags`\n3. Update the README.md with the new version and git hash\n4. Update the CHANGELOG.md\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakeboshiwind%2Ftg-clj-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakeboshiwind%2Ftg-clj-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakeboshiwind%2Ftg-clj-server/lists"}