├── .gitignore ├── LICENSE ├── README.md ├── client ├── .gitignore ├── .vscode │ └── extensions.json ├── README.md ├── index.html ├── package-lock.json ├── package.json ├── public │ └── favicon.ico ├── src │ ├── App.vue │ ├── assets │ │ └── logo.svg │ ├── components │ │ ├── Alert.vue │ │ ├── Books.vue │ │ ├── HelloWorld.vue │ │ └── Ping.vue │ ├── main.js │ └── router │ │ └── index.js └── vite.config.js └── server ├── app.py └── requirements.txt /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | /dist/ 4 | env/ 5 | __pycache__ 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 TestDriven.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Developing a Single Page App with Flask and Vue.js 2 | 3 | ### Want to learn how to build this? 4 | 5 | 6 | 7 | ## Want to use this project? 8 | 9 | 1. Fork/Clone 10 | 11 | 1. Run the server-side Flask app in one terminal window: 12 | 13 | ```sh 14 | $ cd server 15 | $ python3 -m venv env 16 | $ source env/bin/activate 17 | (env)$ pip install -r requirements.txt 18 | (env)$ flask run --port=5001 --debug 19 | ``` 20 | 21 | 22 | 23 | 1. Run the client-side Vue app in a different terminal window: 24 | 25 | ```sh 26 | $ cd client 27 | $ npm install 28 | $ npm run dev 29 | ``` 30 | 31 | 32 | -------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | .DS_Store 12 | dist 13 | dist-ssr 14 | coverage 15 | *.local 16 | 17 | /cypress/videos/ 18 | /cypress/screenshots/ 19 | 20 | # Editor directories and files 21 | .vscode/* 22 | !.vscode/extensions.json 23 | .idea 24 | *.suo 25 | *.ntvs* 26 | *.njsproj 27 | *.sln 28 | *.sw? 29 | -------------------------------------------------------------------------------- /client/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] 3 | } 4 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # client 2 | 3 | This template should help get you started developing with Vue 3 in Vite. 4 | 5 | ## Recommended IDE Setup 6 | 7 | [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). 8 | 9 | ## Customize configuration 10 | 11 | See [Vite Configuration Reference](https://vitejs.dev/config/). 12 | 13 | ## Project Setup 14 | 15 | ```sh 16 | npm install 17 | ``` 18 | 19 | ### Compile and Hot-Reload for Development 20 | 21 | ```sh 22 | npm run dev 23 | ``` 24 | 25 | ### Compile and Minify for Production 26 | 27 | ```sh 28 | npm run build 29 | ``` 30 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "client", 9 | "version": "0.0.0", 10 | "dependencies": { 11 | "axios": "^1.3.6", 12 | "bootstrap": "^5.2.3", 13 | "vue": "^3.2.47", 14 | "vue-router": "^4.1.6" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^4.0.0", 18 | "vite": "^4.1.4" 19 | } 20 | }, 21 | "node_modules/@babel/parser": { 22 | "version": "7.21.4", 23 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", 24 | "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", 25 | "bin": { 26 | "parser": "bin/babel-parser.js" 27 | }, 28 | "engines": { 29 | "node": ">=6.0.0" 30 | } 31 | }, 32 | "node_modules/@esbuild/android-arm": { 33 | "version": "0.17.17", 34 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.17.tgz", 35 | "integrity": "sha512-E6VAZwN7diCa3labs0GYvhEPL2M94WLF8A+czO8hfjREXxba8Ng7nM5VxV+9ihNXIY1iQO1XxUU4P7hbqbICxg==", 36 | "cpu": [ 37 | "arm" 38 | ], 39 | "dev": true, 40 | "optional": true, 41 | "os": [ 42 | "android" 43 | ], 44 | "engines": { 45 | "node": ">=12" 46 | } 47 | }, 48 | "node_modules/@esbuild/android-arm64": { 49 | "version": "0.17.17", 50 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.17.tgz", 51 | "integrity": "sha512-jaJ5IlmaDLFPNttv0ofcwy/cfeY4bh/n705Tgh+eLObbGtQBK3EPAu+CzL95JVE4nFAliyrnEu0d32Q5foavqg==", 52 | "cpu": [ 53 | "arm64" 54 | ], 55 | "dev": true, 56 | "optional": true, 57 | "os": [ 58 | "android" 59 | ], 60 | "engines": { 61 | "node": ">=12" 62 | } 63 | }, 64 | "node_modules/@esbuild/android-x64": { 65 | "version": "0.17.17", 66 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.17.tgz", 67 | "integrity": "sha512-446zpfJ3nioMC7ASvJB1pszHVskkw4u/9Eu8s5yvvsSDTzYh4p4ZIRj0DznSl3FBF0Z/mZfrKXTtt0QCoFmoHA==", 68 | "cpu": [ 69 | "x64" 70 | ], 71 | "dev": true, 72 | "optional": true, 73 | "os": [ 74 | "android" 75 | ], 76 | "engines": { 77 | "node": ">=12" 78 | } 79 | }, 80 | "node_modules/@esbuild/darwin-arm64": { 81 | "version": "0.17.17", 82 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.17.tgz", 83 | "integrity": "sha512-m/gwyiBwH3jqfUabtq3GH31otL/0sE0l34XKpSIqR7NjQ/XHQ3lpmQHLHbG8AHTGCw8Ao059GvV08MS0bhFIJQ==", 84 | "cpu": [ 85 | "arm64" 86 | ], 87 | "dev": true, 88 | "optional": true, 89 | "os": [ 90 | "darwin" 91 | ], 92 | "engines": { 93 | "node": ">=12" 94 | } 95 | }, 96 | "node_modules/@esbuild/darwin-x64": { 97 | "version": "0.17.17", 98 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.17.tgz", 99 | "integrity": "sha512-4utIrsX9IykrqYaXR8ob9Ha2hAY2qLc6ohJ8c0CN1DR8yWeMrTgYFjgdeQ9LIoTOfLetXjuCu5TRPHT9yKYJVg==", 100 | "cpu": [ 101 | "x64" 102 | ], 103 | "dev": true, 104 | "optional": true, 105 | "os": [ 106 | "darwin" 107 | ], 108 | "engines": { 109 | "node": ">=12" 110 | } 111 | }, 112 | "node_modules/@esbuild/freebsd-arm64": { 113 | "version": "0.17.17", 114 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.17.tgz", 115 | "integrity": "sha512-4PxjQII/9ppOrpEwzQ1b0pXCsFLqy77i0GaHodrmzH9zq2/NEhHMAMJkJ635Ns4fyJPFOlHMz4AsklIyRqFZWA==", 116 | "cpu": [ 117 | "arm64" 118 | ], 119 | "dev": true, 120 | "optional": true, 121 | "os": [ 122 | "freebsd" 123 | ], 124 | "engines": { 125 | "node": ">=12" 126 | } 127 | }, 128 | "node_modules/@esbuild/freebsd-x64": { 129 | "version": "0.17.17", 130 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.17.tgz", 131 | "integrity": "sha512-lQRS+4sW5S3P1sv0z2Ym807qMDfkmdhUYX30GRBURtLTrJOPDpoU0kI6pVz1hz3U0+YQ0tXGS9YWveQjUewAJw==", 132 | "cpu": [ 133 | "x64" 134 | ], 135 | "dev": true, 136 | "optional": true, 137 | "os": [ 138 | "freebsd" 139 | ], 140 | "engines": { 141 | "node": ">=12" 142 | } 143 | }, 144 | "node_modules/@esbuild/linux-arm": { 145 | "version": "0.17.17", 146 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.17.tgz", 147 | "integrity": "sha512-biDs7bjGdOdcmIk6xU426VgdRUpGg39Yz6sT9Xp23aq+IEHDb/u5cbmu/pAANpDB4rZpY/2USPhCA+w9t3roQg==", 148 | "cpu": [ 149 | "arm" 150 | ], 151 | "dev": true, 152 | "optional": true, 153 | "os": [ 154 | "linux" 155 | ], 156 | "engines": { 157 | "node": ">=12" 158 | } 159 | }, 160 | "node_modules/@esbuild/linux-arm64": { 161 | "version": "0.17.17", 162 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.17.tgz", 163 | "integrity": "sha512-2+pwLx0whKY1/Vqt8lyzStyda1v0qjJ5INWIe+d8+1onqQxHLLi3yr5bAa4gvbzhZqBztifYEu8hh1La5+7sUw==", 164 | "cpu": [ 165 | "arm64" 166 | ], 167 | "dev": true, 168 | "optional": true, 169 | "os": [ 170 | "linux" 171 | ], 172 | "engines": { 173 | "node": ">=12" 174 | } 175 | }, 176 | "node_modules/@esbuild/linux-ia32": { 177 | "version": "0.17.17", 178 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.17.tgz", 179 | "integrity": "sha512-IBTTv8X60dYo6P2t23sSUYym8fGfMAiuv7PzJ+0LcdAndZRzvke+wTVxJeCq4WgjppkOpndL04gMZIFvwoU34Q==", 180 | "cpu": [ 181 | "ia32" 182 | ], 183 | "dev": true, 184 | "optional": true, 185 | "os": [ 186 | "linux" 187 | ], 188 | "engines": { 189 | "node": ">=12" 190 | } 191 | }, 192 | "node_modules/@esbuild/linux-loong64": { 193 | "version": "0.17.17", 194 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.17.tgz", 195 | "integrity": "sha512-WVMBtcDpATjaGfWfp6u9dANIqmU9r37SY8wgAivuKmgKHE+bWSuv0qXEFt/p3qXQYxJIGXQQv6hHcm7iWhWjiw==", 196 | "cpu": [ 197 | "loong64" 198 | ], 199 | "dev": true, 200 | "optional": true, 201 | "os": [ 202 | "linux" 203 | ], 204 | "engines": { 205 | "node": ">=12" 206 | } 207 | }, 208 | "node_modules/@esbuild/linux-mips64el": { 209 | "version": "0.17.17", 210 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.17.tgz", 211 | "integrity": "sha512-2kYCGh8589ZYnY031FgMLy0kmE4VoGdvfJkxLdxP4HJvWNXpyLhjOvxVsYjYZ6awqY4bgLR9tpdYyStgZZhi2A==", 212 | "cpu": [ 213 | "mips64el" 214 | ], 215 | "dev": true, 216 | "optional": true, 217 | "os": [ 218 | "linux" 219 | ], 220 | "engines": { 221 | "node": ">=12" 222 | } 223 | }, 224 | "node_modules/@esbuild/linux-ppc64": { 225 | "version": "0.17.17", 226 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.17.tgz", 227 | "integrity": "sha512-KIdG5jdAEeAKogfyMTcszRxy3OPbZhq0PPsW4iKKcdlbk3YE4miKznxV2YOSmiK/hfOZ+lqHri3v8eecT2ATwQ==", 228 | "cpu": [ 229 | "ppc64" 230 | ], 231 | "dev": true, 232 | "optional": true, 233 | "os": [ 234 | "linux" 235 | ], 236 | "engines": { 237 | "node": ">=12" 238 | } 239 | }, 240 | "node_modules/@esbuild/linux-riscv64": { 241 | "version": "0.17.17", 242 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.17.tgz", 243 | "integrity": "sha512-Cj6uWLBR5LWhcD/2Lkfg2NrkVsNb2sFM5aVEfumKB2vYetkA/9Uyc1jVoxLZ0a38sUhFk4JOVKH0aVdPbjZQeA==", 244 | "cpu": [ 245 | "riscv64" 246 | ], 247 | "dev": true, 248 | "optional": true, 249 | "os": [ 250 | "linux" 251 | ], 252 | "engines": { 253 | "node": ">=12" 254 | } 255 | }, 256 | "node_modules/@esbuild/linux-s390x": { 257 | "version": "0.17.17", 258 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.17.tgz", 259 | "integrity": "sha512-lK+SffWIr0XsFf7E0srBjhpkdFVJf3HEgXCwzkm69kNbRar8MhezFpkIwpk0qo2IOQL4JE4mJPJI8AbRPLbuOQ==", 260 | "cpu": [ 261 | "s390x" 262 | ], 263 | "dev": true, 264 | "optional": true, 265 | "os": [ 266 | "linux" 267 | ], 268 | "engines": { 269 | "node": ">=12" 270 | } 271 | }, 272 | "node_modules/@esbuild/linux-x64": { 273 | "version": "0.17.17", 274 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.17.tgz", 275 | "integrity": "sha512-XcSGTQcWFQS2jx3lZtQi7cQmDYLrpLRyz1Ns1DzZCtn898cWfm5Icx/DEWNcTU+T+tyPV89RQtDnI7qL2PObPg==", 276 | "cpu": [ 277 | "x64" 278 | ], 279 | "dev": true, 280 | "optional": true, 281 | "os": [ 282 | "linux" 283 | ], 284 | "engines": { 285 | "node": ">=12" 286 | } 287 | }, 288 | "node_modules/@esbuild/netbsd-x64": { 289 | "version": "0.17.17", 290 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.17.tgz", 291 | "integrity": "sha512-RNLCDmLP5kCWAJR+ItLM3cHxzXRTe4N00TQyQiimq+lyqVqZWGPAvcyfUBM0isE79eEZhIuGN09rAz8EL5KdLA==", 292 | "cpu": [ 293 | "x64" 294 | ], 295 | "dev": true, 296 | "optional": true, 297 | "os": [ 298 | "netbsd" 299 | ], 300 | "engines": { 301 | "node": ">=12" 302 | } 303 | }, 304 | "node_modules/@esbuild/openbsd-x64": { 305 | "version": "0.17.17", 306 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.17.tgz", 307 | "integrity": "sha512-PAXswI5+cQq3Pann7FNdcpSUrhrql3wKjj3gVkmuz6OHhqqYxKvi6GgRBoaHjaG22HV/ZZEgF9TlS+9ftHVigA==", 308 | "cpu": [ 309 | "x64" 310 | ], 311 | "dev": true, 312 | "optional": true, 313 | "os": [ 314 | "openbsd" 315 | ], 316 | "engines": { 317 | "node": ">=12" 318 | } 319 | }, 320 | "node_modules/@esbuild/sunos-x64": { 321 | "version": "0.17.17", 322 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.17.tgz", 323 | "integrity": "sha512-V63egsWKnx/4V0FMYkr9NXWrKTB5qFftKGKuZKFIrAkO/7EWLFnbBZNM1CvJ6Sis+XBdPws2YQSHF1Gqf1oj/Q==", 324 | "cpu": [ 325 | "x64" 326 | ], 327 | "dev": true, 328 | "optional": true, 329 | "os": [ 330 | "sunos" 331 | ], 332 | "engines": { 333 | "node": ">=12" 334 | } 335 | }, 336 | "node_modules/@esbuild/win32-arm64": { 337 | "version": "0.17.17", 338 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.17.tgz", 339 | "integrity": "sha512-YtUXLdVnd6YBSYlZODjWzH+KzbaubV0YVd6UxSfoFfa5PtNJNaW+1i+Hcmjpg2nEe0YXUCNF5bkKy1NnBv1y7Q==", 340 | "cpu": [ 341 | "arm64" 342 | ], 343 | "dev": true, 344 | "optional": true, 345 | "os": [ 346 | "win32" 347 | ], 348 | "engines": { 349 | "node": ">=12" 350 | } 351 | }, 352 | "node_modules/@esbuild/win32-ia32": { 353 | "version": "0.17.17", 354 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.17.tgz", 355 | "integrity": "sha512-yczSLRbDdReCO74Yfc5tKG0izzm+lPMYyO1fFTcn0QNwnKmc3K+HdxZWLGKg4pZVte7XVgcFku7TIZNbWEJdeQ==", 356 | "cpu": [ 357 | "ia32" 358 | ], 359 | "dev": true, 360 | "optional": true, 361 | "os": [ 362 | "win32" 363 | ], 364 | "engines": { 365 | "node": ">=12" 366 | } 367 | }, 368 | "node_modules/@esbuild/win32-x64": { 369 | "version": "0.17.17", 370 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.17.tgz", 371 | "integrity": "sha512-FNZw7H3aqhF9OyRQbDDnzUApDXfC1N6fgBhkqEO2jvYCJ+DxMTfZVqg3AX0R1khg1wHTBRD5SdcibSJ+XF6bFg==", 372 | "cpu": [ 373 | "x64" 374 | ], 375 | "dev": true, 376 | "optional": true, 377 | "os": [ 378 | "win32" 379 | ], 380 | "engines": { 381 | "node": ">=12" 382 | } 383 | }, 384 | "node_modules/@popperjs/core": { 385 | "version": "2.11.7", 386 | "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz", 387 | "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==", 388 | "peer": true, 389 | "funding": { 390 | "type": "opencollective", 391 | "url": "https://opencollective.com/popperjs" 392 | } 393 | }, 394 | "node_modules/@vitejs/plugin-vue": { 395 | "version": "4.1.0", 396 | "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.1.0.tgz", 397 | "integrity": "sha512-++9JOAFdcXI3lyer9UKUV4rfoQ3T1RN8yDqoCLar86s0xQct5yblxAE+yWgRnU5/0FOlVCpTZpYSBV/bGWrSrQ==", 398 | "dev": true, 399 | "engines": { 400 | "node": "^14.18.0 || >=16.0.0" 401 | }, 402 | "peerDependencies": { 403 | "vite": "^4.0.0", 404 | "vue": "^3.2.25" 405 | } 406 | }, 407 | "node_modules/@vue/compiler-core": { 408 | "version": "3.2.47", 409 | "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.47.tgz", 410 | "integrity": "sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==", 411 | "dependencies": { 412 | "@babel/parser": "^7.16.4", 413 | "@vue/shared": "3.2.47", 414 | "estree-walker": "^2.0.2", 415 | "source-map": "^0.6.1" 416 | } 417 | }, 418 | "node_modules/@vue/compiler-dom": { 419 | "version": "3.2.47", 420 | "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.47.tgz", 421 | "integrity": "sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==", 422 | "dependencies": { 423 | "@vue/compiler-core": "3.2.47", 424 | "@vue/shared": "3.2.47" 425 | } 426 | }, 427 | "node_modules/@vue/compiler-sfc": { 428 | "version": "3.2.47", 429 | "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.47.tgz", 430 | "integrity": "sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==", 431 | "dependencies": { 432 | "@babel/parser": "^7.16.4", 433 | "@vue/compiler-core": "3.2.47", 434 | "@vue/compiler-dom": "3.2.47", 435 | "@vue/compiler-ssr": "3.2.47", 436 | "@vue/reactivity-transform": "3.2.47", 437 | "@vue/shared": "3.2.47", 438 | "estree-walker": "^2.0.2", 439 | "magic-string": "^0.25.7", 440 | "postcss": "^8.1.10", 441 | "source-map": "^0.6.1" 442 | } 443 | }, 444 | "node_modules/@vue/compiler-ssr": { 445 | "version": "3.2.47", 446 | "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.47.tgz", 447 | "integrity": "sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==", 448 | "dependencies": { 449 | "@vue/compiler-dom": "3.2.47", 450 | "@vue/shared": "3.2.47" 451 | } 452 | }, 453 | "node_modules/@vue/devtools-api": { 454 | "version": "6.5.0", 455 | "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", 456 | "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" 457 | }, 458 | "node_modules/@vue/reactivity": { 459 | "version": "3.2.47", 460 | "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.47.tgz", 461 | "integrity": "sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==", 462 | "dependencies": { 463 | "@vue/shared": "3.2.47" 464 | } 465 | }, 466 | "node_modules/@vue/reactivity-transform": { 467 | "version": "3.2.47", 468 | "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz", 469 | "integrity": "sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==", 470 | "dependencies": { 471 | "@babel/parser": "^7.16.4", 472 | "@vue/compiler-core": "3.2.47", 473 | "@vue/shared": "3.2.47", 474 | "estree-walker": "^2.0.2", 475 | "magic-string": "^0.25.7" 476 | } 477 | }, 478 | "node_modules/@vue/runtime-core": { 479 | "version": "3.2.47", 480 | "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.47.tgz", 481 | "integrity": "sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==", 482 | "dependencies": { 483 | "@vue/reactivity": "3.2.47", 484 | "@vue/shared": "3.2.47" 485 | } 486 | }, 487 | "node_modules/@vue/runtime-dom": { 488 | "version": "3.2.47", 489 | "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.47.tgz", 490 | "integrity": "sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==", 491 | "dependencies": { 492 | "@vue/runtime-core": "3.2.47", 493 | "@vue/shared": "3.2.47", 494 | "csstype": "^2.6.8" 495 | } 496 | }, 497 | "node_modules/@vue/server-renderer": { 498 | "version": "3.2.47", 499 | "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.47.tgz", 500 | "integrity": "sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==", 501 | "dependencies": { 502 | "@vue/compiler-ssr": "3.2.47", 503 | "@vue/shared": "3.2.47" 504 | }, 505 | "peerDependencies": { 506 | "vue": "3.2.47" 507 | } 508 | }, 509 | "node_modules/@vue/shared": { 510 | "version": "3.2.47", 511 | "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.47.tgz", 512 | "integrity": "sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==" 513 | }, 514 | "node_modules/asynckit": { 515 | "version": "0.4.0", 516 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 517 | "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" 518 | }, 519 | "node_modules/axios": { 520 | "version": "1.3.6", 521 | "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.6.tgz", 522 | "integrity": "sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==", 523 | "dependencies": { 524 | "follow-redirects": "^1.15.0", 525 | "form-data": "^4.0.0", 526 | "proxy-from-env": "^1.1.0" 527 | } 528 | }, 529 | "node_modules/bootstrap": { 530 | "version": "5.2.3", 531 | "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.2.3.tgz", 532 | "integrity": "sha512-cEKPM+fwb3cT8NzQZYEu4HilJ3anCrWqh3CHAok1p9jXqMPsPTBhU25fBckEJHJ/p+tTxTFTsFQGM+gaHpi3QQ==", 533 | "funding": [ 534 | { 535 | "type": "github", 536 | "url": "https://github.com/sponsors/twbs" 537 | }, 538 | { 539 | "type": "opencollective", 540 | "url": "https://opencollective.com/bootstrap" 541 | } 542 | ], 543 | "peerDependencies": { 544 | "@popperjs/core": "^2.11.6" 545 | } 546 | }, 547 | "node_modules/combined-stream": { 548 | "version": "1.0.8", 549 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 550 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 551 | "dependencies": { 552 | "delayed-stream": "~1.0.0" 553 | }, 554 | "engines": { 555 | "node": ">= 0.8" 556 | } 557 | }, 558 | "node_modules/csstype": { 559 | "version": "2.6.21", 560 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", 561 | "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" 562 | }, 563 | "node_modules/delayed-stream": { 564 | "version": "1.0.0", 565 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 566 | "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", 567 | "engines": { 568 | "node": ">=0.4.0" 569 | } 570 | }, 571 | "node_modules/esbuild": { 572 | "version": "0.17.17", 573 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.17.tgz", 574 | "integrity": "sha512-/jUywtAymR8jR4qsa2RujlAF7Krpt5VWi72Q2yuLD4e/hvtNcFQ0I1j8m/bxq238pf3/0KO5yuXNpuLx8BE1KA==", 575 | "dev": true, 576 | "hasInstallScript": true, 577 | "bin": { 578 | "esbuild": "bin/esbuild" 579 | }, 580 | "engines": { 581 | "node": ">=12" 582 | }, 583 | "optionalDependencies": { 584 | "@esbuild/android-arm": "0.17.17", 585 | "@esbuild/android-arm64": "0.17.17", 586 | "@esbuild/android-x64": "0.17.17", 587 | "@esbuild/darwin-arm64": "0.17.17", 588 | "@esbuild/darwin-x64": "0.17.17", 589 | "@esbuild/freebsd-arm64": "0.17.17", 590 | "@esbuild/freebsd-x64": "0.17.17", 591 | "@esbuild/linux-arm": "0.17.17", 592 | "@esbuild/linux-arm64": "0.17.17", 593 | "@esbuild/linux-ia32": "0.17.17", 594 | "@esbuild/linux-loong64": "0.17.17", 595 | "@esbuild/linux-mips64el": "0.17.17", 596 | "@esbuild/linux-ppc64": "0.17.17", 597 | "@esbuild/linux-riscv64": "0.17.17", 598 | "@esbuild/linux-s390x": "0.17.17", 599 | "@esbuild/linux-x64": "0.17.17", 600 | "@esbuild/netbsd-x64": "0.17.17", 601 | "@esbuild/openbsd-x64": "0.17.17", 602 | "@esbuild/sunos-x64": "0.17.17", 603 | "@esbuild/win32-arm64": "0.17.17", 604 | "@esbuild/win32-ia32": "0.17.17", 605 | "@esbuild/win32-x64": "0.17.17" 606 | } 607 | }, 608 | "node_modules/estree-walker": { 609 | "version": "2.0.2", 610 | "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", 611 | "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" 612 | }, 613 | "node_modules/follow-redirects": { 614 | "version": "1.15.2", 615 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 616 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", 617 | "funding": [ 618 | { 619 | "type": "individual", 620 | "url": "https://github.com/sponsors/RubenVerborgh" 621 | } 622 | ], 623 | "engines": { 624 | "node": ">=4.0" 625 | }, 626 | "peerDependenciesMeta": { 627 | "debug": { 628 | "optional": true 629 | } 630 | } 631 | }, 632 | "node_modules/form-data": { 633 | "version": "4.0.0", 634 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", 635 | "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", 636 | "dependencies": { 637 | "asynckit": "^0.4.0", 638 | "combined-stream": "^1.0.8", 639 | "mime-types": "^2.1.12" 640 | }, 641 | "engines": { 642 | "node": ">= 6" 643 | } 644 | }, 645 | "node_modules/fsevents": { 646 | "version": "2.3.2", 647 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 648 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 649 | "dev": true, 650 | "hasInstallScript": true, 651 | "optional": true, 652 | "os": [ 653 | "darwin" 654 | ], 655 | "engines": { 656 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 657 | } 658 | }, 659 | "node_modules/magic-string": { 660 | "version": "0.25.9", 661 | "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", 662 | "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", 663 | "dependencies": { 664 | "sourcemap-codec": "^1.4.8" 665 | } 666 | }, 667 | "node_modules/mime-db": { 668 | "version": "1.52.0", 669 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", 670 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", 671 | "engines": { 672 | "node": ">= 0.6" 673 | } 674 | }, 675 | "node_modules/mime-types": { 676 | "version": "2.1.35", 677 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", 678 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", 679 | "dependencies": { 680 | "mime-db": "1.52.0" 681 | }, 682 | "engines": { 683 | "node": ">= 0.6" 684 | } 685 | }, 686 | "node_modules/nanoid": { 687 | "version": "3.3.6", 688 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 689 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 690 | "funding": [ 691 | { 692 | "type": "github", 693 | "url": "https://github.com/sponsors/ai" 694 | } 695 | ], 696 | "bin": { 697 | "nanoid": "bin/nanoid.cjs" 698 | }, 699 | "engines": { 700 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 701 | } 702 | }, 703 | "node_modules/picocolors": { 704 | "version": "1.0.0", 705 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 706 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 707 | }, 708 | "node_modules/postcss": { 709 | "version": "8.4.23", 710 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", 711 | "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", 712 | "funding": [ 713 | { 714 | "type": "opencollective", 715 | "url": "https://opencollective.com/postcss/" 716 | }, 717 | { 718 | "type": "tidelift", 719 | "url": "https://tidelift.com/funding/github/npm/postcss" 720 | }, 721 | { 722 | "type": "github", 723 | "url": "https://github.com/sponsors/ai" 724 | } 725 | ], 726 | "dependencies": { 727 | "nanoid": "^3.3.6", 728 | "picocolors": "^1.0.0", 729 | "source-map-js": "^1.0.2" 730 | }, 731 | "engines": { 732 | "node": "^10 || ^12 || >=14" 733 | } 734 | }, 735 | "node_modules/proxy-from-env": { 736 | "version": "1.1.0", 737 | "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", 738 | "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" 739 | }, 740 | "node_modules/rollup": { 741 | "version": "3.20.7", 742 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.20.7.tgz", 743 | "integrity": "sha512-P7E2zezKSLhWnTz46XxjSmInrbOCiul1yf+kJccMxT56vxjHwCbDfoLbiqFgu+WQoo9ij2PkraYaBstgB2prBA==", 744 | "dev": true, 745 | "bin": { 746 | "rollup": "dist/bin/rollup" 747 | }, 748 | "engines": { 749 | "node": ">=14.18.0", 750 | "npm": ">=8.0.0" 751 | }, 752 | "optionalDependencies": { 753 | "fsevents": "~2.3.2" 754 | } 755 | }, 756 | "node_modules/source-map": { 757 | "version": "0.6.1", 758 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 759 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 760 | "engines": { 761 | "node": ">=0.10.0" 762 | } 763 | }, 764 | "node_modules/source-map-js": { 765 | "version": "1.0.2", 766 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 767 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 768 | "engines": { 769 | "node": ">=0.10.0" 770 | } 771 | }, 772 | "node_modules/sourcemap-codec": { 773 | "version": "1.4.8", 774 | "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", 775 | "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", 776 | "deprecated": "Please use @jridgewell/sourcemap-codec instead" 777 | }, 778 | "node_modules/vite": { 779 | "version": "4.3.1", 780 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.1.tgz", 781 | "integrity": "sha512-EPmfPLAI79Z/RofuMvkIS0Yr091T2ReUoXQqc5ppBX/sjFRhHKiPPF/R46cTdoci/XgeQpB23diiJxq5w30vdg==", 782 | "dev": true, 783 | "dependencies": { 784 | "esbuild": "^0.17.5", 785 | "postcss": "^8.4.21", 786 | "rollup": "^3.20.2" 787 | }, 788 | "bin": { 789 | "vite": "bin/vite.js" 790 | }, 791 | "engines": { 792 | "node": "^14.18.0 || >=16.0.0" 793 | }, 794 | "optionalDependencies": { 795 | "fsevents": "~2.3.2" 796 | }, 797 | "peerDependencies": { 798 | "@types/node": ">= 14", 799 | "less": "*", 800 | "sass": "*", 801 | "stylus": "*", 802 | "sugarss": "*", 803 | "terser": "^5.4.0" 804 | }, 805 | "peerDependenciesMeta": { 806 | "@types/node": { 807 | "optional": true 808 | }, 809 | "less": { 810 | "optional": true 811 | }, 812 | "sass": { 813 | "optional": true 814 | }, 815 | "stylus": { 816 | "optional": true 817 | }, 818 | "sugarss": { 819 | "optional": true 820 | }, 821 | "terser": { 822 | "optional": true 823 | } 824 | } 825 | }, 826 | "node_modules/vue": { 827 | "version": "3.2.47", 828 | "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.47.tgz", 829 | "integrity": "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==", 830 | "dependencies": { 831 | "@vue/compiler-dom": "3.2.47", 832 | "@vue/compiler-sfc": "3.2.47", 833 | "@vue/runtime-dom": "3.2.47", 834 | "@vue/server-renderer": "3.2.47", 835 | "@vue/shared": "3.2.47" 836 | } 837 | }, 838 | "node_modules/vue-router": { 839 | "version": "4.1.6", 840 | "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz", 841 | "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==", 842 | "dependencies": { 843 | "@vue/devtools-api": "^6.4.5" 844 | }, 845 | "funding": { 846 | "url": "https://github.com/sponsors/posva" 847 | }, 848 | "peerDependencies": { 849 | "vue": "^3.2.0" 850 | } 851 | } 852 | } 853 | } 854 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build", 8 | "preview": "vite preview" 9 | }, 10 | "dependencies": { 11 | "axios": "^1.3.6", 12 | "bootstrap": "^5.2.3", 13 | "vue": "^3.2.47", 14 | "vue-router": "^4.1.6" 15 | }, 16 | "devDependencies": { 17 | "@vitejs/plugin-vue": "^4.0.0", 18 | "vite": "^4.1.4" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fumatecdev/vue.js_flask/5452ead85dc9760d7943f9bc727b68a57d5436b3/client/public/favicon.ico -------------------------------------------------------------------------------- /client/src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 14 | -------------------------------------------------------------------------------- /client/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /client/src/components/Alert.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /client/src/components/Books.vue: -------------------------------------------------------------------------------- 1 | 193 | 194 | 345 | -------------------------------------------------------------------------------- /client/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 20 | 21 | 44 | -------------------------------------------------------------------------------- /client/src/components/Ping.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 35 | -------------------------------------------------------------------------------- /client/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import 'bootstrap/dist/css/bootstrap.css' 5 | 6 | const app = createApp(App) 7 | 8 | app.use(router) 9 | 10 | app.mount('#app') 11 | -------------------------------------------------------------------------------- /client/src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from 'vue-router' 2 | import Books from '../components/Books.vue' 3 | import Ping from '../components/Ping.vue' 4 | 5 | const router = createRouter({ 6 | history: createWebHistory(import.meta.env.BASE_URL), 7 | routes: [ 8 | { 9 | path: '/', 10 | name: 'Books', 11 | component: Books, 12 | }, 13 | { 14 | path: '/ping', 15 | name: 'ping', 16 | component: Ping 17 | }, 18 | ] 19 | }) 20 | 21 | export default router 22 | -------------------------------------------------------------------------------- /client/vite.config.js: -------------------------------------------------------------------------------- 1 | import { fileURLToPath, URL } from 'node:url' 2 | 3 | import { defineConfig } from 'vite' 4 | import vue from '@vitejs/plugin-vue' 5 | 6 | // https://vitejs.dev/config/ 7 | export default defineConfig({ 8 | plugins: [vue()], 9 | resolve: { 10 | alias: { 11 | '@': fileURLToPath(new URL('./src', import.meta.url)) 12 | } 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /server/app.py: -------------------------------------------------------------------------------- 1 | import uuid 2 | 3 | from flask import Flask, jsonify, request 4 | from flask_cors import CORS 5 | 6 | 7 | BOOKS = [ 8 | { 9 | 'id': uuid.uuid4().hex, 10 | 'title': 'On the Road', 11 | 'author': 'Jack Kerouac', 12 | 'read': True 13 | }, 14 | { 15 | 'id': uuid.uuid4().hex, 16 | 'title': 'Harry Potter and the Philosopher\'s Stone', 17 | 'author': 'J. K. Rowling', 18 | 'read': False 19 | }, 20 | { 21 | 'id': uuid.uuid4().hex, 22 | 'title': 'Green Eggs and Ham', 23 | 'author': 'Dr. Seuss', 24 | 'read': True 25 | } 26 | ] 27 | 28 | # instantiate the app 29 | app = Flask(__name__) 30 | app.config.from_object(__name__) 31 | 32 | # enable CORS 33 | CORS(app, resources={r'/*': {'origins': '*'}}) 34 | 35 | 36 | def remove_book(book_id): 37 | for book in BOOKS: 38 | if book['id'] == book_id: 39 | BOOKS.remove(book) 40 | return True 41 | return False 42 | 43 | 44 | # sanity check route 45 | @app.route('/ping', methods=['GET']) 46 | def ping_pong(): 47 | return jsonify('pong!') 48 | 49 | 50 | @app.route('/books', methods=['GET', 'POST']) 51 | def all_books(): 52 | response_object = {'status': 'success'} 53 | if request.method == 'POST': 54 | post_data = request.get_json() 55 | BOOKS.append({ 56 | 'id': uuid.uuid4().hex, 57 | 'title': post_data.get('title'), 58 | 'author': post_data.get('author'), 59 | 'read': post_data.get('read') 60 | }) 61 | response_object['message'] = 'Book added!' 62 | else: 63 | response_object['books'] = BOOKS 64 | return jsonify(response_object) 65 | 66 | 67 | @app.route('/books/', methods=['PUT', 'DELETE']) 68 | def single_book(book_id): 69 | response_object = {'status': 'success'} 70 | if request.method == 'PUT': 71 | post_data = request.get_json() 72 | remove_book(book_id) 73 | BOOKS.append({ 74 | 'id': uuid.uuid4().hex, 75 | 'title': post_data.get('title'), 76 | 'author': post_data.get('author'), 77 | 'read': post_data.get('read') 78 | }) 79 | response_object['message'] = 'Book updated!' 80 | if request.method == 'DELETE': 81 | remove_book(book_id) 82 | response_object['message'] = 'Book removed!' 83 | return jsonify(response_object) 84 | 85 | 86 | if __name__ == '__main__': 87 | app.run() 88 | -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.2.3 2 | Flask-Cors==3.0.10 3 | --------------------------------------------------------------------------------