{"id":20709013,"url":"https://github.com/difrex/zoorest","last_synced_at":"2025-07-18T06:34:33.324Z","repository":{"id":57559399,"uuid":"82281509","full_name":"Difrex/zoorest","owner":"Difrex","description":"Zookeeper REST API","archived":false,"fork":false,"pushed_at":"2020-02-11T08:52:31.000Z","size":70,"stargazers_count":18,"open_issues_count":1,"forks_count":8,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-23T02:54:02.063Z","etag":null,"topics":["api","docker","json","rest-api","zookeeper"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Difrex.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-02-17T09:39:41.000Z","updated_at":"2023-03-15T21:17:39.000Z","dependencies_parsed_at":"2022-08-28T14:02:57.590Z","dependency_job_id":null,"html_url":"https://github.com/Difrex/zoorest","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/Difrex/zoorest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Difrex%2Fzoorest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Difrex%2Fzoorest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Difrex%2Fzoorest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Difrex%2Fzoorest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Difrex","download_url":"https://codeload.github.com/Difrex/zoorest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Difrex%2Fzoorest/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265710895,"owners_count":23815428,"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","docker","json","rest-api","zookeeper"],"created_at":"2024-11-17T01:34:31.918Z","updated_at":"2025-07-18T06:34:33.278Z","avatar_url":"https://github.com/Difrex.png","language":"Go","readme":"# Zoorest\n[![Build Status](https://travis-ci.org/Difrex/zoorest.svg?branch=master)](https://travis-ci.org/Difrex/zoorest)\n\nZookeeper REST API\n\u003c!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --\u003e\n**Table of Contents**\n\n- [Zoorest](#zoorest)\n    - [Usage](#usage)\n    - [CORS](#cors)\n    - [API v1](#api-v1)\n        - [List node childrens](#list-node-childrens)\n            - [Errors](#errors)\n        - [Get node data](#get-node-data)\n            - [Errors](#errors-1)\n        - [Get node data as JSON](#get-node-data-as-json)\n            - [Errors](#errors-2)\n        - [Create node recursive](#create-node-recursive)\n        - [Create node children](#create-node-children)\n            - [Errors](#errors-3)\n        - [Update node](#update-node)\n            - [Errors](#errors-4)\n        - [Delete node recursive](#delete-node-recursive)\n    - [API v2](#api-v2)\n        - [List node childrens](#list-node-childrens-1)\n            - [Errors](#errors-5)\n        - [Get node data](#get-node-data-1)\n            - [Errors](#errors-6)\n        - [Get node data as JSON](#get-node-data-as-json-1)\n            - [Errors](#errors-7)\n        - [Create node recursive](#create-node-recursive-1)\n        - [Create node children](#create-node-children-1)\n            - [Errors](#errors-8)\n        - [Update node](#update-node-1)\n            - [Errors](#errors-9)\n        - [Delete node recursive](#delete-node-recursive-1)\n            - [Errors](#errors-10)\n    - [Build](#build)\n        - [Binary](#binary)\n        - [Docker build](#docker-build)\n            - [Binary file](#binary-file)\n            - [Docker image](#docker-image)\n    - [Get docker image](#get-docker-image)\n- [AUTHORS](#authors)\n- [LICENSE](#license)\n- [DONATE](#donate)\n\n\u003c!-- markdown-toc end --\u003e\n\n## Usage\n\n```\nUsage of ./zoorest:\n  -listen string\n    \tAddress to listen (default \"127.0.0.1:8889\")\n  -mc\n    \tEnable memcached support\n  -mchosts string\n    \tMemcached servers. Comma separated (default \"127.0.0.1:11211\")\n  -mcprefix string\n    \tMemcached key prefix (default \"zoorest\")\n  -path string\n    \tZk root path (default \"/\")\n  -zk string\n    \tZk servers. Comma separated (default \"127.0.0.1:2181\")\n```\n\nNOTE: If memcached support is enabled zkStat metrics will not be returned.\n\nTypical usage scheme:\n\n[![tupical usage](img/usage.png)](img/usage.png)\n\n### CORS\n`Cross-origin resource sharing` is a feature that securely allows access to a zoorest instance from a web browser.   This is an optional feature and is disabled by default.  It is enabled and configured via OS environment variables.\n\n**ZOOREST_CORS_ENABLE**\n    enable the feature.  Any non-empty value is considered \"true\" and enables it.\n    **default:  false**\n\n**ZOOREST_CORS_DEBUG_ENABLE**\n    enable CORS debug mode Any non-null value is considered \"true\" and enables it.\n    **default: false**\n\n**ZOOREST_CORS_ALLOWED_ORIGINS**\n    comma delimited list of origin url patterns to allow access to the service.\n    **default: \\***    (any origin)\n\n## API v1\n\n### List node childrens\n\nMethod: **GET**\n\nLocation: **/v1/ls**\n\nReturn JSON\n```json\ncurl -s -XGET http://127.0.0.1:8889/v1/ls/ | jq\n{\n  \"childrens\": [\n    \"two\",\n    \"three\",\n    \"one\"\n  ],\n  \"path\": \"/zoorest\",\n  \"state\": \"OK\",\n  \"error\": \"\"\n}\n```\n\n#### Errors\n\n```json\ncurl -s -XGET http://127.0.0.1:8889/v1/ls/does/not/exist | jq\n{\n  \"childrens\": null,\n  \"path\": \"\",\n  \"state\": \"ERROR\",\n  \"error\": \"zk: node does not exist\"\n}\n```\n\n### Get node data\n\nMethod: **GET**\n\nLocation: **/v1/get**\n\nReturn JSON\n```\ncurl -s -XGET http://127.0.0.1:8889/v1/get/one/data | jq\n{\n  \"path\": \"/zoorest/one/data\",\n  \"state\": \"OK\",\n  \"error\": \"\",\n  \"data\": \"eyJzb21lIjogImpzb24ifQ==\"\n}\n```\nNode data stored in *data* field as base64 encoded string\n```\necho eyJzb21lIjogImpzb24ifQ== | base64 -d\n{\"some\": \"json\"}\n```\n\n#### Errors\n\n```json\n curl -s -XGET http://127.0.0.1:8889/v1/get/does/not/exist | jq\n{\n  \"path\": \"\",\n  \"state\": \"ERROR\",\n  \"error\": \"zk: node does not exist\",\n  \"data\": null\n}\n```\n\n### Get node data as JSON\n\nMethod: **GET**\n\nLocation: **/v1/get/path/to/node+json**\n\nSimple add to the end of the path `+json`\nReturn JSON\n```\ncurl -s -XGET http://127.0.0.1:8889/v1/json/one/data+json | jq\n{\n  \"path\": \"/json/one/data\",\n  \"state\": \"OK\",\n  \"error\": \"\",\n  \"zkstat\": {\n    \"Czxid\": 45,\n    \"Mzxid\": 55,\n    \"Ctime\": 1564645641612,\n    \"Mtime\": 1564646317882,\n    \"Version\": 6,\n    \"Cversion\": 0,\n    \"Aversion\": 0,\n    \"EphemeralOwner\": 0,\n    \"DataLength\": 28,\n    \"NumChildren\": 0,\n    \"Pzxid\": 45\n  },\n  \"data\": {\n    \"ok\": true,\n    \"some\": \"data\"\n  }\n}\n```\n\n#### Errors\n\n```json\ncurl -s -XGET http://127.0.0.1:8889/v1/get/invalid/json+json | jq\n{\n  \"path\": \"/invalid/json\",\n  \"state\": \"ERROR\",\n  \"error\": \"JSON parsing failure: invalid character 'i' looking for beginning of value\",\n  \"zkstat\": {\n    \"Czxid\": 45,\n    \"Mzxid\": 56,\n    \"Ctime\": 1564645641612,\n    \"Mtime\": 1564646350753,\n    \"Version\": 7,\n    \"Cversion\": 0,\n    \"Aversion\": 0,\n    \"EphemeralOwner\": 0,\n    \"DataLength\": 17,\n    \"NumChildren\": 0,\n    \"Pzxid\": 45\n  },\n  \"data\": null\n}\n```\n\n### Create node recursive\n\nMethod: **PUT**\n\nLocation: **/v1/up**\n\nReturn string with created path\n```\ncurl -XPUT http://127.0.0.1:8889/v1/up/two/three/four -d '{\"four\": \"json\"}'\n/zoorest/two/three/four\n```\n\n### Create node children\n\nMethod: **PATCH**\n\nLocation: **/v1/up**\n\nReturn string with created children path\n```\ncurl -XPATCH http://127.0.0.1:8889/v1/up/one/test -d 'test'\n/one/test\n```\n\n#### Errors\n\n```\ncurl -XPATCH http://127.0.0.1:8889/v1/up/six/test -d '{\"six\": \"json\"}'\nzk: node does not exist\n```\n\n### Update node\n\nMethod: **POST**\n\nLocation: **/v1/up**\n\nReturn string with updated path\n```\ncurl -XPOST http://127.0.0.1:8889/v1/up/two -d '{\"two\": \"json\"}'\n/zoorest/two\n```\n\n#### Errors\n\n```\ncurl -XPOST http://127.0.0.1:8889/v1/up/twa -d '{\"two\": \"json\"}'\nzk: node does not exist\n```\n\n### Delete node recursive\nMethod: **DELETE**\n\nLocation: **/v1/rmr**\n\nReturn string with removed path\n```\ncurl -XDELETE http://127.0.0.1:8889/v1/rmr/two\n/zoorest/two\n```\n\n## API v2\n\n### List node childrens\n\nMethod: **LIST**\n\nReturn JSON\n```json\ncurl -s -XGET http://127.0.0.1:8889/v2/ | jq\n{\n  \"childrens\": [\n    \"two\",\n    \"three\",\n    \"one\"\n  ],\n  \"path\": \"/zoorest\",\n  \"state\": \"OK\",\n  \"error\": \"\"\n}\n```\n\n#### Errors\n\n```json\ncurl -s -XGET http://127.0.0.1:8889/v2/does/not/exist | jq\n{\n  \"childrens\": null,\n  \"path\": \"\",\n  \"state\": \"ERROR\",\n  \"error\": \"zk: node does not exist\"\n}\n```\n\n### Get node data\n\nMethod: **GET**\n\nReturn JSON\n```\ncurl -s -XGET http://127.0.0.1:8889/v2/one/data | jq\n{\n  \"path\": \"/zoorest/one/data\",\n  \"state\": \"OK\",\n  \"error\": \"\",\n  \"data\": \"eyJzb21lIjogImpzb24ifQ==\"\n}\n```\nNode data stored in *data* field as base64 encoded string\n```\necho eyJzb21lIjogImpzb24ifQ== | base64 -d\n{\"some\": \"json\"}\n```\n\n#### Errors\n\n```json\n curl -s -XGET http://127.0.0.1:8889/v2/does/not/exist | jq\n{\n  \"path\": \"\",\n  \"state\": \"ERROR\",\n  \"error\": \"zk: node does not exist\",\n  \"data\": null\n}\n```\n\n### Get node data as JSON\n\nMethod: **GET**\n\nLocation: **/v2/path/to/node+json**\n\nSimple add to the end of the path `+json`\nReturn JSON\n```\ncurl -s -XGET http://127.0.0.1:8889/v2/json/one/data+json | jq\n{\n  \"path\": \"/json/one/data\",\n  \"state\": \"OK\",\n  \"error\": \"\",\n  \"zkstat\": {\n    \"Czxid\": 45,\n    \"Mzxid\": 55,\n    \"Ctime\": 1564645641612,\n    \"Mtime\": 1564646317882,\n    \"Version\": 6,\n    \"Cversion\": 0,\n    \"Aversion\": 0,\n    \"EphemeralOwner\": 0,\n    \"DataLength\": 28,\n    \"NumChildren\": 0,\n    \"Pzxid\": 45\n  },\n  \"data\": {\n    \"ok\": true,\n    \"some\": \"data\"\n  }\n}\n```\n\n#### Errors\n\n```json\ncurl -s -XGET http://127.0.0.1:8889/v2/invalid/json+json | jq\n{\n  \"path\": \"/invalid/json\",\n  \"state\": \"ERROR\",\n  \"error\": \"JSON parsing failure: invalid character 'i' looking for beginning of value\",\n  \"zkstat\": {\n    \"Czxid\": 45,\n    \"Mzxid\": 56,\n    \"Ctime\": 1564645641612,\n    \"Mtime\": 1564646350753,\n    \"Version\": 7,\n    \"Cversion\": 0,\n    \"Aversion\": 0,\n    \"EphemeralOwner\": 0,\n    \"DataLength\": 17,\n    \"NumChildren\": 0,\n    \"Pzxid\": 45\n  },\n  \"data\": null\n}\n```\n\n### Create node recursive\n\nMethod: **PUT**\n\nReturn string with created path\n```\ncurl -XPUT http://127.0.0.1:8889/v2/two/three/four -d '{\"four\": \"json\"}'\n/zoorest/two/three/four\n```\n\n### Create node children\n\nMethod: **PATCH**\n\nReturn string with created children path\n```\ncurl -XPATCH http://127.0.0.1:8889/v2/one/test -d 'test'\n/one/test\n```\n\n#### Errors\n\n```\ncurl -XPATCH http://127.0.0.1:8889/v2/six/test -d '{\"six\": \"json\"}'\nzk: node does not exist\n```\n\n### Update node\n\nMethod: **POST**\n\nReturn string with updated path\n```\ncurl -XPOST http://127.0.0.1:8889/v2/two -d '{\"two\": \"json\"}'\n/zoorest/two\n```\n\n#### Errors\n\n```\ncurl -XPOST http://127.0.0.1:8889/v2/twa -d '{\"two\": \"json\"}'\nzk: node does not exist\n```\n\n### Delete node recursive\nMethod: **DELETE**\n\nReturn string with removed path\n```\ncurl -XDELETE http://127.0.0.1:8889/v2/two\n/zoorest/two\n```\n\n#### Errors\n```\ncurl -XPOST http://127.0.0.1:8889/v2/two\nMethod POST not alowed\n```\n\n## Build\n\n### Binary\n\nSet GOPATH variable\n```\nexport GOPATH ${HOME}/.local\n```\n\nGet source code\n```\ngo get github.com/Difrex/zoorest/rest\n```\n\nGet dependencies\n```\ncd ${GOPATH}/src/github.com/Difrex/zoorest\ngo get -t -v ./...\n```\n\nBuild staticaly linked binary\n```\ngo build -ldflags \"-linkmode external -extldflags -static\"\n```\n\nBuild dynamicaly linked binary\n```\ngo build\n```\n\nBuild dynamicaly linked binary with gcc\n```\ngo build -compile gccgo\n```\n\n### Docker build\n\n#### Binary file\n\nBuild binary with the Docker\n```\ngit clone https://github.com/Difrex/zoorest.git\ncd zoorest\n./build.sh docker-binary\n```\nResult binary file will be placed in out/ dir\n\n#### Docker image\n\nBuild Alpine based docker image\n```\ngit clone https://github.com/Difrex/zoorest.git\ncd zoorest\n./build.sh docker\n```\n\nImage will be tagged as zoorest:latest\n\n## Get docker image\n\nPull image\n```\ndocker pull lessmore/zoorest\n```\n\nAnd run it\n```\n/usr/bin/docker run -d -p 8889:8889 --name zoorest lessmore/zoorest:latest --zk zoo1:2181,zoo2:2181,zoo3:2181 --path /zoorest/jail --listen 0.0.0.0:8889 -mc -mchosts mc1:11211,mc2:11211,mc3:11211\n```\n\n# AUTHORS\n\nDenis Zheleztsov \u003cdifrex.punk@gmail.com\u003e\n\n# LICENSE\n\nGPLv3 see [LICENSE](LICENSE)\n\n# DONATE\n\nBTC 1JCmZQdESKPCrcjUxDRNgt5HaSgUEWZ8pV\u003cbr\u003e\nDASH XxEWcJgfiAav1gxTtVLGXqE5T66uMA7te7\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdifrex%2Fzoorest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdifrex%2Fzoorest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdifrex%2Fzoorest/lists"}