{"id":20650792,"url":"https://github.com/or-abdillh/express-starter","last_synced_at":"2025-04-17T12:42:22.557Z","repository":{"id":110202995,"uuid":"494517194","full_name":"or-abdillh/express-starter","owner":"or-abdillh","description":"Starter Project For Build Rest API using Express JS For Create CRUD Action with PostgreSQL Sequelize and support JWT Authentication ","archived":false,"fork":false,"pushed_at":"2022-05-29T07:50:42.000Z","size":483,"stargazers_count":13,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T06:11:15.396Z","etag":null,"topics":["express","expressjs","jwt","jwt-authentication","nodejs","postgresql","rest-api","restful-api","sequelizejs","starter-project","starter-template"],"latest_commit_sha":null,"homepage":"http://express-starter.herokuapp.com","language":"JavaScript","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/or-abdillh.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-05-20T15:31:20.000Z","updated_at":"2023-11-20T14:30:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"fc8a68c9-6bb8-4f8a-bfdb-fe3ec41ce39a","html_url":"https://github.com/or-abdillh/express-starter","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/or-abdillh%2Fexpress-starter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/or-abdillh%2Fexpress-starter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/or-abdillh%2Fexpress-starter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/or-abdillh%2Fexpress-starter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/or-abdillh","download_url":"https://codeload.github.com/or-abdillh/express-starter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249342137,"owners_count":21254228,"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":["express","expressjs","jwt","jwt-authentication","nodejs","postgresql","rest-api","restful-api","sequelizejs","starter-project","starter-template"],"created_at":"2024-11-16T17:23:13.789Z","updated_at":"2025-04-17T12:42:22.544Z","avatar_url":"https://github.com/or-abdillh.png","language":"JavaScript","readme":"### express-starter\n#### A starter project for build REST API with Express, Sequelize, PostgresSQL, supported JWT Authentication, and File Upload handler\n![GitHub](https://img.shields.io/github/license/or-abdillh/express-starter?style=for-the-badge)\n![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/or-abdillh/express-starter?style=for-the-badge)\n![Github activity](https://img.shields.io/github/last-commit/or-abdillh/express-starter/main?style=for-the-badge)\n\n## Documentation\n### Getting Started\nFollow the steps below to start the application\n1. Clone this repo with using command on your terminal \u003ccode\u003egit clone https://github.com/or-abdillh/express-starter.git\u003c/code\u003e\n2. Change current directory to application with commnd \u003ccode\u003ecd express-starter\u003c/code\u003e\n3. Install node modules \u003ccode\u003enpm install\u003c/code\u003e\n\n### Environment \u0026 Database\nThis aplication using PostgreSQL as a DBMS, you must setup your information connection into file `.env`\n1. In current directory  `cp .env.example .env`\n2. Edit `.env`  file with your connection setup:\n\t```env\n\tDATABASE_URL=postgresql://username:password@host:port/mydb\n\tSECRET_KEY=random_string_for_JWT\t\n\t```\n3. Run postgres service in your computer or you can try this command `npm run postgres-start` equal to `pg_ctl -D ~/pg start`\n4. Login to psql  terminal and create new database using name **blog**\n5. In current directory run `npm run migrate` and `npm run seeding`\n6. Before running command on point 5, your computer must installed sequelize-cli or you can install manual with command `npm i sequelize-cli --save-dev`\n\n### Check connection\nIn current directory running the application with command `npm run dev`\n![npm run dev](./public/run-dev.jpg)\n\n### API Documentation\nThis application case study is a simple blog, where users can create an account and login to be able to post articles, edit articles, or delete articles. but if the user doesn't want to register, he can log in as a guest and can only see all the articles that have been posted.\n\nThis is the documentation about the API that has been made\n\n#### Endpoint\n`http://localhost:8000`\n\n#### `/` `GET`\nTesting application or index route \u003cbr\u003e\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"This is example response from your application\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n#### `/users` `GET`\nGet all users \u003cbr\u003e\nResponse :\n```json\n{\n  \"status\": true,\n  \"code\": 200,\n  \"message\": \"Success\",\n  \"results\": {\n    \"users\": [\n      {\n        \"username\": \"fulan12\",\n        \"fullname\": \"Fulanah\",\n        \"createdAt\": \"2022-05-26T11:38:12.544Z\"\n      }\n    ]\n  },\n  \"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n\n```\n\n##### `/articles` `GET`  or `/articles?title=keyword` `GET`\nGet all articles or by query \u003cbr\u003e\nResponse : \n``` json\n{\n  \"status\": true,\n  \"code\": 200,\n  \"message\": \"Success\",\n  \"results\": {\n     \"articles\": [\n       {\n         \"id\": 1,\n         \"title\": \"Lorem ipsum\",\n         \"content\": \"lorem ipsum sit amet dolor\",\n         \"image\": \"http://localhost:8000/images/IMG-2092302302908343.jpg\",\n         \"createdAt\": \"2022-05-26T11:38:12.544Z\",\n         \"user\": {\n           \"fullname\": \"Sandhika Galih\"\n         }\n       }\n     ]\n  },\n  \"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n```\n``` json\n{\n\t\"status\": false,\n\t\"code\": 404,\n\t\"message\": \"Not found\",\n\t\"results\": \"Sorry, article not found\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\t\n}\n```\n\n#### `/articles/:username` `GET`\nGet article by username or author article \u003cbr\u003e\nResponse :\n``` json\n{\n  \"status\": true,\n  \"code\": 200,\n  \"message\": \"Success\",\n  \"results\": {\n     \"articles\": [\n       {\n         \"id\": 1,\n         \"title\": \"Lorem ipsum\",\n         \"content\": \"lorem ipsum sit amet dolor\",\n         \"image\": \"http://localhost:8000/images/IMG-2092302302908343.jpg\",\n         \"createdAt\": \"2022-05-26T11:38:12.544Z\",\n         \"user\": {\n           \"fullname\": \"Sandhika Galih\"\n         }\n       }\n     ]\n  },\n  \"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n```\n``` json\n{\n\t\"status\": false,\n\t\"code\": 404,\n\t\"message\": \"Not found\",\n\t\"results\": \"Sorry, article not found\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\t\n}\n```\n#### `/article/:id` `GET`\nGet article by id article \u003cbr\u003e\nResponse: \n``` json\n{\n  \"status\": true,\n  \"code\": 200,\n  \"message\": \"Success\",\n  \"results\": {\n     \"article\": {\n         \"id\": 1,\n         \"title\": \"Lorem ipsum\",\n         \"content\": \"lorem ipsum sit amet dolor\",\n         \"image\": \"http://localhost:8000/images/IMG-2092302302908343.jpg\",\n         \"createdAt\": \"2022-05-26T11:38:12.544Z\",\n       }\n  },\n  \"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n```\n``` json\n{\n\t\"status\": false,\n\t\"code\": 404,\n\t\"message\": \"Not found\",\n\t\"results\": \"Sorry, article not found\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\t\n}\n```\n#### `/user/login` `POST`\nGet JWT token from login \u003cbr\u003e\nRequest body : \n``` javascript\n{\n\tusername: 'YOUR USERNAME',\n\tpassword: 'YOUR PASSWORD'\n}\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": {\n\t\t\"token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsb2dpbiI6dHJ1ZSwidXNlcm5hbWUiOiJzYW5kaGlrYTIzNDAiLCJpYXQiOjE2NTM2NDMxODksImV4cCI6MTY1MzY0Njc4OX0.D61_9icM60wDzYgs_3Usk0AeOQ-r3ZIkCl5ingjv_B4\"\n\t},\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n``` json\n{\n\t\"status\": false,\n\t\"code\": 404,\n\t\"message\": \"Not found\",\n\t\"results\": \"Sorry, account not found or your username and password is wrong\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\t\n}\n```\n#### `/user/register` `POST`\nCreate new account \u003cbr\u003e\nRequest body :\n```javascript\n{\n\tusername: 'YOUR USERNAME',\n\tpassword: 'YOUR PASSWORD',\n\tfullname: 'YOUR FULLNAME',\n\tpassword: 'YOUR PASSWORD'\n}\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success create account for fulanah\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": false,\n\t\"code\": 403,\n    \"message\": \"Forbidden\",\n\t\"results\": \"Username has already exist\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n\n#### `/user/verify` `GET`\nJWT token verification \u003cbr\u003e\nRequest headers :\n```javascript\n{ headers: { token: 'YOUR TOKEN' } }\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Your login session valid\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": false,\n\t\"code\": 403,\n    \"message\": \"Forbidden\",\n\t\"results\": \"Your login session invalid\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n\n#### `/user/article/:username` `POST`\nPosting new article \u003cbr\u003e\nRequest headers :\n```javascript\n{ headers: { token: 'YOUR TOKEN' } }\n```\nRequest body :\n```javascript\n{\n\ttitle: 'YOUR TITTLE',\n\tcontent: 'THE CONTENT FROM YOUR ARTICLE'\n}\n```\nRequest files :\n```javascript\n{ files: { image: filesInputElement } }\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success posting new article\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n#### `/user/article/:username` `PUT`\nChange or update current article \u003cbr\u003e\nRequest header :\n```javascript\n{ headers: { token: 'YOUR TOKEN' } }\n```\nRequest body :\n```javascript\n{\n\ttitle: 'YOUR TITTLE',\n\tcontent: 'THE CONTENT FROM YOUR ARTICLE',\n\tid: 1\n}\n```\nRequest files [reupload image] :\n```javascript\n{ files: { image: filesInputElement } }\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success update article and remove old image from server\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success update article\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success update article but fail remove old image from server\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": false,\n\t\"code\": 404,\n    \"message\": \"Not Found\",\n\t\"results\": \"Article not found\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n#### `/user/article/:username` `DELETE`\nDelete article from database using id article \u003cbr\u003e\nRequest header :\n```javascript\n{ headers: { token: 'YOUR TOKEN' } }\n```\nRequest body :\n```javascript\n{ id: 1 }\n```\nResponse :\n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success update article and image from server\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": true,\n\t\"code\": 200,\n    \"message\": \"Success\",\n\t\"results\": \"Success update article but fail remove image from server\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n```json\n{\n\t\"status\": false,\n\t\"code\": 404,\n    \"message\": \"Not Found\",\n\t\"results\": \"Article not found\",\n\t\"createAt\": \"5/27/2022, 5:00:06 PM\"\n}\n``` \n### Middlewares\nThis application has middlewares to verify the user's JWT token when accessing sensitive resources.\n\n In addition to token verification, this application also has a middleware tool to log every incoming request and save it in the form of a txt file.\n#### 1. JWT Authentication\nOnly works on sensitive routes i.e. `user/article`. Every request that goes into that route must have an access token in the headers\n\nResponse :\n```json\n{\n\t\"status\": false,\n\t\"code\": 403,\n\t\"message\": \"Forbidden\",\n\t\"results\": \"Token cannot empty\"\n}\n```\n```json\n{\n\t\"status\": false,\n\t\"code\": 403,\n\t\"message\": \"Forbidden\",\n\t\"results\": \"Illegal access, your token invalid\"\n}\n```\n```json\n{\n\t\"status\": false,\n\t\"code\": 403,\n\t\"message\": \"Forbidden\",\n\t\"results\": \"You cannot access resource outside your account\"\n}\n```\n#### 2. Logging\nEach route that is accessed automatically the application will print information to the terminal\n```bash\n[5/27/2022, 5:41:01 PM] [403 - Forbidden] /user/register POST 96,791ms\n[5/27/2022, 5:53:41 PM] [200 - OK] /user/article/hans4x POST 77,54ms\n[5/27/2022, 6:18:06 PM] [404 - Not Found] /article/1 GET 29,043ms\n```\nThe application will also automatically save the logging results into a file in the `logs` directory and system will automatically create a new log file every day.\n```bash\n~/express-starter/logs/ $ ls\nexample-log.txt  log-file-2022-26-5.txt  log-file-2022-27-5.txt\n```\n\n### Public directory\nTo access the uploaded file use the `http://localhost:8000/images` route which is relevant to the `public/images` directory. \nExample :\n```\nhttp://localhost:8000/images/IMG-203820402380.png\n```\n\nIf you want to add a new public route in the public directory, add it to the `app/index.js` file:\nCode :\n```javascript\napp.use('/YOUR-CUSTOM-PATH', express.static(path.join( process.cwd(), '/public/NEW-DIRECTORY' )))\n```\n```\nhttp://localhost:8000/YOUR-CUSTOM-PATH\n```\n\n### Uploaded file name\nEvery new file that comes in will be renamed automatically by using the formula:\n```javascript\nconst format = 'png'\nconst fileName = `IMG-${ new Date().getTime()}.${ format }`\n```\n\n### Demo\nI have created a simple front end application as an example of implementing the API which is available here\n[coming soon](http://github.com/or-abdillh/express-starter)\n\n\n### Thanks \nSupport me with a cup of coffee and other snacks [here ..](https://saweria.co/orabdillh) \u003cbr\u003e\nDon't forget to give me star in this repository 🙏🏻🙏🏻 \u003cbr\u003e\nSee my other projects on instagram [@or.abdillh](http://www.instagram.com/or.abdillh) \u003cbr\u003e\n\n[Oka R Abdillah ](http://github.com/or-abdillh)\n\u003cbr\u003e\nLast edited on : 28/05/2022\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2For-abdillh%2Fexpress-starter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2For-abdillh%2Fexpress-starter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2For-abdillh%2Fexpress-starter/lists"}