{"id":13682621,"url":"https://github.com/johndatserakis/koa-vue-notes-api","last_synced_at":"2025-04-07T13:07:26.936Z","repository":{"id":86795339,"uuid":"97355983","full_name":"johndatserakis/koa-vue-notes-api","owner":"johndatserakis","description":"🤓 This is a simple SPA built using Koa as the backend, Vue as the first frontend, and React as the second frontend. Features MySQL integration, user authentication, CRUD note actions, and async/await.","archived":false,"fork":false,"pushed_at":"2021-01-13T00:55:25.000Z","size":5814,"stargazers_count":363,"open_issues_count":1,"forks_count":66,"subscribers_count":19,"default_branch":"develop","last_synced_at":"2025-03-31T11:05:33.376Z","etag":null,"topics":["api","backend","boilerplate","database","demo","jwt","koa","mysql","node","pm2","spa","template"],"latest_commit_sha":null,"homepage":"https://koa-vue-notes-web.innermonkdesign.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/johndatserakis.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}},"created_at":"2017-07-16T02:55:59.000Z","updated_at":"2025-02-06T08:41:36.000Z","dependencies_parsed_at":"2023-03-06T14:15:37.123Z","dependency_job_id":null,"html_url":"https://github.com/johndatserakis/koa-vue-notes-api","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johndatserakis%2Fkoa-vue-notes-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johndatserakis%2Fkoa-vue-notes-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johndatserakis%2Fkoa-vue-notes-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/johndatserakis%2Fkoa-vue-notes-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/johndatserakis","download_url":"https://codeload.github.com/johndatserakis/koa-vue-notes-api/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247657281,"owners_count":20974345,"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","backend","boilerplate","database","demo","jwt","koa","mysql","node","pm2","spa","template"],"created_at":"2024-08-02T13:01:49.873Z","updated_at":"2025-04-07T13:07:26.917Z","avatar_url":"https://github.com/johndatserakis.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://koa-vue-notes-web.innermonkdesign.com/\" target=\"_blank\"\u003e\u003cimg width=\"200\" src=\"./src/static/koa-vue-notes-icon.png\"\u003e\u003c/a\u003e\n  \u0026nbsp;\u0026nbsp;\u0026nbsp;\n  \u003ca href=\"https://koa-react-notes-web.innermonkdesign.com/\" target=\"_blank\" \u003e\u003cimg width=\"200\" src=\"./src/static/koa-react-notes-icon.png\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/license-MIT-blue.svg\" alt=\"License\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://twitter.com/intent/tweet?url=https%3A%2F%2Fgithub.com%2Fjohndatserakis%2Fkoa-vue-notes-api\u0026text=Check%20out%20koa-vue-notes-api%20on%20GitHub\u0026via=innermonkdesign\"\u003e\n  \u003cimg src=\"https://img.shields.io/twitter/url/https/github.com/johndatserakis/koa-vue-notes-api.svg?style=social\" alt=\"Tweet\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n# Koa-Vue-Notes-Api\n\nThis is a simple SPA built using [Koa](http://koajs.com/) as the backend, [Vue](https://vuejs.org/) as the first frontend, and [React](https://reactjs.org) as the second frontend.\n\n- [Frontend Vue GitHub](https://github.com/johndatserakis/koa-vue-notes-web)\n- [Frontend Vue Demo](https://koa-vue-notes-web.innermonkdesign.com/)\n- [Frontend React GitHub](https://github.com/johndatserakis/koa-react-notes-web)\n- [Frontend React Demo](https://koa-react-notes-web.innermonkdesign.com/)\n- [Backend Koa GitHub](https://github.com/johndatserakis/koa-vue-notes-api)\n\n# Features\n\n- Koa 2.5.1\n- Fully written using async/await\n- Koa-Router\n- Koa-Ratelimit\n- Koa-Bodyparser\n- KCors\n- Koa-Json-Error for JSON requests/responses\n- Koa-Useragent to get client user-agent data\n- Bcrypt\n- Sendgrid Mailer for email\n- Joi for input validation\n- Fs-Extra\n- JWT\n- Nodemon for running in development\n- Prettier\n- Babel\n- MySQL\n- Knex with migrations and seeds\n- Jest for testing\n- Faker to create seeds\n- log4js for logging\n- Docker server\n- And more...\n\n## Installing / Getting started\n\n```bash\n# Install dependencies\nnpm i\n\n# Serve using nodemon with hot reload\nnpm run watch\n\n# Build for production\nnpm run build\n\n# Lint the project with eslint\nnpm run lint\n\n# Run tests\nnpm run test\n\n## knex Migrations\n\n## Note - All knex migrate/rollback/seed calls must be prefaced\n## with the setting of NODE_ENV - also, seeds and rollbacks are\n## disabled in production\n\n# Migrate latest\nNODE_ENV=development knex migrate:latest\n\n# Rollback\nNODE_ENV=development knex migrate:rollback\n\n# Run all seeds\nNODE_ENV=development knex seed:run\n\n# Make migration\nknex migrate:make create_users_table\n\n# Make seed\nknex seed:make seed_users\n```\n\n#### Note\n\nIf you want to turn on the rate-limiter, uncomment the rate-limiter block in `./src/index.js` and make sure you have redis running. I use homebrew. You can follow [this](https://medium.com/@petehouston/install-and-config-redis-on-mac-os-x-via-homebrew-eb8df9a4f298) guide. After installing and running redis, you should be able to enter `redis-cli ping` into a terminal and get `PONG` back.\n\n## General Information\n\nThis backend is part of a pair of projects that serve a simple notes app. I chose a notes app because it gives you a good look at the different techniques used in both the frontend and backend world. What's really cool is these projects feature a fully fleshed-out user login/signup/forgot/reset authentication system using `JWT`.\n\nI've liberally commented the code and tried to balance the project in a way that it's complex enough to learn from but not so complex that it's impossible to follow. It can be tough to learn from a boilerplate that has too much or too little.\n\nHaving used mainly `PHP` for the backend in the past - I am very glad I checked out Koa as I think it is absolutely awesome in the way it handles the server code. Same thing with `Vue` and `React` - I've used mainly `jQuery` in the past - albeit with the really structured Revealing-Module-Pattern - and using `Vue` and `React` was such a pleasure. You can really tell right away what kind of power a well-structured library can give you.\n\nYou'll need to create a `.env` file and place it in the root of your directory. Take a look at `.example.env` and add your information as needed. For `JWT_ACCESS_TOKEN_EXP` you can set it to `5m`, `5w`, `5d` etc - although `5m` is what I'm using at the moment. Note - we don't set the `NODE_ENV` variable in the `.env` - we set it in the npm scripts. This lets us specifically set different environments as needed. Also make sure to set the `JWT_SECRET` variable - something random around 32 characters.\n\nThis project only responds and listens in `JSON`. Keep that in mind when send requests through `Insomnia` or your frontend.\n\n### User Authentication Process\n\nAs mentioned in the frontend code, the user authentication process is this:\n\n- User create an account\n- User logs in\n- The server sends and `accessToken` and a `refreshToken` back\n- We take the `accessToken` and decode it using `jwt-decode`. This gets us the logged in user's information. We stick this in the Vuex/Redux `user` store. Then we store the `refreshToken` and `accessToken` in the user's `localStorage`.\n- Each protected endpoint will be expecting you to attach the `accessToken` you have to the call (using `Authentication: Bearer`)\n- After a short amount of time, the server will respond with `401 TOKEN EXPIRED`. When you see this - that means you need to send your `refreshToken` and `user.email` to the endpoint that deals with `accessToken` refreshing.\n- Once you do that, you'll received a brand new `accessToken` and `refreshToken`\n- Repeat the process as needed\n\nThe `src` folder is the heart of the program. I'll go over its subfolders now.\n\n### Controllers\n\nWe use controllers to keep our router thin. The controller's responsibility is to manage the request body and make sure it's nice and clean when it eventually gets sent to a `model` to make database calls. There are two controller files present - one for user signup/login/forgot... and one for notes. Note: the `UserActionController.js` is a little different then normal controllers, as I believe the actions of a user signup/login/forgot/reset are seperate from the normal actions for a user - so that's why `UserActionController.js` in written in a more _procedural_ way.\n\n### DB\n\nHere is our database setup. This project uses `Knex` to manage migrations and execute queries. I initially wrote wrote all the `MySQL` calls using raw `SQL`, but the need for a migrations manager pushed me towards an `ORM` for the `MySQL` database. `Knex` is awesome - very powerful, easy to use and make queries, and the migrations are nice to have for sure - especially for testing.\n\nFor this project you'll need to make two databases in your development environment, `koa_vue_notes_development` and `koa_vue_notes_testing`. In your production environment you would just have `koa_vue_notes_production`. Tests use a different database because the data there is extremely volatile - as table information is created and destroyed on every test. The `knexfile.js` used here dynamically attaches to the proper database based the `NODE_ENV`.\n\nThe `knexfile.js` in the root of the project is all setup with the ability to read your `.env` file. Make sure to have knex installed globally, `npm install -g knex`. Let's say you download this project - first you'll `npm i`, then create a `koa_vue_notes_development` database and a `koa_vue_notes_testing` database, then `knex migrate:latest` and `knex seed:run` to create and seed your tables. Currently it's set up to make five users and 100 notes distributed to those users.\n\n### Docker\n\nDocker is used for the development virtual machine and for building the production app. To use the included dockerfile.yml, run `docker-compose up -d --build` to bring up the machine. To stop the machine, run `docker-compose down`. The main reason docker is used in this case is to host the `MySQL` database. Make a database named `koa-vue-notes_development`. Connect through Sequel Pro using `host: 127.0.0.1`, `port: 3360`, `user: root`, and `password: docker`.\n\n### Middleware\n\nHere I place any custom middleware the app is using. The custom middleware we're using is based on the `koa-jwt` library - but I had to tweak it because it mysteriously didn't report an expired token correctly. Strange, as I thought that would be an important requirement. No biggie.\n\n### Models\n\nOur models folder contains two model files - one for users and one for notes. These models are where the actual database calls are made. This keeps things nice and neat - also make actions reusable for the future.\n\n### Routes\n\nVery simple - here are our routes. I've broken it down into a few files - this keeps things in control. Each route is nice and thin - all it's doing is calling a controller. Some routes are using that jwt middleware I mentioned earlier. Koa make it really nice and easy to add middleware to a route. Very cool.\n\n### Static\n\nStatic files - just used for the favicon.\n\n### index.js\n\nindex.js isn't a folder - it's the brain of the app. Here you'll see we are attaching a bunch of middleware to our `Koa` instance. Very slick and straight-forward initialization.\n\n### Testing\n\nThis project uses `Jest` for testing. Bascially, each API endpoint is tested with working request data to confirm the server behaves correctly when spoken to. Each time the tests are run the migrations get kicked into gear. After the tests are complete the testing database rolls-back - ready for the next test.\n\n### TypeScript\n\nSo, I added some basic TypeScript support because I've been really digging TypeScript lately. The implementation in this project is not perfect, but it's initialized and a good amount of the files are now converted. I'll get to the rest of the files as soon as I can, but the good news is that any new files needed going forward will be all set to write in TypeScript.\n\n## Hit Me Up\n\nGo ahead and fork the project! Message me here if you have questions or submit an issue if needed. I'll be making touch-ups as time goes on. Have fun with this!\n\n## License\n\nCopyright 2017 John Datserakis\n\n[MIT](http://opensource.org/licenses/MIT)\n\n-\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohndatserakis%2Fkoa-vue-notes-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjohndatserakis%2Fkoa-vue-notes-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjohndatserakis%2Fkoa-vue-notes-api/lists"}