{"id":21250903,"url":"https://github.com/michal-wrzosek/challenge-api","last_synced_at":"2026-04-08T16:01:32.083Z","repository":{"id":44142284,"uuid":"187276744","full_name":"michal-wrzosek/challenge-api","owner":"michal-wrzosek","description":"Challenge API - REST API","archived":false,"fork":false,"pushed_at":"2022-12-30T17:41:14.000Z","size":1549,"stargazers_count":1,"open_issues_count":22,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-13T08:02:10.246Z","etag":null,"topics":["api","chai","express","express-js","expressjs","heroku","jwt","jwt-authentication","jwt-token","mocha","mongodb","mongoose","node-js","nodejs","rest","rest-api","travis","travis-ci","travisci","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/michal-wrzosek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-17T20:20:26.000Z","updated_at":"2019-05-25T14:03:32.000Z","dependencies_parsed_at":"2023-01-31T12:31:38.345Z","dependency_job_id":null,"html_url":"https://github.com/michal-wrzosek/challenge-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/michal-wrzosek/challenge-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michal-wrzosek%2Fchallenge-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michal-wrzosek%2Fchallenge-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michal-wrzosek%2Fchallenge-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michal-wrzosek%2Fchallenge-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michal-wrzosek","download_url":"https://codeload.github.com/michal-wrzosek/challenge-api/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michal-wrzosek%2Fchallenge-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31562697,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","chai","express","express-js","expressjs","heroku","jwt","jwt-authentication","jwt-token","mocha","mongodb","mongoose","node-js","nodejs","rest","rest-api","travis","travis-ci","travisci","typescript"],"created_at":"2024-11-21T03:39:32.370Z","updated_at":"2026-04-08T16:01:32.069Z","avatar_url":"https://github.com/michal-wrzosek.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Challenge API - REST API\n\nIt's a demo API. There is also a [Demo App](https://github.com/michal-wrzosek/challenge-app) using this API.\n\n---\n\n# Documentation\n\n- [Environments](#environments)\n- [Authentication](#authentication)\n- [Error responses](#error-responses)\n- [Routes](#routes):\n  - [Providers](#providers)\n  - [Users](#users)\n- [Architecture Design](#architecture-design)\n- [Development](#development)\n  - [Seeds](#seeds)\n\n## Environments\n\n**Production:**\nhttps://challenge-api-production.herokuapp.com/\n\n**Staging:**\nhttps://challenge-api-staging.herokuapp.com/\n\n## Authentication\n\nAccess to some endpoints is limited. In order to gain access to them you'll need a valid JSON Web Token. This token can be obtained by calling [/api/v1/users/login](#post-userslogin) endpoint. Token is active for 1 hour. When calling protected endpoints you need to attach an Authorization header with your token like this:\n\n```\nHeader[\"Authorization\"]: \"Bearer your_token_here\"\n```\n\n## Error responses\n\nAll errors responses are always structured in the same way:\n\n```\nStatus: 401, 404, 500\n\nJSON:\n- error:\n  - message: string\n```\n\n## Routes\n\n### Providers\n\nThis route lets you query \"Providers\" resource.\n\n#### GET /providers\n\nThis endpoint let's you receive a list of Providers. This endpoint needs a valid token to be accessed (Read more: [Authentication](#authentication))\n\n```\nGET /api/v1/providers\n```\n\n**Pagination:**\nThis endpoint is paginated. 10 records per page by default. (Min 1, max 50)\n\n**Filters:**\nYou can filter results. Check \"Parameters\" section.\n\n**Projection:**\nYou can select which fields should be returned. All are visible by default. Check \"Parameters\" section.\n\n**Parameters:**\n\n```\nFilters query params:\n- max_discharges: number\n  - min: 0\n  - filters totalDischarges column\n- min_discharges: number\n  - min: 0\n  - filters totalDischarges column\n- max_average_covered_charges: number\n  - min: 0\n  - filters avgCoveredCharges column\n- min_average_covered_charges: number\n  - min: 0\n  - filters avgCoveredCharges column\n- max_average_medicare_payments: number\n  - min: 0\n  - filters avgMedicarePayments column\n- min_average_medicare_payments: number\n  - min: 0\n  - filters avgMedicarePayments column\n- state: string (ISO 3166-2 Code like \"DC\")\n  - filters state column\n\nProjection query params:\n- project: string\n  - one of:\n    - providerId\n    - name\n    - street\n    - city\n    - state\n    - zipcode\n    - hospitalReferralRegionDesc\n    - totalDischarges\n    - avgCoveredCharges\n    - avgTotalPayments\n    - avgMedicarePayments\n    - drgDefinition\n  - when using this param you can control which field should be returned\n  - you can project multiple columns like this:\n    - /api/v1/providers?project=name\u0026project=street\n    - this will return only \"_id\", \"name\" and \"street\" fields\n  - \"_id\" field will always be returned\n\nPagination query params:\n- page: number (positive integer to select current page)\n- limit: number (integer in range 1 - 50 to select certain nr of records per page)\n```\n\n**Successful response:**\n\n```\nStatus: 200\n\nJSON:\n- data:\n  - providers: [\n    - _id: string\n    - providerId: string\n    - name: string\n    - street: string\n    - city: string\n    - state: string\n    - zipcode: string\n    - hospitalReferralRegionDesc: string\n    - totalDischarges: number\n    - avgCoveredCharges: number\n    - avgTotalPayments: number\n    - avgMedicarePayments: number\n    - drgDefinition: string\n  ]\n- pagination:\n  - totalDocs: number\n  - limit: number\n  - page: number\n  - totalPages: number\n  - prevPage: number | null\n  - nextPage: number | null\n\n```\n\n### Users\n\nThis route is exposed just for authentication purposes. There are no resources you can retrieve.\n\n#### POST /users/login\n\nThis is an authentication endpoint that lets you receive JSON Web Token. [More about authentication](#authentication)\n\n**Endpoint:**\n\n```\nPOST /api/v1/users/login\n```\n\n**Parameters:**\n\n```\nBody (JSON):\n\n- email: string (required)\n- password: string (required)\n```\n\n**Successful response:**\n\n```\nStatus: 200\n\nJSON:\n- token: JSON Web Token\n```\n\n**Failed response:**\n\n```\nStatus: 401\n\nJSON:\n- error:\n  - message: \"Auth failed\"\n```\n\n#### GET /users/me\n\nThis is a token protected endpoint. [More about authentication](#authentication) This endpoint returns current user's data.\n\n**Endpoint:**\n\n```\nGET /api/v1/users/me\n```\n\n**Parameters:**\n\n```\nNo parameters expected\n```\n\n**Successful response:**\n\n```\nStatus: 200\n\nJSON:\n- user:\n  - _id: string\n  - email: string\n```\n\n**Failed response:**\n\n```\nStatus: 401\n\nJSON:\n- error:\n  - message: \"Auth failed\"\n```\n\n---\n\n## Architecture Design\n\nThis app was built from scratch (no boilerplate). It's a Typescript project using express.js and mongoose with mongodb. All endpoints were covered by tests. For testing API I used supertest to mock requests to \"app\". For testing purposes I'm spinning up \"mongodb-memory-server\" and I'm clearing db for each test. I created a small fixture factory to help me test Providers endpoints. Later on I published an NPM library based on a solution I used building this project - [worp](https://www.npmjs.com/package/worp).\n\nFor pagination I used \"mongoose-paginate-v2\" plugin.\n\nFiltering and projection is made more or less \"manually\" in a controller.\n\nGitHub repo restricts PRs to master branch to pass Travis CI build.\n\nMaster branch is automatically deployed to staging environment on Heroku. Production can be deployed manually.\n\n---\n\n## Development\n\n### Seeds\n\nIt is sometimes useful to populate database with some prepared data/fixtures. I created a simple seed CLI runner. Just type:\n\n```bash\nnpm run seed name_of_seed_here\n```\n\n#### Create Master User Seed\n\nSince this API does not expose any sign-up endpoint we can create a master user by seeds. Just provide user's email and password via ENV and run a seed.\n\n**ENVs:**\n\n- `MASTER_USER_EMAIL`\n- `MASTER_USER_PASSWORD`\n\n**Command to run this seed:**\n\n```bash\nnpm run seed createMasterUser\n```\n\n#### Populate Providers Seed\n\nFor development purposes you can populate your DB with 300 Providers coming from automatically generated fixtures:\n\n```bash\nnpm run seed populateProviders\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichal-wrzosek%2Fchallenge-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichal-wrzosek%2Fchallenge-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichal-wrzosek%2Fchallenge-api/lists"}