{"id":14235834,"url":"https://github.com/subeshb1/api-test","last_synced_at":"2025-04-13T02:32:23.891Z","repository":{"id":47040194,"uuid":"264418806","full_name":"subeshb1/api-test","owner":"subeshb1","description":"🌿 A simple bash script to test JSON API from terminal in a structured and organized way.","archived":false,"fork":false,"pushed_at":"2021-09-21T11:57:52.000Z","size":134,"stargazers_count":73,"open_issues_count":9,"forks_count":16,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-26T20:49:31.278Z","etag":null,"topics":["api-test","api-testing","api-testing-framework","automated-api-test","automated-test-runner","automated-testing","automation","bash","bash-script","bash-scripting","curl","integration-testing","jq","json-api","test","testing","testing-automation","testing-framework","testing-library","testing-tools"],"latest_commit_sha":null,"homepage":"https://subeshbhandari.com/api-test","language":"Shell","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/subeshb1.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}},"created_at":"2020-05-16T11:08:49.000Z","updated_at":"2025-03-26T06:08:49.000Z","dependencies_parsed_at":"2022-08-25T15:51:43.204Z","dependency_job_id":null,"html_url":"https://github.com/subeshb1/api-test","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subeshb1%2Fapi-test","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subeshb1%2Fapi-test/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subeshb1%2Fapi-test/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/subeshb1%2Fapi-test/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/subeshb1","download_url":"https://codeload.github.com/subeshb1/api-test/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248657803,"owners_count":21140842,"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-test","api-testing","api-testing-framework","automated-api-test","automated-test-runner","automated-testing","automation","bash","bash-script","bash-scripting","curl","integration-testing","jq","json-api","test","testing","testing-automation","testing-framework","testing-library","testing-tools"],"created_at":"2024-08-20T21:02:23.907Z","updated_at":"2025-04-13T02:32:23.596Z","avatar_url":"https://github.com/subeshb1.png","language":"Shell","readme":"\u003c!-- \u003cHEADER\u003e // IGNORE IT --\u003e\n\u003cp align=\"center\"\u003e\n\u003cimg src=\"./api-test.png\" height=\"200px\" alt=\"api-test log\"\u003e\n \n\u003c/p\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eAPI testing framework for the terminal\u003c/h1\u003e\n\u003c/div\u003e\n\n\u003cbr /\u003e\n\u003c!-- \u003c/HEADER\u003e // NOW BEGINS THE README --\u003e\n\napi-test is a simple bash script to test JSON API from terminal in a structured and organized way.\n\n![CI](https://github.com/subeshb1/api-test/workflows/CI/badge.svg)\n![Release](https://img.shields.io/github/v/release/subeshb1/api-test)\n\nDocs: [https://subeshbhandari.com/api-test](https://subeshbhandari.com/api-test)\n\n## Setting up\n\n### Requirements\n\n- [curl](https://curl.haxx.se/download.html)\n- [jq](https://stedolan.github.io/jq/download)\n\nIn cloud 9 / CentOs / aws linux image\n\n```sh\nsudo yum install jq\n```\n\n## Installing\n\nPull the script\n\n```sh\ncurl -LJO https://raw.githubusercontent.com/subeshb1/api-test/master/api-test.sh\n```\n\nMake the script executable\n\n```sh\nchmod +x api-test.sh\n```\n\nMove it to `/usr/local/bin` to make it executable from anywhere\n\n```\nsudo mv api-test.sh /usr/local/bin/api-test\n```\n\nCheck if the installation is successful\n\n```\napi-test --help\n```\n\n### Alternate Approach\n\nSince it is a small bash file, you can copy the content in https://raw.githubusercontent.com/subeshb1/api-test/master/api-test.sh and paste in a file, make it executable and run it.\n\n## Usage\n\n```sh\n$ api-test.sh -h\n\nA simple program to test JSON APIs.\n\nUSAGE: api-test [-hv] -f file_name [CMD] [ARGS]\n\nOPTIONS:\n  -h (--help)       print this message\n  -v (--verbose)    verbose logging\n  -f (--file)       file to test\n  --version         print the version of the program\n\nCOMMANDS:\n  run               Run test cases specified in the test file.\n  test              Run automated test in the test file.\n  describe          List test cases or describe the contents in a test case.\n\nRun 'api-test COMMAND --help' for more information on a command.\n```\n\n### Test file\n\nThe test file will contain test cases in json format.\n\nExample:\n`test.json`\n\n```js\n{\n  \"name\": \"My API test\",\n  \"testCases\": {\n    \"test_case_1\": {\n      \"path\": \"/path_1\",\n      \"method\": \"POST\",\n      \"description\": \"Best POST api\",\n      \"body\": {\n        \"value\": 1\n      },\n      \"header\": {\n        \"X-per\": \"1\"\n      }\n    },\n    \"test_case_2\": {\n      \"path\": \"/path_2\",\n      \"method\": \"GET\",\n      \"description\": \"Best GET api\",\n      \"query\": {\n        \"value\": 1\n      }\n    },\n    \"test_case_3\": {\n      \"path\": \"/path_1\",\n      \"method\": \"DELETE\",\n      \"description\": \"Best DELETE api\",\n      \"body\": {\n        \"value\": 1\n      }\n    }\n  },\n  \"url\": \"localhost:3000\",\n  \"header\": {\n    \"Authorization\": \"Bearer \u003cACCESS_TOKEN\u003e\"\n  }\n}\n```\n\nThe test cases are present in the `testCases` object. The main url for the api is store in `url` string. If the test cases share common headers add them in root `header` key.\n\nTo pull the `template.json`\n\n```sh\ncurl -LJO https://raw.githubusercontent.com/subeshb1/api-test/master/template.json\n```\n\n### Running test case\n\n```sh\napi-test -f test.json run test_case_1 # running single test case\napi-test -f test.json run test_case_1 test_case_2 # running multiple test case\napi-test -f test.json run all # running all test case. WARNING: Don't name a test case `all`\napi-test -v -f test.json run test_case_1 # To run in verbose mode use `-v`\n```\n\n## Automated testing\n\nTo run an automated test run,\n\n```sh\napi-test -f test.json test test_case_1\napi-test -f test.json test all # To run all tests\n```\n\n![test](https://user-images.githubusercontent.com/27361350/82819405-0e5b5f00-9ec0-11ea-959b-211704ea4c1a.gif)\n\nBoth the headers and body can be compared to create automated api tests using different types of checking schemes described in further sections. All the checking schemes can be used for a test case.\nTo define test units add them in `expect` object in the testCase.\n\n```js\n{\n  \"test_case_1\": {\n    \"path\": \"/path_1\",\n    \"method\": \"POST\",\n    \"expect\": { // automated tests are kept inside this object\n      \"header\": {\n        ...\n      },\n      \"body\": {\n        ...\n      }\n    }\n  }\n}\n```\n\nThere are 5 ways you can compare the result from the api response.\n\n### 1. eq\n\nThe `eq` check compares every element in an object irrespective of the order of object keys and array elements. Every element in compared object should match as the object defined in `eq` block.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"eq\": {\n        \"key\": \"value\"\n      }\n    }\n  }\n}\n\n```\n\nExample:\nThe api has following response.\n\n```js\n{\n  \"name\": \"ram\",\n  \"age\": 20\n}\n```\n\nTo test using `eq` check:\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"eq\": {\n        \"name\": \"ram\",\n        \"age\": 20\n      }\n    }\n  }\n}\n```\n\nThe check will pass for the above response. If any of the value or key is different it will throw error.\n\n### 2. contains\n\nThe `contains` check compares the expected value with all the possible subset of the compared object irrespective of the order of object keys and array elements. It will pass if the value matches any subset.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"contains\": {\n        \"key\": \"value\"\n      }\n    }\n  }\n}\n\n```\n\nExample:\nThe api has following response.\n\n```js\n{\n  \"name\": \"ram\",\n  \"age\": 20\n}\n```\n\nTo test using `contains` check:\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"contains\": {\n        \"age\": 20\n      }\n    }\n  }\n}\n```\n\nThe check will pass for the above response as `\"age\": 20` is the subset of response.\n\n### 3. hasKeys\n\nThe `hasKeys` will check if the provided keys in array are present in the response or not.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"hasKeys\": []\n    }\n  }\n}\n\n```\n\nExample:\nThe api has following response.\n\n```js\n{\n  \"people\": [\n    {\n      \"name\": \"ram\",\n      \"age\": 20\n    },\n    {\n      \"name\": \"Shyam\",\n      \"age\": 21\n    }\n  ]\n}\n```\n\nTo test using `hasKey` check:\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"hasKeys\": [\"people\", \"people.0\", \"people.1\", \"people.0.name\", \"people.1.name\"]\n    }\n  }\n}\n```\n\nAll the above keys are valid in the response. We can compare the key at any depth. While accessing arrays, be sure to use the index without brackets. The key accessing pattern contradicts with the next two checking schemes where bracket is used to access array properties.\n\n### 4. path_eq\n\nThe `path_eq` does the same check as `eq` but allows the check to be made inside JSON object path at any depth. The path accessing pattern follows javascript object accessing patterns.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n    \"path_eq\": {\n      \"path\": {\"key\": \"value:\"},\n      \"path.key1.key\": 1\n    }\n  }\n}\n\n```\n\nExample:\nThe api has following response.\n\n```js\n{\n  \"people\": [\n    {\n      \"name\": \"ram\",\n      \"age\": 20\n    },\n    {\n      \"name\": \"Shyam\",\n      \"age\": 21\n    }\n  ]\n}\n```\n\nTo test using `path_eq` check:\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"path_eq\": {\n        \"people[0]\": {\n          \"name\": \"ram\",\n          \"age\": 20\n        },\n        \"people[1].name\": \"Shyam\"\n      }\n    }\n  }\n}\n```\n\nThe above example shows how to access an object path to compare and check the values at any depths.\n\n### 5. path_contains\n\nThe `path_contains` does the same check as `contains` but allows the check to be made inside JSON object path at any depth. The path accessing pattern follows javascript object accessing patterns.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n     \"body\": {\n      \"path_contains\": {\n        \"path\": \"value\",\n        \"path.key1.key\": \"value\"\n      }\n     }\n  }\n}\n\n```\n\nExample:\nThe api has following response.\n\n```js\n{\n  \"people\": [\n    {\n      \"name\": \"ram\",\n      \"age\": 20\n    },\n    {\n      \"name\": \"Shyam\",\n      \"age\": 21\n    }\n  ]\n}\n```\n\nTo test using `path_contains` check:\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {\n      \"path_contains\": {\n        \"people[0]\": {\n          \"name\": \"ram\",\n        },\n        \"people[1].name\": \"Shyam\",\n        \"people\": []\n      }\n    }\n  }\n}\n```\n\n### 6. External scripts or program\n\nIf none of the above checks work for you, there is a way to inject **any language** to compare and test an api response. To do so, provide the command name or script in the `external` key in the `expect` block. If a test case passes return an `exit code 0` and if a test fails `exit code \u003e 0` to communicate with the `api-test` program.\n\n#### Syntax\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {...},\n    \"header\": {...},\n    \"external\": \"\u003cyour program\u003e\"\n  }\n}\n```\n\nExample:\n\ntest.json\n\n```js\n{\n  ...\n  \"expect\": {\n    \"body\": {...},\n    \"header\": {...},\n    \"external\": \"node test.js\"\n  }\n}\n\n```\n\ntest.js\n\n```js\nlet testCase = process.argv[2]; // First arg will be test case key\nlet body = process.argv[3]; // Second arg will be body\nlet header = process.argv[4]; // Third arg will be header\n\nlet success = true;\nswitch (testCase) {\n  case \"get_api\":\n    if (success) {\n      process.exit(0); // For success case\n    } else {\n      process.exit(1); // For failure case\n    }\n    break;\n  case \"invalid_post_api\":\n    ...\n    break;\n\n  default:\n    break;\n}\n```\n\nThe `test case key`, `body` and `header` are passed respectively to the supplied program. You can use any language as long as you are sending out the correct exit code for failure and success.\n\nThe above example shows how to access an object path to compare and check the values at any depths. All the above comparison are a subset of response and will pass the check.\n\n## Uninstalling\n\n```\nrm /usr/local/bin/api-test\n```\n","funding_links":[],"categories":["Shell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubeshb1%2Fapi-test","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsubeshb1%2Fapi-test","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsubeshb1%2Fapi-test/lists"}