diff --git a/astro.config.mjs b/astro.config.mjs index 89e8133ef..af30876b4 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -11,6 +11,9 @@ import react from '@astrojs/react'; // https://astro.build/config export default defineConfig({ site: 'https://roadmap.sh/', + experimental: { + rewriting: true, + }, markdown: { shikiConfig: { theme: 'dracula', diff --git a/package.json b/package.json index 4b1ce6f21..4273f588a 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,9 @@ "upgrade": "ncu -u", "roadmap-links": "node scripts/roadmap-links.cjs", "roadmap-dirs": "node scripts/roadmap-dirs.cjs", + "roadmap-assets": "tsx scripts/editor-roadmap-assets.ts", + "editor-roadmap-dirs": "tsx scripts/editor-roadmap-dirs.ts", + "editor-roadmap-content": "tsx scripts/editor-roadmap-content.ts", "roadmap-content": "node scripts/roadmap-content.cjs", "generate-renderer": "sh scripts/generate-renderer.sh", "best-practice-dirs": "node scripts/best-practice-dirs.cjs", @@ -35,7 +38,7 @@ "@resvg/resvg-js": "^2.6.2", "@types/react": "^18.3.2", "@types/react-dom": "^18.3.0", - "astro": "^4.8.3", + "astro": "^4.8.5", "clsx": "^2.1.1", "dayjs": "^1.11.11", "dom-to-image": "^2.6.0", @@ -50,6 +53,7 @@ "nanostores": "^0.10.3", "node-html-parser": "^6.1.13", "npm-check-updates": "^16.14.20", + "playwright": "^1.44.0", "prismjs": "^1.29.0", "react": "^18.3.1", "react-calendar-heatmap": "^1.9.0", @@ -62,7 +66,7 @@ "roadmap-renderer": "^1.0.6", "satori": "^0.10.13", "satori-html": "^0.3.2", - "sharp": "^0.33.3", + "sharp": "^0.33.4", "slugify": "^1.6.6", "tailwind-merge": "^2.3.0", "tailwindcss": "^3.4.3", @@ -80,10 +84,10 @@ "gh-pages": "^6.1.1", "js-yaml": "^4.1.0", "markdown-it": "^14.1.0", - "openai": "^4.45.0", + "openai": "^4.47.1", "prettier": "^3.2.5", "prettier-plugin-astro": "^0.13.0", "prettier-plugin-tailwindcss": "^0.5.14", - "tsx": "^4.10.2" + "tsx": "^4.10.4" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e56986433..0643f952a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: dependencies: '@astrojs/node': specifier: ^8.2.5 - version: 8.2.5(astro@4.8.3(@types/node@18.19.31)) + version: 8.2.5(astro@4.8.5(@types/node@18.19.31)) '@astrojs/react': specifier: ^3.3.4 version: 3.3.4(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(vite@5.2.11(@types/node@18.19.31)) @@ -19,7 +19,7 @@ importers: version: 3.1.4 '@astrojs/tailwind': specifier: ^5.1.0 - version: 5.1.0(astro@4.8.3(@types/node@18.19.31))(tailwindcss@3.4.3) + version: 5.1.0(astro@4.8.5(@types/node@18.19.31))(tailwindcss@3.4.3) '@fingerprintjs/fingerprintjs': specifier: ^4.3.0 version: 4.3.0 @@ -39,8 +39,8 @@ importers: specifier: ^18.3.0 version: 18.3.0 astro: - specifier: ^4.8.3 - version: 4.8.3(@types/node@18.19.31) + specifier: ^4.8.5 + version: 4.8.5(@types/node@18.19.31) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -83,6 +83,9 @@ importers: npm-check-updates: specifier: ^16.14.20 version: 16.14.20 + playwright: + specifier: ^1.44.0 + version: 1.44.0 prismjs: specifier: ^1.29.0 version: 1.29.0 @@ -120,8 +123,8 @@ importers: specifier: ^0.3.2 version: 0.3.2 sharp: - specifier: ^0.33.3 - version: 0.33.3 + specifier: ^0.33.4 + version: 0.33.4 slugify: specifier: ^1.6.6 version: 1.6.6 @@ -169,8 +172,8 @@ importers: specifier: ^14.1.0 version: 14.1.0 openai: - specifier: ^4.45.0 - version: 4.45.0(encoding@0.1.13) + specifier: ^4.47.1 + version: 4.47.1(encoding@0.1.13) prettier: specifier: ^3.2.5 version: 3.2.5 @@ -181,8 +184,8 @@ importers: specifier: ^0.5.14 version: 0.5.14(prettier-plugin-astro@0.13.0)(prettier@3.2.5) tsx: - specifier: ^4.10.2 - version: 4.10.2 + specifier: ^4.10.4 + version: 4.10.4 packages: @@ -704,14 +707,14 @@ packages: '@gar/promisify@1.1.3': resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - '@img/sharp-darwin-arm64@0.33.3': - resolution: {integrity: sha512-FaNiGX1MrOuJ3hxuNzWgsT/mg5OHG/Izh59WW2mk1UwYHUwtfbhk5QNKYZgxf0pLOhx9ctGiGa2OykD71vOnSw==} + '@img/sharp-darwin-arm64@0.33.4': + resolution: {integrity: sha512-p0suNqXufJs9t3RqLBO6vvrgr5OhgbWp76s5gTRvdmxmuv9E1rcaqGUsl3l4mKVmXPkTkTErXediAui4x+8PSA==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.3': - resolution: {integrity: sha512-2QeSl7QDK9ru//YBT4sQkoq7L0EAJZA3rtV+v9p8xTKl4U1bUqTIaCnoC7Ctx2kCjQgwFXDasOtPTCT8eCTXvw==} + '@img/sharp-darwin-x64@0.33.4': + resolution: {integrity: sha512-0l7yRObwtTi82Z6ebVI2PnHT8EB2NxBgpK2MiKJZJ7cz32R4lxd001ecMhzzsZig3Yv9oclvqqdV93jo9hy+Dw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [darwin] @@ -764,55 +767,55 @@ packages: cpu: [x64] os: [linux] - '@img/sharp-linux-arm64@0.33.3': - resolution: {integrity: sha512-Zf+sF1jHZJKA6Gor9hoYG2ljr4wo9cY4twaxgFDvlG0Xz9V7sinsPp8pFd1XtlhTzYo0IhDbl3rK7P6MzHpnYA==} + '@img/sharp-linux-arm64@0.33.4': + resolution: {integrity: sha512-2800clwVg1ZQtxwSoTlHvtm9ObgAax7V6MTAB/hDT945Tfyy3hVkmiHpeLPCKYqYR1Gcmv1uDZ3a4OFwkdBL7Q==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - '@img/sharp-linux-arm@0.33.3': - resolution: {integrity: sha512-Q7Ee3fFSC9P7vUSqVEF0zccJsZ8GiiCJYGWDdhEjdlOeS9/jdkyJ6sUSPj+bL8VuOYFSbofrW0t/86ceVhx32w==} + '@img/sharp-linux-arm@0.33.4': + resolution: {integrity: sha512-RUgBD1c0+gCYZGCCe6mMdTiOFS0Zc/XrN0fYd6hISIKcDUbAW5NtSQW9g/powkrXYm6Vzwd6y+fqmExDuCdHNQ==} engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm] os: [linux] - '@img/sharp-linux-s390x@0.33.3': - resolution: {integrity: sha512-vFk441DKRFepjhTEH20oBlFrHcLjPfI8B0pMIxGm3+yilKyYeHEVvrZhYFdqIseSclIqbQ3SnZMwEMWonY5XFA==} - engines: {glibc: '>=2.28', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} + '@img/sharp-linux-s390x@0.33.4': + resolution: {integrity: sha512-h3RAL3siQoyzSoH36tUeS0PDmb5wINKGYzcLB5C6DIiAn2F3udeFAum+gj8IbA/82+8RGCTn7XW8WTFnqag4tQ==} + engines: {glibc: '>=2.31', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [s390x] os: [linux] - '@img/sharp-linux-x64@0.33.3': - resolution: {integrity: sha512-Q4I++herIJxJi+qmbySd072oDPRkCg/SClLEIDh5IL9h1zjhqjv82H0Seupd+q2m0yOfD+/fJnjSoDFtKiHu2g==} + '@img/sharp-linux-x64@0.33.4': + resolution: {integrity: sha512-GoR++s0XW9DGVi8SUGQ/U4AeIzLdNjHka6jidVwapQ/JebGVQIpi52OdyxCNVRE++n1FCLzjDovJNozif7w/Aw==} engines: {glibc: '>=2.26', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - '@img/sharp-linuxmusl-arm64@0.33.3': - resolution: {integrity: sha512-qnDccehRDXadhM9PM5hLvcPRYqyFCBN31kq+ErBSZtZlsAc1U4Z85xf/RXv1qolkdu+ibw64fUDaRdktxTNP9A==} + '@img/sharp-linuxmusl-arm64@0.33.4': + resolution: {integrity: sha512-nhr1yC3BlVrKDTl6cO12gTpXMl4ITBUZieehFvMntlCXFzH2bvKG76tBL2Y/OqhupZt81pR7R+Q5YhJxW0rGgQ==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [arm64] os: [linux] - '@img/sharp-linuxmusl-x64@0.33.3': - resolution: {integrity: sha512-Jhchim8kHWIU/GZ+9poHMWRcefeaxFIs9EBqf9KtcC14Ojk6qua7ghKiPs0sbeLbLj/2IGBtDcxHyjCdYWkk2w==} + '@img/sharp-linuxmusl-x64@0.33.4': + resolution: {integrity: sha512-uCPTku0zwqDmZEOi4ILyGdmW76tH7dm8kKlOIV1XC5cLyJ71ENAAqarOHQh0RLfpIpbV5KOpXzdU6XkJtS0daw==} engines: {musl: '>=1.2.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [linux] - '@img/sharp-wasm32@0.33.3': - resolution: {integrity: sha512-68zivsdJ0koE96stdUfM+gmyaK/NcoSZK5dV5CAjES0FUXS9lchYt8LAB5rTbM7nlWtxaU/2GON0HVN6/ZYJAQ==} + '@img/sharp-wasm32@0.33.4': + resolution: {integrity: sha512-Bmmauh4sXUsUqkleQahpdNXKvo+wa1V9KhT2pDA4VJGKwnKMJXiSTGphn0gnJrlooda0QxCtXc6RX1XAU6hMnQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [wasm32] - '@img/sharp-win32-ia32@0.33.3': - resolution: {integrity: sha512-CyimAduT2whQD8ER4Ux7exKrtfoaUiVr7HG0zZvO0XTFn2idUWljjxv58GxNTkFb8/J9Ub9AqITGkJD6ZginxQ==} + '@img/sharp-win32-ia32@0.33.4': + resolution: {integrity: sha512-99SJ91XzUhYHbx7uhK3+9Lf7+LjwMGQZMDlO/E/YVJ7Nc3lyDFZPGhjwiYdctoH2BOzW9+TnfqcaMKt0jHLdqw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.3': - resolution: {integrity: sha512-viT4fUIDKnli3IfOephGnolMzhz5VaTvDRkYqtZxOMIoMQ4MrAziO7pT1nVnOt2FAm7qW5aa+CCc13aEY6Le0g==} + '@img/sharp-win32-x64@0.33.4': + resolution: {integrity: sha512-3QLocdTRVIrFNye5YocZl+KKpYKP+fksi1QhmOArgx7GyhIbQp/WrJRu176jm8IxromS7RIkzMiMINVdBtC8Aw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0', yarn: '>=3.2.0'} cpu: [x64] os: [win32] @@ -1506,8 +1509,8 @@ packages: resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} engines: {node: '>=0.10.0'} - astro@4.8.3: - resolution: {integrity: sha512-pgIKopkmAUXY3EJHdG7zQpudtBzYAsd94A1R7jmLpH2LFZvzHEkAdHnunmSVmgikJCNqtEo3bUCHgLnCPQaN1g==} + astro@4.8.5: + resolution: {integrity: sha512-h+t4VGLPBk6KjIiJnYGotJ16wsLIdmNVSvnwEk51XhqZ5T2VlbozgDtgDi6y3qP3mqkhpN3Q39YQORhVeuEYsg==} engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0, npm: '>=9.6.5', pnpm: '>=7.1.0'} hasBin: true @@ -2155,8 +2158,8 @@ packages: resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} engines: {node: '>=16'} - get-tsconfig@4.7.3: - resolution: {integrity: sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==} + get-tsconfig@4.7.5: + resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} gh-pages@6.1.1: resolution: {integrity: sha512-upnohfjBwN5hBP9w2dPE7HO5JJTHzSGMV1JrLrHvNuqmjoYHg6TBrCcnEoorjG/e0ejbuvnwyKMdTyM40PEByw==} @@ -3032,8 +3035,8 @@ packages: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} - openai@4.45.0: - resolution: {integrity: sha512-uszUQrl9eQPCA9a7Zml+Eizb3mG0JDd8zUl528OM6Ccn039dqbOmUivL5s8zUM6iJMRMvNGRMXS9yuuR1Bv2sw==} + openai@4.47.1: + resolution: {integrity: sha512-WWSxhC/69ZhYWxH/OBsLEirIjUcfpQ5+ihkXKp06hmeYXgBBIUCa9IptMzYx6NdkiOCsSGYCnTIsxaic3AjRCQ==} hasBin: true ora@8.0.1: @@ -3586,8 +3589,8 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sharp@0.33.3: - resolution: {integrity: sha512-vHUeXJU1UvlO/BNwTpT0x/r53WkLUVxrmb5JTgW92fdFCFk0ispLMAeu/jPO2vjkXM1fYUi3K7/qcLF47pwM1A==} + sharp@0.33.4: + resolution: {integrity: sha512-7i/dt5kGl7qR4gwPRD2biwD2/SvBn3O04J77XKFgL2OnZtQw+AG9wnuS/csmu80nPRHLYE9E41fyEiG8nhH6/Q==} engines: {libvips: '>=8.15.2', node: ^18.17.0 || ^20.3.0 || >=21.0.0} shebang-command@2.0.0: @@ -3831,8 +3834,8 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tsx@4.10.2: - resolution: {integrity: sha512-gOfACgv1ElsIjvt7Fp0rMJKGnMGjox0JfGOfX3kmZCV/yZumaNqtHGKBXt1KgaYS9KjDOmqGeI8gHk/W7kWVZg==} + tsx@4.10.4: + resolution: {integrity: sha512-Gtg9qnZWNqC/OtcgiXfoAUdAKx3/cgKOYvEocAsv+m21MV/eKpV/WUjRXe6/sDCaGBl2/v8S6v29BpUnGMCX5A==} engines: {node: '>=18.0.0'} hasBin: true @@ -4175,9 +4178,9 @@ snapshots: transitivePeerDependencies: - supports-color - '@astrojs/node@8.2.5(astro@4.8.3(@types/node@18.19.31))': + '@astrojs/node@8.2.5(astro@4.8.5(@types/node@18.19.31))': dependencies: - astro: 4.8.3(@types/node@18.19.31) + astro: 4.8.5(@types/node@18.19.31) send: 0.18.0 server-destroy: 1.0.1 transitivePeerDependencies: @@ -4205,9 +4208,9 @@ snapshots: stream-replace-string: 2.0.0 zod: 3.23.4 - '@astrojs/tailwind@5.1.0(astro@4.8.3(@types/node@18.19.31))(tailwindcss@3.4.3)': + '@astrojs/tailwind@5.1.0(astro@4.8.5(@types/node@18.19.31))(tailwindcss@3.4.3)': dependencies: - astro: 4.8.3(@types/node@18.19.31) + astro: 4.8.5(@types/node@18.19.31) autoprefixer: 10.4.19(postcss@8.4.38) postcss: 8.4.38 postcss-load-config: 4.0.2(postcss@8.4.38) @@ -4309,7 +4312,7 @@ snapshots: '@babel/helper-hoist-variables@7.22.5': dependencies: - '@babel/types': 7.24.5 + '@babel/types': 7.24.0 '@babel/helper-module-imports@7.24.3': dependencies: @@ -4634,12 +4637,12 @@ snapshots: '@gar/promisify@1.1.3': {} - '@img/sharp-darwin-arm64@0.33.3': + '@img/sharp-darwin-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-arm64': 1.0.2 optional: true - '@img/sharp-darwin-x64@0.33.3': + '@img/sharp-darwin-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-darwin-x64': 1.0.2 optional: true @@ -4668,45 +4671,45 @@ snapshots: '@img/sharp-libvips-linuxmusl-x64@1.0.2': optional: true - '@img/sharp-linux-arm64@0.33.3': + '@img/sharp-linux-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-arm64': 1.0.2 optional: true - '@img/sharp-linux-arm@0.33.3': + '@img/sharp-linux-arm@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-arm': 1.0.2 optional: true - '@img/sharp-linux-s390x@0.33.3': + '@img/sharp-linux-s390x@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-s390x': 1.0.2 optional: true - '@img/sharp-linux-x64@0.33.3': + '@img/sharp-linux-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-linux-x64': 1.0.2 optional: true - '@img/sharp-linuxmusl-arm64@0.33.3': + '@img/sharp-linuxmusl-arm64@0.33.4': optionalDependencies: '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 optional: true - '@img/sharp-linuxmusl-x64@0.33.3': + '@img/sharp-linuxmusl-x64@0.33.4': optionalDependencies: '@img/sharp-libvips-linuxmusl-x64': 1.0.2 optional: true - '@img/sharp-wasm32@0.33.3': + '@img/sharp-wasm32@0.33.4': dependencies: '@emnapi/runtime': 1.1.1 optional: true - '@img/sharp-win32-ia32@0.33.3': + '@img/sharp-win32-ia32@0.33.4': optional: true - '@img/sharp-win32-x64@0.33.3': + '@img/sharp-win32-x64@0.33.4': optional: true '@isaacs/cliui@8.0.2': @@ -5409,7 +5412,7 @@ snapshots: array-uniq@1.0.3: {} - astro@4.8.3(@types/node@18.19.31): + astro@4.8.5(@types/node@18.19.31): dependencies: '@astrojs/compiler': 2.8.0 '@astrojs/internal-helpers': 0.4.0 @@ -5475,7 +5478,7 @@ snapshots: zod: 3.23.8 zod-to-json-schema: 3.23.0(zod@3.23.8) optionalDependencies: - sharp: 0.33.3 + sharp: 0.33.4 transitivePeerDependencies: - '@types/node' - less @@ -6132,7 +6135,7 @@ snapshots: get-stream@8.0.1: {} - get-tsconfig@4.7.3: + get-tsconfig@4.7.5: dependencies: resolve-pkg-maps: 1.0.0 @@ -7278,7 +7281,7 @@ snapshots: dependencies: mimic-fn: 4.0.0 - openai@4.45.0(encoding@0.1.13): + openai@4.47.1(encoding@0.1.13): dependencies: '@types/node': 18.19.31 '@types/node-fetch': 2.6.11 @@ -7886,14 +7889,14 @@ snapshots: setprototypeof@1.2.0: {} - sharp@0.33.3: + sharp@0.33.4: dependencies: color: 4.2.3 detect-libc: 2.0.3 - semver: 7.6.0 + semver: 7.6.2 optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.3 - '@img/sharp-darwin-x64': 0.33.3 + '@img/sharp-darwin-arm64': 0.33.4 + '@img/sharp-darwin-x64': 0.33.4 '@img/sharp-libvips-darwin-arm64': 1.0.2 '@img/sharp-libvips-darwin-x64': 1.0.2 '@img/sharp-libvips-linux-arm': 1.0.2 @@ -7902,15 +7905,15 @@ snapshots: '@img/sharp-libvips-linux-x64': 1.0.2 '@img/sharp-libvips-linuxmusl-arm64': 1.0.2 '@img/sharp-libvips-linuxmusl-x64': 1.0.2 - '@img/sharp-linux-arm': 0.33.3 - '@img/sharp-linux-arm64': 0.33.3 - '@img/sharp-linux-s390x': 0.33.3 - '@img/sharp-linux-x64': 0.33.3 - '@img/sharp-linuxmusl-arm64': 0.33.3 - '@img/sharp-linuxmusl-x64': 0.33.3 - '@img/sharp-wasm32': 0.33.3 - '@img/sharp-win32-ia32': 0.33.3 - '@img/sharp-win32-x64': 0.33.3 + '@img/sharp-linux-arm': 0.33.4 + '@img/sharp-linux-arm64': 0.33.4 + '@img/sharp-linux-s390x': 0.33.4 + '@img/sharp-linux-x64': 0.33.4 + '@img/sharp-linuxmusl-arm64': 0.33.4 + '@img/sharp-linuxmusl-x64': 0.33.4 + '@img/sharp-wasm32': 0.33.4 + '@img/sharp-win32-ia32': 0.33.4 + '@img/sharp-win32-x64': 0.33.4 shebang-command@2.0.0: dependencies: @@ -8160,10 +8163,10 @@ snapshots: tslib@2.6.2: {} - tsx@4.10.2: + tsx@4.10.4: dependencies: esbuild: 0.20.2 - get-tsconfig: 4.7.3 + get-tsconfig: 4.7.5 optionalDependencies: fsevents: 2.3.3 diff --git a/public/pdfs/roadmaps/api.pdf b/public/pdfs/roadmaps/api.pdf new file mode 100644 index 000000000..96e45d065 Binary files /dev/null and b/public/pdfs/roadmaps/api.pdf differ diff --git a/public/roadmaps/api.png b/public/roadmaps/api.png new file mode 100644 index 000000000..a8854c19b Binary files /dev/null and b/public/roadmaps/api.png differ diff --git a/scripts/editor-roadmap-assets.ts b/scripts/editor-roadmap-assets.ts new file mode 100644 index 000000000..df33e97f4 --- /dev/null +++ b/scripts/editor-roadmap-assets.ts @@ -0,0 +1,75 @@ +import playwright from 'playwright'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Usage: tsx ./scripts/editor-roadmap-dirs.ts + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +console.log(`Launching chromium`); +const browser = await playwright.chromium.launch(); +const context = await browser.newContext(); +const page = await context.newPage(); + +const pageUrl = `http://localhost:3000/${roadmapId}/svg`; +console.log(`Opening page ${pageUrl}`); +await page.goto(pageUrl); +await page.waitForSelector('#resource-svg-wrap'); +console.log(`Generating PDF ${pageUrl}`); +await page.pdf({ + path: `./public/pdfs/roadmaps/${roadmapId}.pdf`, + margin: { top: 0, right: 0, bottom: 0, left: 0 }, + height: roadmapFrontmatter?.dimensions?.height || 2000, + width: roadmapFrontmatter?.dimensions?.width || 968, +}); + +// @todo generate png from the pdf +console.log(`Generating png ${pageUrl}`); +await page.locator('#resource-svg-wrap>svg').screenshot({ + path: `./public/roadmaps/${roadmapId}.png`, + type: 'png', + scale: 'device', +}); + +await browser.close(); diff --git a/scripts/editor-roadmap-content.ts b/scripts/editor-roadmap-content.ts new file mode 100644 index 000000000..2fd034e89 --- /dev/null +++ b/scripts/editor-roadmap-content.ts @@ -0,0 +1,185 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { Edge, Node } from 'reactflow'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { slugify } from '../src/lib/slugger'; +import OpenAI from 'openai'; +import { runPromisesInBatchSequentially } from '../src/lib/promise'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Usage: tsx ./scripts/editor-roadmap-content.ts +const OPEN_AI_API_KEY = process.env.OPEN_AI_API_KEY; +console.log('OPEN_AI_API_KEY:', OPEN_AI_API_KEY); +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +const roadmapDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.json`, +); +const roadmapContent = await fs.readFile(roadmapDir, 'utf-8'); +let { nodes, edges } = JSON.parse(roadmapContent) as { + nodes: Node[]; + edges: Edge[]; +}; +const enrichedNodes = nodes + .filter( + (node) => + node?.type && + ['topic', 'subtopic'].includes(node.type) && + node.data?.label, + ) + .map((node) => { + // Because we only need the parent id and title for subtopics + if (node.type !== 'subtopic') { + return node; + } + + const parentNodeId = + edges.find((edge) => edge.target === node.id)?.source || ''; + const parentNode = nodes.find((n) => n.id === parentNodeId); + + return { + ...node, + parentId: parentNodeId, + parentTitle: parentNode?.data?.label || '', + }; + }) as (Node & { parentId?: string; parentTitle?: string })[]; + +const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'); +const stats = await fs.stat(roadmapContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); +} + +let openai: OpenAI | undefined; +if (OPEN_AI_API_KEY) { + openai = new OpenAI({ + apiKey: OPEN_AI_API_KEY, + }); +} + +function writeTopicContent( + roadmapTitle: string, + childTopic: string, + parentTopic?: string, +) { + let prompt = `I will give you a topic and you need to write a brief introduction for that with regards to "${roadmapTitle}". Your format should be as follows and be in strictly markdown format: + +# (Put a heading for the topic without adding parent "Subtopic in Topic" or "Topic in Roadmap" etc.) + +(Write me a brief introduction for the topic with regards to "${roadmapTitle}") +`; + + if (!parentTopic) { + prompt += `First topic is: ${childTopic}`; + } else { + prompt += `First topic is: ${childTopic} under ${parentTopic}`; + } + + return new Promise((resolve, reject) => { + openai?.chat.completions + .create({ + model: 'gpt-4', + messages: [ + { + role: 'user', + content: prompt, + }, + ], + }) + .then((response) => { + const article = response.choices[0].message.content; + + resolve(article); + }) + .catch((err) => { + reject(err); + }); + }); +} + +async function writeNodeContent(node: Node & { parentTitle?: string }) { + const nodeDirPattern = `${slugify(node.data.label)}@${node.id}.md`; + if (!roadmapContentFiles.includes(nodeDirPattern)) { + console.log(`Missing file for: ${nodeDirPattern}`); + return; + } + + const nodeDir = path.join(roadmapContentDir, nodeDirPattern); + const nodeContent = await fs.readFile(nodeDir, 'utf-8'); + const isFileEmpty = !nodeContent.replace(`# ${node.data.label}`, '').trim(); + if (!isFileEmpty) { + console.log(`❌ Ignoring ${nodeDirPattern}. Not empty.`); + return; + } + + const topic = node.data.label; + const parentTopic = node.parentTitle; + + console.log(`⏳ Generating content for ${topic}...`); + let newContentFile = ''; + if (OPEN_AI_API_KEY) { + newContentFile = (await writeTopicContent( + roadmapFrontmatter.title, + topic, + parentTopic, + )) as string; + } else { + newContentFile = `# ${topic}`; + } + + await fs.writeFile(nodeDir, newContentFile, 'utf-8'); + console.log(`✅ Content generated for ${topic}`); +} + +let roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, +}); + +if (!OPEN_AI_API_KEY) { + console.log('----------------------------------------'); + console.log('OPEN_AI_API_KEY not found. Skipping openai api calls...'); + console.log('----------------------------------------'); +} +const promises = enrichedNodes.map((node) => () => writeNodeContent(node)); +await runPromisesInBatchSequentially(promises, 20); +console.log('✅ All content generated'); diff --git a/scripts/editor-roadmap-dirs.ts b/scripts/editor-roadmap-dirs.ts new file mode 100644 index 000000000..ce7aeb145 --- /dev/null +++ b/scripts/editor-roadmap-dirs.ts @@ -0,0 +1,86 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import type { Node } from 'reactflow'; +import matter from 'gray-matter'; +import type { RoadmapFrontmatter } from '../src/lib/roadmap'; +import { slugify } from '../src/lib/slugger'; + +// ERROR: `__dirname` is not defined in ES module scope +// https://iamwebwiz.medium.com/how-to-fix-dirname-is-not-defined-in-es-module-scope-34d94a86694d +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Usage: tsx ./scripts/editor-roadmap-dirs.ts + +// Directory containing the roadmaps +const ROADMAP_CONTENT_DIR = path.join(__dirname, '../src/data/roadmaps'); +const roadmapId = process.argv[2]; + +const allowedRoadmapIds = await fs.readdir(ROADMAP_CONTENT_DIR); +if (!roadmapId) { + console.error('Roadmap Id is required'); + process.exit(1); +} + +if (!allowedRoadmapIds.includes(roadmapId)) { + console.error(`Invalid roadmap key ${roadmapId}`); + console.error(`Allowed keys are ${allowedRoadmapIds.join(', ')}`); + process.exit(1); +} + +const roadmapFrontmatterDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.md`, +); +const roadmapFrontmatterRaw = await fs.readFile(roadmapFrontmatterDir, 'utf-8'); +const { data } = matter(roadmapFrontmatterRaw); + +const roadmapFrontmatter = data as RoadmapFrontmatter; +if (!roadmapFrontmatter) { + console.error('Invalid roadmap frontmatter'); + process.exit(1); +} + +if (roadmapFrontmatter.renderer !== 'editor') { + console.error('Only Editor Rendered Roadmaps are allowed'); + process.exit(1); +} + +const roadmapDir = path.join( + ROADMAP_CONTENT_DIR, + roadmapId, + `${roadmapId}.json`, +); +const roadmapContent = await fs.readFile(roadmapDir, 'utf-8'); +let { nodes } = JSON.parse(roadmapContent) as { + nodes: Node[]; +}; +nodes = nodes.filter( + (node) => + node?.type && ['topic', 'subtopic'].includes(node.type) && node.data?.label, +); + +const roadmapContentDir = path.join(ROADMAP_CONTENT_DIR, roadmapId, 'content'); +const stats = await fs.stat(roadmapContentDir).catch(() => null); +if (!stats || !stats.isDirectory()) { + await fs.mkdir(roadmapContentDir, { recursive: true }); +} + +const roadmapContentFiles = await fs.readdir(roadmapContentDir, { + recursive: true, +}); + +nodes.forEach(async (node, index) => { + const nodeDirPattern = `${slugify(node.data.label)}@${node.id}.md`; + if (roadmapContentFiles.includes(nodeDirPattern)) { + console.log(`Skipping ${nodeDirPattern}`); + return; + } + + await fs.writeFile( + path.join(roadmapContentDir, nodeDirPattern), + `# ${node.data.label}`, + ); +}); diff --git a/src/components/CommandMenu/CommandMenu.tsx b/src/components/CommandMenu/CommandMenu.tsx index 5512fb0f1..fcfb8a8e8 100644 --- a/src/components/CommandMenu/CommandMenu.tsx +++ b/src/components/CommandMenu/CommandMenu.tsx @@ -18,6 +18,7 @@ import { GuideIcon } from '../ReactIcons/GuideIcon.tsx'; import { HomeIcon } from '../ReactIcons/HomeIcon.tsx'; import { VideoIcon } from '../ReactIcons/VideoIcon.tsx'; import { cn } from '../../lib/classname.ts'; +import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts'; export type PageType = { id: string; @@ -27,6 +28,7 @@ export type PageType = { icon?: ReactElement; isProtected?: boolean; metadata?: Record; + renderer?: AllowedRoadmapRenderer; }; const defaultPages: PageType[] = [ diff --git a/src/components/CreateTeam/RoadmapSelector.tsx b/src/components/CreateTeam/RoadmapSelector.tsx index c7462361f..1c82f8087 100644 --- a/src/components/CreateTeam/RoadmapSelector.tsx +++ b/src/components/CreateTeam/RoadmapSelector.tsx @@ -24,6 +24,7 @@ export type TeamResourceConfig = { topics?: number; sharedTeamMemberIds: string[]; sharedFriendIds: string[]; + defaultRoadmapId?: string; }[]; type RoadmapSelectorProps = { @@ -106,6 +107,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) { } pageProgressMessage.set(`Adding roadmap to team`); + const renderer = allRoadmaps.find((r) => r.id === roadmapId)?.renderer; const { error, response } = await httpPut( `${ import.meta.env.PUBLIC_API_URL @@ -115,6 +117,7 @@ export function RoadmapSelector(props: RoadmapSelectorProps) { resourceId: roadmapId, resourceType: 'roadmap', removed: [], + renderer: renderer || 'balsamiq', }, ); @@ -124,6 +127,9 @@ export function RoadmapSelector(props: RoadmapSelectorProps) { } setTeamResources(response); + if (renderer === 'editor') { + setShowSelectRoadmapModal(false); + } } useEffect(() => { diff --git a/src/components/EditorRoadmap/EditorRoadmap.tsx b/src/components/EditorRoadmap/EditorRoadmap.tsx new file mode 100644 index 000000000..d69974240 --- /dev/null +++ b/src/components/EditorRoadmap/EditorRoadmap.tsx @@ -0,0 +1,85 @@ +import { useEffect, useState, type CSSProperties } from 'react'; +import { + EditorRoadmapRenderer, + type RoadmapRendererProps, +} from './EditorRoadmapRenderer'; +import { Spinner } from '../ReactIcons/Spinner'; +import type { ResourceType } from '../../lib/resource-progress'; +import { httpGet } from '../../lib/http'; +import { ProgressNudge } from '../FrameRenderer/ProgressNudge'; + +type EditorRoadmapProps = { + resourceId: string; + resourceType?: ResourceType; + dimensions: { + width: number; + height: number; + }; +}; + +export function EditorRoadmap(props: EditorRoadmapProps) { + const { resourceId, resourceType = 'roadmap', dimensions } = props; + + const [isLoading, setIsLoading] = useState(true); + const [roadmapData, setRoadmapData] = useState< + Omit | undefined + >(undefined); + + const loadRoadmapData = async () => { + setIsLoading(true); + const { response, error } = await httpGet< + Omit + >(`/${resourceId}.json`); + + if (error) { + console.error(error); + return; + } + + setRoadmapData(response); + setIsLoading(false); + }; + + useEffect(() => { + loadRoadmapData().finally(); + }, [resourceId]); + + if (!roadmapData || isLoading) { + return ( +
+
+ +
+
+ ); + } + + return ( +
+ + +
+ ); +} diff --git a/src/components/EditorRoadmap/EditorRoadmapRenderer.css b/src/components/EditorRoadmap/EditorRoadmapRenderer.css new file mode 100644 index 000000000..c5ae89fba --- /dev/null +++ b/src/components/EditorRoadmap/EditorRoadmapRenderer.css @@ -0,0 +1,56 @@ +svg text tspan { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeSpeed; +} + +svg > g[data-type='topic'], +svg > g[data-type='subtopic'], +svg g[data-type='link-item'], +svg > g[data-type='button'] { + cursor: pointer; +} + +svg > g[data-type='topic']:hover > rect { + fill: #d6d700; +} + +svg > g[data-type='subtopic']:hover > rect { + fill: #f3c950; +} +svg > g[data-type='button']:hover { + opacity: 0.8; +} +svg g[data-type='link-item']:hover { + opacity: 0.8; +} + +svg .done rect { + fill: #cbcbcb !important; +} + +svg .done text, +svg .skipped text { + text-decoration: line-through; +} + +svg > g[data-type='topic'].learning > rect + text, +svg > g[data-type='topic'].done > rect + text { + fill: black; +} + +svg > g[data-type='subtipic'].done > rect + text, +svg > g[data-type='subtipic'].learning > rect + text { + fill: #cbcbcb; +} + +svg .learning rect { + fill: #dad1fd !important; +} +svg .learning text { + text-decoration: underline; +} + +svg .skipped rect { + fill: #496b69 !important; +} diff --git a/src/components/EditorRoadmap/EditorRoadmapRenderer.tsx b/src/components/EditorRoadmap/EditorRoadmapRenderer.tsx new file mode 100644 index 000000000..b964b2319 --- /dev/null +++ b/src/components/EditorRoadmap/EditorRoadmapRenderer.tsx @@ -0,0 +1,176 @@ +import { useCallback, useEffect, useRef } from 'react'; +import './EditorRoadmapRenderer.css'; +import { + renderResourceProgress, + updateResourceProgress, + type ResourceProgressType, + renderTopicProgress, + refreshProgressCounters, +} from '../../lib/resource-progress'; +import { pageProgressMessage } from '../../stores/page'; +import { useToast } from '../../hooks/use-toast'; +import type { Edge, Node } from 'reactflow'; +import { Renderer } from '../../../editor/renderer'; +import { slugify } from '../../lib/slugger'; + +export type RoadmapRendererProps = { + resourceId: string; + nodes: Node[]; + edges: Edge[]; + dimensions: { + width: number; + height: number; + }; +}; + +type RoadmapNodeDetails = { + nodeId: string; + nodeType: string; + targetGroup: SVGElement; + title?: string; +}; + +function getNodeDetails(svgElement: SVGElement): RoadmapNodeDetails | null { + const targetGroup = (svgElement?.closest('g') as SVGElement) || {}; + + const nodeId = targetGroup?.dataset?.nodeId; + const nodeType = targetGroup?.dataset?.type; + const title = targetGroup?.dataset?.title; + if (!nodeId || !nodeType) { + return null; + } + + return { nodeId, nodeType, targetGroup, title }; +} + +const allowedNodeTypes = ['topic', 'subtopic', 'button', 'link-item']; + +export function EditorRoadmapRenderer(props: RoadmapRendererProps) { + const { resourceId, nodes = [], edges = [] } = props; + const roadmapRef = useRef(null); + + const toast = useToast(); + + async function updateTopicStatus( + topicId: string, + newStatus: ResourceProgressType, + ) { + pageProgressMessage.set('Updating progress'); + updateResourceProgress( + { + resourceId, + resourceType: 'roadmap', + topicId, + }, + newStatus, + ) + .then(() => { + renderTopicProgress(topicId, newStatus); + }) + .catch((err) => { + toast.error('Something went wrong, please try again.'); + console.error(err); + }) + .finally(() => { + pageProgressMessage.set(''); + refreshProgressCounters(); + }); + + return; + } + + const handleSvgClick = useCallback((e: MouseEvent) => { + const target = e.target as SVGElement; + const { nodeId, nodeType, targetGroup, title } = + getNodeDetails(target) || {}; + + if (!nodeId || !nodeType || !allowedNodeTypes.includes(nodeType)) { + return; + } + + if (nodeType === 'button' || nodeType === 'link-item') { + const link = targetGroup?.dataset?.link || ''; + const isExternalLink = link.startsWith('http'); + if (isExternalLink) { + window.open(link, '_blank'); + } else { + window.location.href = link; + } + return; + } + + const isCurrentStatusLearning = targetGroup?.classList.contains('learning'); + const isCurrentStatusSkipped = targetGroup?.classList.contains('skipped'); + + if (e.shiftKey) { + e.preventDefault(); + updateTopicStatus( + nodeId, + isCurrentStatusLearning ? 'pending' : 'learning', + ); + return; + } else if (e.altKey) { + e.preventDefault(); + updateTopicStatus(nodeId, isCurrentStatusSkipped ? 'pending' : 'skipped'); + return; + } + + if (!title) { + return; + } + const detailsPattern = `${slugify(title)}@${nodeId}`; + window.dispatchEvent( + new CustomEvent('roadmap.node.click', { + detail: { + topicId: detailsPattern, + resourceId, + resourceType: 'roadmap', + }, + }), + ); + }, []); + + const handleSvgRightClick = useCallback((e: MouseEvent) => { + e.preventDefault(); + + const target = e.target as SVGElement; + const { nodeId, nodeType, targetGroup } = getNodeDetails(target) || {}; + if (!nodeId || !nodeType || !allowedNodeTypes.includes(nodeType)) { + return; + } + + if (nodeType === 'button') { + return; + } + + const isCurrentStatusDone = targetGroup?.classList.contains('done'); + updateTopicStatus(nodeId, isCurrentStatusDone ? 'pending' : 'done'); + }, []); + + useEffect(() => { + if (!roadmapRef?.current) { + return; + } + roadmapRef?.current?.addEventListener('click', handleSvgClick); + roadmapRef?.current?.addEventListener('contextmenu', handleSvgRightClick); + + return () => { + roadmapRef?.current?.removeEventListener('click', handleSvgClick); + roadmapRef?.current?.removeEventListener( + 'contextmenu', + handleSvgRightClick, + ); + }; + }, []); + + return ( + { + roadmapRef.current?.setAttribute('data-renderer', 'editor'); + renderResourceProgress('roadmap', resourceId).finally(); + }} + /> + ); +} diff --git a/src/components/FrameRenderer/FrameRenderer.css b/src/components/FrameRenderer/FrameRenderer.css index e2c9e0657..a3b9514ce 100644 --- a/src/components/FrameRenderer/FrameRenderer.css +++ b/src/components/FrameRenderer/FrameRenderer.css @@ -52,7 +52,7 @@ svg .done rect { fill: #cbcbcb !important; } -svg .done rect[stroke="rgb(255,229,153)"] { +svg .done rect[stroke='rgb(255,229,153)'] { stroke: #cbcbcb !important; } @@ -133,10 +133,12 @@ svg .removed path { } } -#customized-roadmap #resource-svg-wrap g:not([class]), -#customized-roadmap #resource-svg-wrap circle, -#customized-roadmap #resource-svg-wrap path[stroke='#fff'], -#customized-roadmap #resource-svg-wrap g[data-group-id$='-note'] { +#customized-roadmap #resource-svg-wrap:not([data-renderer]) g:not([class]), +#customized-roadmap #resource-svg-wrap:not([data-renderer]) circle, +#customized-roadmap #resource-svg-wrap:not([data-renderer]) path[stroke='#fff'], +#customized-roadmap + #resource-svg-wrap:not([data-renderer]) + g[data-group-id$='-note'] { display: none; } diff --git a/src/components/Friends/FriendProgressItem.tsx b/src/components/Friends/FriendProgressItem.tsx index 41b1c66ac..da60cbf27 100644 --- a/src/components/Friends/FriendProgressItem.tsx +++ b/src/components/Friends/FriendProgressItem.tsx @@ -7,12 +7,14 @@ import { useToast } from '../../hooks/use-toast'; import { TrashIcon } from '../ReactIcons/TrashIcon'; import { AddedUserIcon } from '../ReactIcons/AddedUserIcon'; import { AddUserIcon } from '../ReactIcons/AddUserIcon'; +import type { AllowedRoadmapRenderer } from '../../lib/roadmap'; type FriendProgressItemProps = { friend: ListFriendsResponse[0]; onShowResourceProgress: ( resourceId: string, - isCustomResource?: boolean + isCustomResource?: boolean, + renderer?: AllowedRoadmapRenderer, ) => void; onReload: () => void; }; @@ -27,7 +29,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { pageProgressMessage.set('Please wait...'); const { response, error } = await httpDelete( `${import.meta.env.PUBLIC_API_URL}/v1-delete-friend/${userId}`, - {} + {}, ); if (error || !response) { @@ -43,7 +45,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { pageProgressMessage.set('Please wait...'); const { response, error } = await httpPost( `${import.meta.env.PUBLIC_API_URL}/v1-add-friend/${userId}`, - {} + {}, ); if (error || !response) { @@ -92,7 +94,8 @@ export function FriendProgressItem(props: FriendProgressItemProps) { onClick={() => onShowResourceProgress( progress.resourceId, - progress.isCustomResource + progress.isCustomResource, + progress?.renderer, ) } className="group relative overflow-hidden rounded-md border p-2 hover:border-gray-300 hover:text-black focus:outline-none" @@ -160,7 +163,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { deleteFriend(friend.userId, 'Friend removed').finally( () => { pageProgressMessage.set(''); - } + }, ); }} > @@ -198,7 +201,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { addFriend(friend.userId, 'Friend request accepted').finally( () => { pageProgressMessage.set(''); - } + }, ); }} > @@ -225,7 +228,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { deleteFriend(friend.userId, 'Friend request removed').finally( () => { pageProgressMessage.set(''); - } + }, ); }} > @@ -267,7 +270,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { onClick={() => { deleteFriend( friend.userId, - 'Friend request withdrawn' + 'Friend request withdrawn', ).finally(() => { pageProgressMessage.set(''); }); @@ -304,7 +307,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { addFriend(friend.userId, 'Friend request accepted').finally( () => { pageProgressMessage.set(''); - } + }, ); }} className="mb-1 block w-full max-w-[150px] rounded-md bg-black py-1.5 text-sm text-white" @@ -316,7 +319,7 @@ export function FriendProgressItem(props: FriendProgressItemProps) { onClick={() => { deleteFriend( friend.userId, - 'Friend request rejected' + 'Friend request rejected', ).finally(() => { pageProgressMessage.set(''); }); diff --git a/src/components/Friends/FriendsPage.tsx b/src/components/Friends/FriendsPage.tsx index 0e8adbe2f..00c939feb 100644 --- a/src/components/Friends/FriendsPage.tsx +++ b/src/components/Friends/FriendsPage.tsx @@ -11,6 +11,7 @@ import { UserProgressModal } from '../UserProgress/UserProgressModal'; import { InviteFriendPopup } from './InviteFriendPopup'; import { UserCustomProgressModal } from '../UserProgress/UserCustomProgressModal'; import { UserIcon } from 'lucide-react'; +import type { AllowedRoadmapRenderer } from '../../lib/roadmap'; type FriendResourceProgress = { updatedAt: string; @@ -22,6 +23,7 @@ type FriendResourceProgress = { skipped: number; done: number; total: number; + renderer?: AllowedRoadmapRenderer; }; export type ListFriendsResponse = { @@ -55,6 +57,7 @@ export function FriendsPage() { resourceId: string; friend: ListFriendsResponse[0]; isCustomResource?: boolean; + renderer?: AllowedRoadmapRenderer; }>(); const [isLoading, setIsLoading] = useState(true); @@ -92,8 +95,8 @@ export function FriendsPage() { (grouping) => grouping.value === selectedGrouping, ); - const filteredFriends = friends.filter( - (friend) => selectedGroupingType?.statuses.includes(friend.status), + const filteredFriends = friends.filter((friend) => + selectedGroupingType?.statuses.includes(friend.status), ); const receivedRequests = friends.filter( @@ -124,6 +127,7 @@ export function FriendsPage() { resourceType={'roadmap'} onClose={() => setShowFriendProgress(undefined)} isCustomResource={showFriendProgress?.isCustomResource} + renderer={showFriendProgress?.renderer} /> ); @@ -182,11 +186,16 @@ export function FriendsPage() { {filteredFriends.map((friend) => ( { + onShowResourceProgress={( + resourceId, + isCustomResource, + renderer, + ) => { setShowFriendProgress({ resourceId, friend, isCustomResource, + renderer, }); }} key={friend.userId} diff --git a/src/components/RelatedRoadmaps.astro b/src/components/RelatedRoadmaps.astro index 61b600e66..baee80e74 100644 --- a/src/components/RelatedRoadmaps.astro +++ b/src/components/RelatedRoadmaps.astro @@ -1,6 +1,6 @@ --- import { getQuestionGroupsByIds } from '../lib/question-group'; -import { getRoadmapsByIds, RoadmapFrontmatter } from '../lib/roadmap'; +import { getRoadmapsByIds, type RoadmapFrontmatter } from '../lib/roadmap'; import { Map, Clipboard } from 'lucide-react'; export interface Props { @@ -59,14 +59,19 @@ const relatedQuestionDetails = await getQuestionGroupsByIds(relatedQuestions); { relatedRoadmaps.length && ( -
+
- Related + Related { diff --git a/src/components/Roadmaps/RoadmapsPage.tsx b/src/components/Roadmaps/RoadmapsPage.tsx index 829510c2a..73604a6ee 100644 --- a/src/components/Roadmaps/RoadmapsPage.tsx +++ b/src/components/Roadmaps/RoadmapsPage.tsx @@ -77,6 +77,12 @@ const groups: GroupType[] = [ type: 'role', otherGroups: ['Web Development', 'Absolute Beginners'], }, + { + title: 'API Design', + link: '/api', + type: 'role', + otherGroups: ['Web Development'], + }, { title: 'QA', link: '/qa', diff --git a/src/components/TeamActivity/TeamActivityPage.tsx b/src/components/TeamActivity/TeamActivityPage.tsx index f2200572c..b8d6b9657 100644 --- a/src/components/TeamActivity/TeamActivityPage.tsx +++ b/src/components/TeamActivity/TeamActivityPage.tsx @@ -189,10 +189,10 @@ export function TeamActivityPage() { Team Activity
    - {usersWithActivities.map((user) => { + {usersWithActivities.map((user, index) => { return ( {selectedResource && ( - act.activity) || [] } onResourceClick={(resourceId, resourceType, isCustomResource) => { - setSelectedResource({ resourceId, resourceType, isCustomResource }); + setSelectedResource({ + resourceId, + resourceType, + isCustomResource, + }); }} /> r.id === roadmapId); const { error, response } = await httpPut( `${ import.meta.env.PUBLIC_API_URL @@ -156,6 +157,7 @@ export function TeamRoadmaps() { resourceId: roadmapId, resourceType: 'roadmap', removed: [], + renderer: roadmap?.renderer || 'balsamiq', }, ); @@ -166,6 +168,9 @@ export function TeamRoadmaps() { setTeamResources(response); toast.success('Roadmap added'); + if (roadmap?.renderer === 'editor') { + setIsAddingRoadmap(false); + } } async function onRemove(resourceId: string) { @@ -219,11 +224,14 @@ export function TeamRoadmaps() { /> ); + const filteredAllRoadmaps = allRoadmaps.filter( + (r) => !teamResources.find((c) => c?.defaultRoadmapId === r.id), + ); const addRoadmapModal = isAddingRoadmap && ( setIsAddingRoadmap(false)} teamResourceConfig={teamResources} - allRoadmaps={allRoadmaps} + allRoadmaps={filteredAllRoadmaps} teamId={teamId} onRoadmapAdd={(roadmapId: string) => { onAdd(roadmapId).finally(() => { diff --git a/src/components/TeamVersions/TeamVersions.tsx b/src/components/TeamVersions/TeamVersions.tsx index b76e44d5b..f67ffff59 100644 --- a/src/components/TeamVersions/TeamVersions.tsx +++ b/src/components/TeamVersions/TeamVersions.tsx @@ -106,6 +106,10 @@ export function TeamVersions(props: TeamVersionsProps) { }, []); useEffect(() => { + if (!selectedTeamVersion) { + return; + } + clearResourceProgress(); // teams have customizations. Assigning #customized-roadmap to roadmapSvgWrap diff --git a/src/components/TopicDetail/TopicDetail.tsx b/src/components/TopicDetail/TopicDetail.tsx index 42551851b..3f318fccd 100644 --- a/src/components/TopicDetail/TopicDetail.tsx +++ b/src/components/TopicDetail/TopicDetail.tsx @@ -225,11 +225,12 @@ export function TopicDetail(props: TopicDetailProps) { className="fixed right-0 top-0 z-40 flex h-screen w-full flex-col overflow-y-auto bg-white p-4 focus:outline-0 sm:max-w-[600px] sm:p-6" > {isLoading && ( -
    +
    )} diff --git a/src/components/UserProgress/UserProgressModal.tsx b/src/components/UserProgress/UserProgressModal.tsx index 3c7072ab0..0153ba533 100644 --- a/src/components/UserProgress/UserProgressModal.tsx +++ b/src/components/UserProgress/UserProgressModal.tsx @@ -11,6 +11,9 @@ import { useAuth } from '../../hooks/use-auth'; import { ModalLoader } from './ModalLoader.tsx'; import { UserProgressModalHeader } from './UserProgressModalHeader'; import { X } from 'lucide-react'; +import type { PageType } from '../CommandMenu/CommandMenu.tsx'; +import type { AllowedRoadmapRenderer } from '../../lib/roadmap.ts'; +import { renderFlowJSON } from '../../../editor/renderer/renderer.ts'; export type ProgressMapProps = { userId?: string; @@ -18,6 +21,7 @@ export type ProgressMapProps = { resourceType: ResourceType; onClose?: () => void; isCustomResource?: boolean; + renderer?: AllowedRoadmapRenderer; }; export type UserProgressResponse = { @@ -39,6 +43,7 @@ export function UserProgressModal(props: ProgressMapProps) { resourceType, userId: propUserId, onClose: onModalClose, + renderer = 'balsamiq', } = props; const { s: userId = propUserId } = getUrlParams(); @@ -87,15 +92,18 @@ export function UserProgressModal(props: ProgressMapProps) { async function getRoadmapSVG( jsonUrl: string, + renderer: AllowedRoadmapRenderer = 'balsamiq', ): Promise { const { error, response: roadmapJson } = await httpGet(jsonUrl); if (error || !roadmapJson) { throw error || new Error('Something went wrong. Please try again!'); } - return await wireframeJSONToSVG(roadmapJson, { - fontURL: '/fonts/balsamiq.woff2', - }); + return renderer === 'editor' + ? await renderFlowJSON(roadmapJson as any) + : await wireframeJSONToSVG(roadmapJson, { + fontURL: '/fonts/balsamiq.woff2', + }); } function onClose() { @@ -124,8 +132,10 @@ export function UserProgressModal(props: ProgressMapProps) { } setIsLoading(true); + setError(''); + Promise.all([ - getRoadmapSVG(resourceJsonUrl), + getRoadmapSVG(resourceJsonUrl, renderer), getUserProgress(userId, resourceType, resourceId), ]) .then(([svg, user]) => { diff --git a/src/data/roadmaps/api/api.json b/src/data/roadmaps/api/api.json new file mode 100644 index 000000000..d4b625d7b --- /dev/null +++ b/src/data/roadmaps/api/api.json @@ -0,0 +1 @@ +{"nodes":[{"id":"SP-d4YngpYXkeIB9SSD-K","type":"section","position":{"x":240.93596412339082,"y":1861.570310981244},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"borderColor":"TRANSPARENt","backgroundColor":"TRANSPARENt"},"oldId":"7s60T3OiXeo29-xN6fGjJ"},"zIndex":-999,"width":202,"height":114,"style":{"width":202,"height":114},"positionAbsolute":{"x":240.93596412339082,"y":1861.570310981244},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"XzXLGjJr2F8Ln7gP0e5N8","type":"paragraph","position":{"x":-151.46804969796983,"y":2375.4716162213053},"selected":true,"data":{"label":"Continue Learning with following relevant tracks","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center","borderColor":"#000000"},"oldId":"jXtqI8k4Abz-vr01IcpWL"},"zIndex":999,"width":436,"height":118,"positionAbsolute":{"x":-151.46804969796983,"y":2375.4716162213053},"dragging":false,"style":{"width":436,"height":118},"resizing":true,"selectable":true,"focusable":true},{"id":"zL4QEM5xZO8XWXXWrdPuj","type":"section","position":{"x":244.19846699906657,"y":1501.3654630729577},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"borderColor":"TRANSPARENt","backgroundColor":"TRANSPARENt"}},"zIndex":-999,"width":200,"height":217,"style":{"width":200,"height":217},"positionAbsolute":{"x":244.19846699906657,"y":1501.3654630729577},"dragging":false,"resizing":true,"selectable":true,"focusable":true},{"id":"o3XFXW2HHLBoxlbEnoWdZ","type":"section","position":{"x":-592.469505701316,"y":1567.7437339754388},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"}},"zIndex":-999,"width":247,"height":381,"style":{"width":247,"height":381},"positionAbsolute":{"x":-592.469505701316,"y":1567.7437339754388},"dragging":false,"resizing":false,"focusable":true,"selectable":true},{"id":"ludceg3fQVkilNTKWznti","type":"section","position":{"x":-210.7109644352177,"y":1239.744561558562},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"}},"zIndex":-999,"width":252,"height":114,"style":{"width":252,"height":114},"positionAbsolute":{"x":-210.7109644352177,"y":1239.744561558562},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"RkPVaSF9XnX6uHUns_-oC","type":"section","position":{"x":228.3676576847514,"y":1267.1153073402706},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"borderColor":"TRANSPARENt"}},"zIndex":-999,"width":219,"height":235,"style":{"width":219,"height":235},"positionAbsolute":{"x":228.3676576847514,"y":1267.1153073402706},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"cGWZQjKazJQ0D3nz_AdAX","type":"section","position":{"x":-593.4010478029121,"y":982.3357132591475},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"borderColor":"TRANSPARENt","backgroundColor":"TRANSPARENt"}},"zIndex":-999,"width":230,"height":279,"style":{"width":230,"height":279},"resizing":true,"dragging":false,"positionAbsolute":{"x":-593.4010478029121,"y":982.3357132591475},"selectable":true,"focusable":true},{"id":"iHtjFSkQWMoUNdltNttEd","type":"section","position":{"x":219.72110595703134,"y":644.8914213180542},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"}},"zIndex":-999,"width":268,"height":297,"style":{"width":268,"height":297},"positionAbsolute":{"x":219.72110595703134,"y":644.8914213180542},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"junprE7dbMyeovApqhSgr","type":"section","position":{"x":219.22110595703134,"y":281.3914213180542},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"}},"zIndex":-999,"width":269,"height":228,"style":{"width":269,"height":228},"positionAbsolute":{"x":219.22110595703134,"y":281.3914213180542},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"wTrcPqj0KpoeOvJf7k3iI","type":"section","position":{"x":-206.8881872719935,"y":451.40074822234897},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"}},"zIndex":-999,"width":266,"height":234,"style":{"width":266,"height":234},"positionAbsolute":{"x":-206.8881872719935,"y":451.40074822234897},"dragging":false,"resizing":false,"focusable":true,"selectable":true},{"id":"IzMY2P54llvbVixWxAl7H","type":"section","position":{"x":-571.1381872719934,"y":123.90074822234897},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17},"oldId":"wOyWgfUDwC3ORsLI8H5A0"},"zIndex":-999,"width":232,"height":437,"style":{"width":232,"height":437},"positionAbsolute":{"x":-571.1381872719934,"y":123.90074822234897},"dragging":false,"resizing":false,"selectable":true,"focusable":true},{"id":"AZoEY2N7PqAQgUl04E3KF","type":"title","position":{"x":-178.6381872719934,"y":-57.599251777651034},"selected":true,"data":{"label":"Building APIs","style":{"fontSize":28,"justifyContent":"flex-start","textAlign":"center"},"oldId":"EhPhMi4v4KT3vEUrInsxF"},"zIndex":999,"width":207,"height":68,"dragging":false,"positionAbsolute":{"x":-178.6381872719934,"y":-57.599251777651034},"selectable":true,"focusable":true},{"id":"duKkpzPjUU_-8kyJGHqRX","type":"topic","position":{"x":-198.1381872719934,"y":123.40074822234897},"selected":true,"data":{"label":"Learn the Basics","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"awdoiCHz7Yc3kYac_iy-a"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-198.1381872719934,"y":123.40074822234897},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"r8M3quACGO2piu0u_R4hO","type":"subtopic","position":{"x":-570.1381872719934,"y":63.400748222348966},"selected":true,"data":{"label":"What are APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"Wghrrm4Riz2t7F41H5GK-"},"zIndex":999,"width":232,"height":49,"positionAbsolute":{"x":-570.1381872719934,"y":63.400748222348966},"dragging":false,"style":{"width":232,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"2HdKzAIQi15pr3YHHrbPp","type":"subtopic","position":{"x":-571.1381872719934,"y":122.60000000000008},"selected":true,"data":{"label":"HTTP","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mbDiNvkeYo9v3T_DN5uNl"},"zIndex":999,"width":232,"height":49,"positionAbsolute":{"x":-571.1381872719934,"y":122.60000000000008},"dragging":false,"style":{"width":232,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"ACALE93mL4gnX5ThRIdRp","type":"subtopic","position":{"x":-560.6381872719934,"y":183.90074822234897},"selected":true,"data":{"label":"HTTP Versions","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"p0C6D4Rt2y_U9atm7X_kt"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-560.6381872719934,"y":183.90074822234897},"selectable":true,"focusable":true,"dragging":false,"style":{"width":210,"height":49},"resizing":true},{"id":"rADHM-6NAxEjzmgiHefDX","type":"subtopic","position":{"x":-560.6381872719934,"y":236.40074822234897},"selected":true,"data":{"label":"HTTP Methods","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"ZGD2Y4TgLOzn-mDEhZGXX"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-560.6381872719934,"y":236.40074822234897},"selectable":true,"focusable":true,"dragging":false,"style":{"width":210,"height":49}},{"id":"7szYyzLifKsepNU0c2KnN","type":"subtopic","position":{"x":-560.6381872719934,"y":288.90074822234897},"selected":true,"data":{"label":"HTTP Status Codes","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"--pZRMVsKFEAhMIgDpGwC"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-560.6381872719934,"y":288.90074822234897},"selectable":true,"focusable":true,"dragging":false,"style":{"width":210,"height":49}},{"id":"rE-0yibRH6B2UBKp351cf","type":"subtopic","position":{"x":-560.6381872719934,"y":341.40074822234897},"selected":true,"data":{"label":"HTTP Headers","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"3iwD_eyT4XZRQNIorTF3a"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-560.6381872719934,"y":341.40074822234897},"selectable":true,"focusable":true,"dragging":false,"style":{"width":210,"height":49}},{"id":"P-rGIk50Bg7nFmWieAW07","type":"subtopic","position":{"x":197.8618127280065,"y":52.100748222348955},"selected":true,"data":{"label":"URL, Query & Path Parameters","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"aBXHVaEfcChnyF4FPlqHp"},"zIndex":999,"width":283,"height":49,"positionAbsolute":{"x":197.8618127280065,"y":52.100748222348955},"dragging":false,"style":{"width":283,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"UFuX8wcxZQ7dvaQF_2Yp8","type":"subtopic","position":{"x":-560.6381872719934,"y":393.90074822234897},"selected":true,"data":{"label":"Cookies","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"2tNyxd-8rFQoOsQIClP4O"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-560.6381872719934,"y":393.90074822234897},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"TX_hg7EobNJhmWKsMCaT1","type":"subtopic","position":{"x":197.8618127280065,"y":106.10074822234895},"selected":true,"data":{"label":"Content Negotiation","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":283,"height":49,"positionAbsolute":{"x":197.8618127280065,"y":106.10074822234895},"dragging":false,"style":{"width":283,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"GRlsBogOlOwuqhMMPyHN3","type":"subtopic","position":{"x":-559.6381872719934,"y":446.40074822234897},"selected":true,"data":{"label":"CORS","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-559.6381872719934,"y":446.40074822234897},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"KG3wO86F8Of27fU7QRcsn","type":"subtopic","position":{"x":197.8618127280065,"y":160.10074822234895},"selected":true,"data":{"label":"Understand TCP / IP","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":283,"height":49,"positionAbsolute":{"x":197.8618127280065,"y":160.10074822234895},"dragging":false,"style":{"width":283,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"v4nJYD9yiIEUviLPhVTCD","type":"subtopic","position":{"x":197.8618127280065,"y":214.10074822234895},"selected":true,"data":{"label":"Basics of DNS","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":283,"height":49,"positionAbsolute":{"x":197.8618127280065,"y":214.10074822234895},"dragging":false,"style":{"width":283,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"o8i093VQv-T5Qf1yGqU0R","type":"topic","position":{"x":-198.1381872719934,"y":330.40074822234897},"selected":true,"data":{"label":"Different API Styles","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5R9yKfN1vItuv__HgCwP7"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-198.1381872719934,"y":330.40074822234897},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"BvwdASMvuNQ9DNgzdSZ4o","type":"subtopic","position":{"x":-196.3881872719935,"y":453.90074822234897},"selected":true,"data":{"label":"RESTful APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":245,"height":49,"positionAbsolute":{"x":-196.3881872719935,"y":453.90074822234897},"dragging":false,"style":{"width":245,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"TVR-SkErlOHbDKLBGfxep","type":"subtopic","position":{"x":-196.3881872719935,"y":507.90074822234897},"selected":true,"data":{"label":"Simple JSON APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":245,"height":49,"positionAbsolute":{"x":-196.3881872719935,"y":507.90074822234897},"dragging":false,"style":{"width":245,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"Wwd-0PjrtViMFWxRGaQey","type":"subtopic","position":{"x":-196.3881872719935,"y":561.900748222349},"selected":true,"data":{"label":"SOAP APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":245,"height":49,"positionAbsolute":{"x":-196.3881872719935,"y":561.900748222349},"dragging":false,"style":{"width":245,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"MKVcPM2EzAr2_Ieyp9Fu3","type":"subtopic","position":{"x":-196.3881872719935,"y":615.900748222349},"selected":true,"data":{"label":"GraphQL APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"WVSgaWgGJKqJYumpdPTCG"},"zIndex":999,"width":245,"height":49,"positionAbsolute":{"x":-196.3881872719935,"y":615.900748222349},"dragging":false,"style":{"width":245,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"iA0C1mFlM_73GcL9XNJmF","type":"button","position":{"x":-576.1381872719934,"y":615.900748222349},"selected":true,"data":{"label":"Visit GraphQL Roadmap","href":"https://roadmap.sh/graphql","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17},"oldId":"MSeNU5cURBInhPlvnhVfO"},"zIndex":999,"width":244,"height":49,"positionAbsolute":{"x":-576.1381872719934,"y":615.900748222349},"dragging":false,"style":{"width":244,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"awdoiCHz7Yc3kYac_iy-a","type":"topic","position":{"x":212.7618127280066,"y":548.400748222349},"selected":true,"data":{"label":"Building JSON / RESTful APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"qHEzyDhqjQSa6vs5UDm_M"},"zIndex":999,"width":282,"height":49,"positionAbsolute":{"x":212.7618127280066,"y":548.400748222349},"dragging":false,"selectable":true,"focusable":true,"style":{"width":282,"height":49},"resizing":false},{"id":"9WI_z34jIFXwoUQuChyRU","type":"subtopic","position":{"x":223.2618127280066,"y":290.40074822234897},"selected":true,"data":{"label":"REST Principles","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":290.40074822234897},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"b3qRTLwCC_9uDoPGrd9Bu","type":"subtopic","position":{"x":223.2618127280066,"y":344.40074822234897},"selected":true,"data":{"label":"URI Design","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":344.40074822234897},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"itILK2SXvLvAjk1Kul7EK","type":"subtopic","position":{"x":223.2618127280066,"y":398.40074822234897},"selected":true,"data":{"label":"Versioning Strategies","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"zXxEiM5HeOn7W-Vue0tQf"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":398.40074822234897},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"pgJDzP3pJjhjr5wTRtPJO","type":"subtopic","position":{"x":223.2618127280066,"y":649.400748222349},"selected":true,"data":{"label":"Pagination","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":649.400748222349},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"O7wjldZ3yTA2s_F-UnJw_","type":"subtopic","position":{"x":223.2618127280066,"y":703.400748222349},"selected":true,"data":{"label":"Reate Limiting","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":703.400748222349},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"20KEgZH6cu_UokqWpV-9I","type":"subtopic","position":{"x":223.2618127280066,"y":757.400748222349},"selected":true,"data":{"label":"Idempotency","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":757.400748222349},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"LByD1vhzunhY1uY1YGZHP","type":"subtopic","position":{"x":223.2618127280066,"y":811.400748222349},"selected":true,"data":{"label":"HATEOAS","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":811.400748222349},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"zXxEiM5HeOn7W-Vue0tQf","type":"subtopic","position":{"x":223.2618127280066,"y":452.40074822234897},"selected":true,"data":{"label":"Handling CRUD Operations","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":452.40074822234897},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"8tELdagrOaGCf3nMVs8t3","type":"subtopic","position":{"x":223.2618127280066,"y":865.400748222349},"selected":true,"data":{"label":"Error Handling","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5CxU3inGcSHp-TDg3BQiY"},"zIndex":999,"width":261,"height":49,"positionAbsolute":{"x":223.2618127280066,"y":865.400748222349},"dragging":false,"style":{"width":261,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"5CxU3inGcSHp-TDg3BQiY","type":"subtopic","position":{"x":-165.6381872719934,"y":865.400748222349},"selected":true,"data":{"label":"RFC 7807 - Problem Details for APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"MKVcPM2EzAr2_Ieyp9Fu3"},"zIndex":999,"width":326,"height":49,"positionAbsolute":{"x":-165.6381872719934,"y":865.400748222349},"dragging":false,"style":{"width":326,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"eUsorPQ8VRLJs28J8dyk2","type":"paragraph","position":{"x":-318.1381872719934,"y":728.9974788763272},"selected":true,"data":{"label":"API Authentication and Authorization","style":{"fontSize":20,"justifyContent":"flex-start","textAlign":"left"}},"zIndex":999,"width":366,"height":69,"dragging":false,"positionAbsolute":{"x":-318.1381872719934,"y":728.9974788763272},"selectable":true,"focusable":true,"style":{"width":366,"height":69},"resizing":false},{"id":"qAolZHf_jp8hCdtqHZwC8","type":"subtopic","position":{"x":-559.1381872719934,"y":498.90074822234897},"selected":true,"data":{"label":"HTTP Caching","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-559.1381872719934,"y":498.90074822234897},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"cQnQ9v3mH27MGNwetz3JW","type":"topic","position":{"x":-601.4010478029121,"y":859.6211541412258},"selected":true,"data":{"label":"Authentication Methods","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5R9yKfN1vItuv__HgCwP7"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-601.4010478029121,"y":859.6211541412258},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"0FzHERK5AeYL5wv1FBJbH","type":"subtopic","position":{"x":-583.4010478029121,"y":983.7533379465866},"selected":true,"data":{"label":"Basic Auth","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"dZTe_kxIUQsc9N3w920aR"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-583.4010478029121,"y":983.7533379465866},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"QTH7sy9uQZWl6ieBz7erY","type":"subtopic","position":{"x":-583.4010478029121,"y":1037.7533379465865},"selected":true,"data":{"label":"Token Based Auth","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-583.4010478029121,"y":1037.7533379465865},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"tWg68AHLIr1gIZA1za3jp","type":"subtopic","position":{"x":-583.4010478029121,"y":1091.7533379465865},"selected":true,"data":{"label":"JWT ","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-583.4010478029121,"y":1091.7533379465865},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"TLuNtQ6HKYQXmglyVk8-t","type":"subtopic","position":{"x":-583.4010478029121,"y":1145.7533379465865},"selected":true,"data":{"label":"OAuth 2.0","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-583.4010478029121,"y":1145.7533379465865},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"eQWoy4CpYP3TJL2bbhPB_","type":"subtopic","position":{"x":-583.4010478029121,"y":1199.8443340956667},"selected":true,"data":{"label":"Session Based Auth","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":-583.4010478029121,"y":1199.8443340956667},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"nHbn8_sMY7J8o6ckbD-ER","type":"topic","position":{"x":-210.6381872719934,"y":1033.5329320277096},"selected":true,"data":{"label":"Authorization Methods","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5R9yKfN1vItuv__HgCwP7"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-210.6381872719934,"y":1033.5329320277096},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"wFsbmMi5Ey9UyDADdbdPW","type":"subtopic","position":{"x":165.00932230336673,"y":1004.0041963907498},"selected":true,"data":{"label":"Role Based Access Control (RBAC)","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"dZTe_kxIUQsc9N3w920aR"},"zIndex":999,"width":352,"height":49,"positionAbsolute":{"x":165.00932230336673,"y":1004.0041963907498},"dragging":false,"style":{"width":352,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"dZTe_kxIUQsc9N3w920aR","type":"subtopic","position":{"x":165.00932230336673,"y":1058.00419639075},"selected":true,"data":{"label":"Attribute Based Access Control (ABAC)","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":351,"height":49,"positionAbsolute":{"x":165.00932230336673,"y":1058.00419639075},"dragging":false,"style":{"width":351,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"tzUJwXu_scwQHnPPT0oY-","type":"topic","position":{"x":-210.6381872719934,"y":1146.5329320277096},"selected":true,"data":{"label":"API Keys & Management","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"Wpk4TvxcZOJgAoXjrOsZF"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-210.6381872719934,"y":1146.5329320277096},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"5R9yKfN1vItuv__HgCwP7","type":"topic","position":{"x":214.72110595703134,"y":1146.5329320277096},"selected":true,"data":{"label":"API Documentation Tools","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"awdoiCHz7Yc3kYac_iy-a"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":214.72110595703134,"y":1146.5329320277096},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"5RY7AlfRQydjxWK65Z4cv","type":"subtopic","position":{"x":232.85884761415554,"y":1270.9481617844106},"selected":true,"data":{"label":"Swagger / Open API","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"OpS2NX1lPTOtfjV1wKtC4"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":232.85884761415554,"y":1270.9481617844106},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"KQAus72RGqx5f-3-YeJby","type":"subtopic","position":{"x":232.85884761415554,"y":1427.5717249610107},"selected":true,"data":{"label":"Postman","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"CDLaORTdB5PWk7VbcU1bz"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":232.85884761415554,"y":1427.5717249610107},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"LxWHkhlikUaMT2G8YmVDQ","type":"subtopic","position":{"x":232.85884761415554,"y":1323.1560161766106},"selected":true,"data":{"label":"Readme.com","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"OpS2NX1lPTOtfjV1wKtC4"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":232.85884761415554,"y":1323.1560161766106},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"OpS2NX1lPTOtfjV1wKtC4","type":"subtopic","position":{"x":232.85884761415554,"y":1375.3638705688106},"selected":true,"data":{"label":"Stoplight","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":210,"height":49,"positionAbsolute":{"x":232.85884761415554,"y":1375.3638705688106},"dragging":false,"style":{"width":210,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"qIJ6dUppjAjOTA8eQbp0n","type":"topic","position":{"x":-207.7109644352177,"y":1398.532340911712},"selected":true,"data":{"label":"API Security","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"Wpk4TvxcZOJgAoXjrOsZF"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-207.7109644352177,"y":1398.532340911712},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"G70wvcOM1Isrx5ZBvS2xP","type":"subtopic","position":{"x":-205.2109644352177,"y":1251.6104620579213},"selected":true,"data":{"label":"Common Vulnerabilities","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"q1yaf-RbHIQsOqfzjn4k4"},"zIndex":999,"width":241,"height":49,"positionAbsolute":{"x":-205.2109644352177,"y":1251.6104620579213},"dragging":false,"style":{"width":241,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"q1yaf-RbHIQsOqfzjn4k4","type":"subtopic","position":{"x":-205.2109644352177,"y":1303.8183164501213},"selected":true,"data":{"label":"Best Practices","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"KQAus72RGqx5f-3-YeJby"},"zIndex":999,"width":241,"height":49,"positionAbsolute":{"x":-205.2109644352177,"y":1303.8183164501213},"dragging":false,"style":{"width":241,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"92-ebM0EwQ3nLjZKtvCZX","type":"button","position":{"x":-612.1381872719934,"y":1303.8183164501213},"selected":true,"data":{"label":"API Security Best Practices","href":"","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17},"oldId":"MSeNU5cURBInhPlvnhVfO"},"zIndex":999,"width":290,"height":49,"positionAbsolute":{"x":-612.1381872719934,"y":1303.8183164501213},"dragging":false,"style":{"width":290,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"d9ZXdU73jiCdeNHQv1_DH","type":"topic","position":{"x":-590.469505701316,"y":1467.491632075372},"selected":true,"data":{"label":"API Performance","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"Wpk4TvxcZOJgAoXjrOsZF"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-590.469505701316,"y":1467.491632075372},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"nQpczZUcn-TvrfT80dv0Q","type":"subtopic","position":{"x":-585.469505701316,"y":1568.4353183589587},"selected":true,"data":{"label":"Performance Metrics","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1568.4353183589587},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"PrvRCR4HCdGar0vcUbG_a","type":"subtopic","position":{"x":-585.469505701316,"y":1619.7437339754388},"selected":true,"data":{"label":"Caching Strategies","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1619.7437339754388},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"p5wsniYnOS7cbHd92RxGk","type":"subtopic","position":{"x":-585.469505701316,"y":1671.0521495919188},"selected":true,"data":{"label":"Load Balancing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1671.0521495919188},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"tPVtRV818D8zAAuNbqPNa","type":"subtopic","position":{"x":-585.469505701316,"y":1722.3605652083988},"selected":true,"data":{"label":"Rate Limiting / Throttling","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1722.3605652083988},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"-qdwBg7HvwlbLy3IKCRij","type":"subtopic","position":{"x":-585.469505701316,"y":1773.6689808248789},"selected":true,"data":{"label":"Profiling and Monitoring","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1773.6689808248789},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"DQcAV59vr1-ZRnMfbLXpu","type":"subtopic","position":{"x":-585.469505701316,"y":1824.977396441359},"selected":true,"data":{"label":"Performance Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"XD1vDtrRQFbLyKJaD1AlA"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1824.977396441359},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"MSeNU5cURBInhPlvnhVfO","type":"button","position":{"x":-614.469505701316,"y":1367.532340911712},"selected":true,"data":{"label":"API Performance Best Practices","href":"","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17}},"zIndex":999,"width":294,"height":49,"positionAbsolute":{"x":-614.469505701316,"y":1367.532340911712},"dragging":false,"style":{"width":294,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"R3aRhqCslwhegMfHtxg5z","type":"topic","position":{"x":-210.2109644352177,"y":1544.4353183589587},"selected":true,"data":{"label":"API Integration Patterns","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"yvdfoly5WHHTq2Puss355"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":-210.2109644352177,"y":1544.4353183589587},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"kJD1K2-ZkoezFCfpmOM0Z","type":"section","position":{"x":-255.7109644352177,"y":1661.7437339754388},"selected":true,"data":{"label":"","style":{"width":150,"height":100,"fontSize":17,"backgroundColor":"TRANSPARENt","borderColor":"TRANSPARENt"},"oldId":"o3XFXW2HHLBoxlbEnoWdZ"},"zIndex":-999,"width":335,"height":370,"style":{"width":335,"height":370},"positionAbsolute":{"x":-255.7109644352177,"y":1661.7437339754388},"dragging":false,"resizing":false,"focusable":true,"selectable":true},{"id":"--mmTKhG58_elbUqyn90G","type":"subtopic","position":{"x":-250.7109644352177,"y":1662.4353183589587},"selected":true,"data":{"label":"Synchronous vs Asynchronous APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1662.4353183589587},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"oMfOBkVsgiLvFLicOUdx6","type":"subtopic","position":{"x":-250.7109644352177,"y":1713.7417878080591},"selected":true,"data":{"label":"Event Driven Architecture","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"PrvRCR4HCdGar0vcUbG_a"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1713.7417878080591},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"MJeUD4fOHaJu1oxk4uQ-x","type":"subtopic","position":{"x":-250.7109644352177,"y":1765.752205777561},"selected":true,"data":{"label":"API Gateways","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"p5wsniYnOS7cbHd92RxGk"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1765.752205777561},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"PPeBbooE121zrgNwpVTiA","type":"subtopic","position":{"x":-250.7109644352177,"y":1817.410649486862},"selected":true,"data":{"label":"Microservices Architecture","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"-qdwBg7HvwlbLy3IKCRij"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1817.410649486862},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"IkPZel5zxXWIx90Qx7fZI","type":"subtopic","position":{"x":-250.7109644352177,"y":1972.3859806147652},"selected":true,"data":{"label":"Messaging Queues","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mXCKtLUvwVJkHrpHzOecq"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1972.3859806147652},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"75NVxS0iwoQXxOHCkWQxH","type":"subtopic","position":{"x":-250.7109644352177,"y":1869.069093196163},"selected":true,"data":{"label":"Webhooks vs Polling","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"X68HXAAV-nKo-V4Fu1o72"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1869.069093196163},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"X68HXAAV-nKo-V4Fu1o72","type":"subtopic","position":{"x":-250.7109644352177,"y":1920.7275369054641},"selected":true,"data":{"label":"Batch Processing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":325,"height":49,"positionAbsolute":{"x":-250.7109644352177,"y":1920.7275369054641},"dragging":false,"style":{"width":325,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"H22jAI2W5QLL-b1rq-c56","type":"subtopic","position":{"x":-497.66906836651873,"y":1941.8678842718575},"selected":true,"data":{"label":"Rabbit MQ","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":145,"height":49,"positionAbsolute":{"x":-497.66906836651873,"y":1941.8678842718575},"dragging":false,"style":{"width":145,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"boYX1QcJullypfX4sevdy","type":"subtopic","position":{"x":-499.16906836651884,"y":1996.867884271857},"selected":true,"data":{"label":"Kafka","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"q1yaf-RbHIQsOqfzjn4k4"},"zIndex":999,"width":148,"height":49,"positionAbsolute":{"x":-499.16906836651884,"y":1996.867884271857},"dragging":false,"style":{"width":148,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"Wpk4TvxcZOJgAoXjrOsZF","type":"topic","position":{"x":221.19846699906657,"y":1758.058993623857},"selected":true,"data":{"label":"API Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"5R9yKfN1vItuv__HgCwP7"},"zIndex":999,"width":246,"height":49,"positionAbsolute":{"x":221.19846699906657,"y":1758.058993623857},"dragging":false,"selectable":true,"focusable":true,"style":{"width":246,"height":49},"resizing":false},{"id":"JvmW78cDm84GNhq8VEYZp","type":"subtopic","position":{"x":247.69846699906657,"y":1505.4070461854096},"selected":true,"data":{"label":"Unit Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":247.69846699906657,"y":1505.4070461854096},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"qZELS5vw2feS7QfyD7spX","type":"subtopic","position":{"x":247.69846699906657,"y":1559.4070461854096},"selected":true,"data":{"label":"Integration Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":247.69846699906657,"y":1559.4070461854096},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"6lm3wy9WTAERTqXCn6pFt","type":"subtopic","position":{"x":247.69846699906657,"y":1613.4070461854096},"selected":true,"data":{"label":"Functional Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":247.69846699906657,"y":1613.4070461854096},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"7JNEx_cbqnAx3esvwZMOd","type":"subtopic","position":{"x":247.69846699906657,"y":1667.4070461854096},"selected":true,"data":{"label":"Load Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":247.69846699906657,"y":1667.4070461854096},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"bEVCT5QGY3uw0kIfAELKh","type":"subtopic","position":{"x":248.4735203536439,"y":1861.446054725657},"selected":true,"data":{"label":"Mocking APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":248.4735203536439,"y":1861.446054725657},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"NqeBglhzukVMMEF9p2CXc","type":"subtopic","position":{"x":248.4735203536439,"y":1915.446054725657},"selected":true,"data":{"label":"Contract Testing","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":248.4735203536439,"y":1915.446054725657},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"XD1vDtrRQFbLyKJaD1AlA","type":"subtopic","position":{"x":-585.469505701316,"y":1876.285812057839},"selected":true,"data":{"label":"Error Handling / Retries","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"boYX1QcJullypfX4sevdy"},"zIndex":999,"width":236,"height":49,"positionAbsolute":{"x":-585.469505701316,"y":1876.285812057839},"dragging":false,"style":{"width":236,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"JE12g5cqnwmgeTle14Vxw","type":"topic","position":{"x":35.36181272800661,"y":2095.4915595367556},"selected":true,"data":{"label":"Real-time APIs","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"At5exN7ZAx2IzY3cTCzHm"},"zIndex":999,"width":170,"height":49,"positionAbsolute":{"x":35.36181272800661,"y":2095.4915595367556},"dragging":false,"selectable":true,"focusable":true,"style":{"width":170,"height":49},"resizing":false},{"id":"UQ8N7gcVpRLAYXgUNHBt5","type":"subtopic","position":{"x":267.72110595703134,"y":2069.2728071916526},"selected":true,"data":{"label":"Web Sockets","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"iNsXTtcIHsI_i-mCfjGYn"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":267.72110595703134,"y":2069.2728071916526},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"iNsXTtcIHsI_i-mCfjGYn","type":"subtopic","position":{"x":267.72110595703134,"y":2123.2728071916526},"selected":true,"data":{"label":"Server Sent Events","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"nQpczZUcn-TvrfT80dv0Q"},"zIndex":999,"width":193,"height":49,"positionAbsolute":{"x":267.72110595703134,"y":2123.2728071916526},"dragging":false,"style":{"width":193,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"yvdfoly5WHHTq2Puss355","type":"topic","position":{"x":-363.31358688509135,"y":2210.5425435400516},"selected":true,"data":{"label":"Standards and Compliance","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"Wpk4TvxcZOJgAoXjrOsZF"},"zIndex":999,"width":271,"height":49,"positionAbsolute":{"x":-363.31358688509135,"y":2210.5425435400516},"dragging":false,"selectable":true,"focusable":true,"style":{"width":271,"height":49},"resizing":false},{"id":"vZxdswGLHCPi5GSuXEcHJ","type":"subtopic","position":{"x":-570.6112846237921,"y":2102.642324872653},"selected":true,"data":{"label":"GDPR","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mXCKtLUvwVJkHrpHzOecq"},"zIndex":999,"width":123,"height":49,"positionAbsolute":{"x":-570.6112846237921,"y":2102.642324872653},"dragging":false,"style":{"width":123,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"At5exN7ZAx2IzY3cTCzHm","type":"topic","position":{"x":-361.55504561899306,"y":2095.4915595367556},"selected":true,"data":{"label":"API Lifecycle Management","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"yvdfoly5WHHTq2Puss355"},"zIndex":999,"width":267,"height":49,"positionAbsolute":{"x":-361.55504561899306,"y":2095.4915595367556},"dragging":false,"selectable":true,"focusable":true,"style":{"width":267,"height":49},"resizing":false},{"id":"a-_iIE7UdoXzD00fD9MxN","type":"subtopic","position":{"x":-570.6112846237921,"y":2156.642324872653},"selected":true,"data":{"label":"CCPA","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mXCKtLUvwVJkHrpHzOecq"},"zIndex":999,"width":123,"height":49,"positionAbsolute":{"x":-570.6112846237921,"y":2156.642324872653},"dragging":false,"style":{"width":123,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"J0enF8UTVzY3H4n3pbPIF","type":"subtopic","position":{"x":-570.6112846237921,"y":2210.642324872653},"selected":true,"data":{"label":"PCI DSS","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mXCKtLUvwVJkHrpHzOecq"},"zIndex":999,"width":123,"height":49,"positionAbsolute":{"x":-570.6112846237921,"y":2210.642324872653},"dragging":false,"style":{"width":123,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"W4WwTmgZGnWmiYsB0ezml","type":"subtopic","position":{"x":-568.8897926825906,"y":2264.642324872653},"selected":true,"data":{"label":"HIPAA","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"mXCKtLUvwVJkHrpHzOecq"},"zIndex":999,"width":123,"height":49,"positionAbsolute":{"x":-568.8897926825906,"y":2264.642324872653},"dragging":false,"style":{"width":123,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"mXCKtLUvwVJkHrpHzOecq","type":"subtopic","position":{"x":-570.6112846237921,"y":2318.642324872653},"selected":true,"data":{"label":"PII","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"center"},"oldId":"X68HXAAV-nKo-V4Fu1o72"},"zIndex":999,"width":123,"height":49,"positionAbsolute":{"x":-570.6112846237921,"y":2318.642324872653},"dragging":false,"style":{"width":123,"height":49},"resizing":false,"selectable":true,"focusable":true},{"id":"ETSZIZbfsiSgwpAS6HgGp","type":"vertical","position":{"x":-85.13818727199339,"y":-164.08481519539623},"selected":true,"data":{"label":"vertical node","style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2B78E4"}},"zIndex":999,"width":20,"height":94,"positionAbsolute":{"x":-85.13818727199339,"y":-164.08481519539623},"dragging":false,"style":{"width":20,"height":94},"resizing":false,"selectable":true,"focusable":true},{"id":"PstbOGqR_4C2WWV8CWXes","type":"linksgroup","position":{"x":-599.3135868850914,"y":-176.03181769055132},"selected":true,"data":{"label":"Related Roadmaps","links":[{"id":"3uv48fdglShh8YYF3zRWv","label":"Backend Roadmap","href":"","url":"https://roadmap.sh/backend"},{"id":"ZW1PEheVeJJiIPR08jfCr","label":"DevOps Roadmap","url":"https://roadmap.sh/devops"},{"id":"td_Z-sAuf092awd8U-VNG","label":"Full Stack Roadmap","url":"https://roadmap.sh/full-stack"}]},"zIndex":999,"width":303,"height":163,"positionAbsolute":{"x":-599.3135868850914,"y":-176.03181769055132},"dragging":false,"selectable":true,"focusable":true,"style":{"width":303,"height":163},"resizing":false},{"id":"yHmHXymPNWwu8p1vvqD3o","type":"paragraph","position":{"x":158.23571626420664,"y":-175.8282364125966},"selected":true,"data":{"label":"Find the detailed version of this roadmap along with other similar roadmaps","style":{"fontSize":17,"justifyContent":"flex-start","textAlign":"left","borderColor":"#000000"}},"zIndex":999,"width":354,"height":143,"positionAbsolute":{"x":158.23571626420664,"y":-175.8282364125966},"dragging":false,"selectable":true,"focusable":true,"style":{"width":354,"height":143},"resizing":false},{"id":"2zqZkyVgigifcRS1H7F_b","type":"button","position":{"x":171.43909067700685,"y":-93.84267299485134},"selected":true,"data":{"label":"roadmap.sh","href":"https://roadmap.sh","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17}},"zIndex":999,"width":329,"height":49,"dragging":false,"style":{"width":329,"height":49},"resizing":false,"positionAbsolute":{"x":171.43909067700685,"y":-93.84267299485134},"selectable":true,"focusable":true},{"id":"4fauwiq2CJnzDA7Z9Pmeo","type":"button","position":{"x":-139.18102870413122,"y":2429.279985574316},"selected":true,"data":{"label":"Backend Roadmap","href":"https://roadmap.sh/backend","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17},"oldId":"eYziHRN-gsg9qr8Yddu2K"},"zIndex":999,"width":196,"height":49,"positionAbsolute":{"x":-139.18102870413122,"y":2429.279985574316},"dragging":false,"selectable":true,"focusable":true,"style":{"width":196,"height":49},"resizing":false},{"id":"eYziHRN-gsg9qr8Yddu2K","type":"button","position":{"x":68.81897129586875,"y":2429.279985574316},"selected":true,"data":{"label":"DevOps Roadmap","href":"https://roadmap.sh/devops","color":"#ffffff","backgroundColor":"#2a79e4","style":{"fontSize":17}},"zIndex":999,"width":196,"height":49,"positionAbsolute":{"x":68.81897129586875,"y":2429.279985574316},"dragging":false,"selectable":true,"focusable":true,"style":{"width":196,"height":49},"resizing":false},{"id":"cV_O7RiFmpoI4f1o8lF4B","type":"vertical","position":{"x":56.53195030203017,"y":2493.4716162213053},"selected":true,"data":{"label":"vertical node","style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2B78E4"}},"zIndex":999,"width":20,"height":94,"positionAbsolute":{"x":56.53195030203017,"y":2493.4716162213053},"dragging":false,"style":{"width":20,"height":94},"resizing":false,"focusable":true,"selectable":true}],"edges":[{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"JOhjYmVo9geZEMeeRPidh","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"89g6rzK2JcZhJ1MAQra8R","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y2","data":{"edgeStyle":"dashed"},"id":"xMpMq9rxn_DYslWm3_Efz","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"-EP79fa9WRfTgvuq5FRaw","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"1Qdcf_-7xas-XQldfLRjv","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","targetHandle":"y1","data":{"edgeStyle":"solid"},"id":"CfFazuChYdU7GaJO_TolE","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"74bGlBMuedspLPHnGV2LW","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"z2","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"XU7kv1zNr-yC063oqWlz2","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","targetHandle":"w2","data":{"edgeStyle":"dashed"},"id":"swvSmJ6SyUFxK9fHwPJTF","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"w2","targetHandle":"x1","data":{"edgeStyle":"dashed"},"id":"-URcDxULzdZbiMbEx8bBe","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"y2","targetHandle":"w1","data":{"edgeStyle":"solid"},"selected":true,"id":"_k4274GmDVM-MViCSYN6K","focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"y2","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"Tf3d_J21EhC-bcfpqV_o5","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"y2","targetHandle":"z2","data":{"edgeStyle":"dashed"},"id":"gRouAKXdfT8XQV_nzA-wA","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"BgmVdQyd7i1SrZj0forT9","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"AZoEY2N7PqAQgUl04E3KF","sourceHandle":"x2","target":"duKkpzPjUU_-8kyJGHqRX","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"1a_QvZPscaIyRxhKH7p-K","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"y2","target":"r8M3quACGO2piu0u_R4hO","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"cWesUDXpvCzBEu5BpXefC","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"y2","target":"2HdKzAIQi15pr3YHHrbPp","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"CVsFgRPHi9vaQWTqSrbFF","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"z2","target":"P-rGIk50Bg7nFmWieAW07","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"AWgpOpfFNBRrSi_K8RPQg","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"z2","target":"TX_hg7EobNJhmWKsMCaT1","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"uJadhS5nJBYewb-YSy7zE","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"GRlsBogOlOwuqhMMPyHN3","sourceHandle":"z2","target":"GRlsBogOlOwuqhMMPyHN3","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-KQAus72RGqx5f-3-YeJbyz2-KQAus72RGqx5f-3-YeJbyz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"z2","target":"KG3wO86F8Of27fU7QRcsn","targetHandle":"y2","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-az2-KG3wO86F8Of27fU7QRcsny2","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"z2","target":"v4nJYD9yiIEUviLPhVTCD","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-az2-MKVcPM2EzAr2_Ieyp9Fu3y1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"duKkpzPjUU_-8kyJGHqRX","sourceHandle":"x2","target":"o8i093VQv-T5Qf1yGqU0R","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-duKkpzPjUU_-8kyJGHqRXx2-awdoiCHz7Yc3kYac_iy-aw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"o8i093VQv-T5Qf1yGqU0R","sourceHandle":"x2","target":"wTrcPqj0KpoeOvJf7k3iI","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-ax2-wTrcPqj0KpoeOvJf7k3iIw1","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"o8i093VQv-T5Qf1yGqU0R","sourceHandle":"z2","target":"awdoiCHz7Yc3kYac_iy-a","targetHandle":"y1","data":{"edgeStyle":"solid"},"selected":true,"selectable":true,"focusable":true,"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7z2-awdoiCHz7Yc3kYac_iy-ay1"},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"awdoiCHz7Yc3kYac_iy-a","sourceHandle":"w2","target":"junprE7dbMyeovApqhSgr","targetHandle":"x1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-aw2-junprE7dbMyeovApqhSgrx1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"awdoiCHz7Yc3kYac_iy-a","sourceHandle":"x2","target":"iHtjFSkQWMoUNdltNttEd","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-ax2-iHtjFSkQWMoUNdltNttEdw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"8tELdagrOaGCf3nMVs8t3","sourceHandle":"y2","target":"5CxU3inGcSHp-TDg3BQiY","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-8tELdagrOaGCf3nMVs8t3y2-5CxU3inGcSHp-TDg3BQiYz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"awdoiCHz7Yc3kYac_iy-a","sourceHandle":"y2","target":"eUsorPQ8VRLJs28J8dyk2","targetHandle":"z1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-awdoiCHz7Yc3kYac_iy-ay2-eUsorPQ8VRLJs28J8dyk2z1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"eUsorPQ8VRLJs28J8dyk2","sourceHandle":"y2","target":"cQnQ9v3mH27MGNwetz3JW","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-eUsorPQ8VRLJs28J8dyk2y2-5R9yKfN1vItuv__HgCwP7w1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"cQnQ9v3mH27MGNwetz3JW","sourceHandle":"x2","target":"cGWZQjKazJQ0D3nz_AdAX","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7x2-cGWZQjKazJQ0D3nz_AdAXw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"cQnQ9v3mH27MGNwetz3JW","sourceHandle":"z2","target":"nHbn8_sMY7J8o6ckbD-ER","targetHandle":"y1","data":{"edgeStyle":"solid"},"selected":true,"id":"reactflow__edge-cQnQ9v3mH27MGNwetz3JWz2-5R9yKfN1vItuv__HgCwP7y1","selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"nHbn8_sMY7J8o6ckbD-ER","sourceHandle":"z2","target":"wFsbmMi5Ey9UyDADdbdPW","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7z2-wFsbmMi5Ey9UyDADdbdPWy1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"nHbn8_sMY7J8o6ckbD-ER","sourceHandle":"z2","target":"dZTe_kxIUQsc9N3w920aR","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7z2-dZTe_kxIUQsc9N3w920aRy1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"nHbn8_sMY7J8o6ckbD-ER","sourceHandle":"x2","target":"tzUJwXu_scwQHnPPT0oY-","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-nHbn8_sMY7J8o6ckbD-ERx2-5R9yKfN1vItuv__HgCwP7w1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"tzUJwXu_scwQHnPPT0oY-","sourceHandle":"z2","target":"5R9yKfN1vItuv__HgCwP7","targetHandle":"y2","data":{"edgeStyle":"solid"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFz2-5R9yKfN1vItuv__HgCwP7y2","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"5R9yKfN1vItuv__HgCwP7","sourceHandle":"x2","target":"RkPVaSF9XnX6uHUns_-oC","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7x2-RkPVaSF9XnX6uHUns_-oCw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"5R9yKfN1vItuv__HgCwP7","sourceHandle":"y2","target":"qIJ6dUppjAjOTA8eQbp0n","targetHandle":"z1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-5R9yKfN1vItuv__HgCwP7y2-Wpk4TvxcZOJgAoXjrOsZFz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"qIJ6dUppjAjOTA8eQbp0n","sourceHandle":"w2","target":"ludceg3fQVkilNTKWznti","targetHandle":"x1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFw2-ludceg3fQVkilNTKWzntix1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"q1yaf-RbHIQsOqfzjn4k4","sourceHandle":"y2","target":"92-ebM0EwQ3nLjZKtvCZX","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-q1yaf-RbHIQsOqfzjn4k4y2-MSeNU5cURBInhPlvnhVfOz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"qIJ6dUppjAjOTA8eQbp0n","sourceHandle":"y2","target":"d9ZXdU73jiCdeNHQv1_DH","targetHandle":"z1","data":{"edgeStyle":"solid"},"selected":true,"selectable":true,"focusable":true,"id":"reactflow__edge-qIJ6dUppjAjOTA8eQbp0ny2-Wpk4TvxcZOJgAoXjrOsZFz1"},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"d9ZXdU73jiCdeNHQv1_DH","sourceHandle":"w2","target":"MSeNU5cURBInhPlvnhVfO","targetHandle":"x1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFw2-MSeNU5cURBInhPlvnhVfOx1","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"d9ZXdU73jiCdeNHQv1_DH","sourceHandle":"x2","target":"o3XFXW2HHLBoxlbEnoWdZ","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFx2-o3XFXW2HHLBoxlbEnoWdZw1","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"d9ZXdU73jiCdeNHQv1_DH","sourceHandle":"z2","target":"R3aRhqCslwhegMfHtxg5z","targetHandle":"y1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-d9ZXdU73jiCdeNHQv1_DHz2-Wpk4TvxcZOJgAoXjrOsZFy1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","target":"kJD1K2-ZkoezFCfpmOM0Z","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"pQSbDAqEripuhCsgK5XMD","selected":true,"focusable":true,"selectable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"R3aRhqCslwhegMfHtxg5z","sourceHandle":"x2","target":"kJD1K2-ZkoezFCfpmOM0Z","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFx2-kJD1K2-ZkoezFCfpmOM0Zw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"IkPZel5zxXWIx90Qx7fZI","sourceHandle":"y2","target":"H22jAI2W5QLL-b1rq-c56","targetHandle":"z2","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-mXCKtLUvwVJkHrpHzOecqy2-H22jAI2W5QLL-b1rq-c56z2","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"IkPZel5zxXWIx90Qx7fZI","sourceHandle":"y2","target":"boYX1QcJullypfX4sevdy","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-mXCKtLUvwVJkHrpHzOecqy2-boYX1QcJullypfX4sevdyz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"Wpk4TvxcZOJgAoXjrOsZF","sourceHandle":"w2","target":"zL4QEM5xZO8XWXXWrdPuj","targetHandle":"x1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFw2-zL4QEM5xZO8XWXXWrdPujx1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"R3aRhqCslwhegMfHtxg5z","sourceHandle":"z2","target":"Wpk4TvxcZOJgAoXjrOsZF","targetHandle":"y1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355z2-Wpk4TvxcZOJgAoXjrOsZFy1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"sourceHandle":"x2","target":"SP-d4YngpYXkeIB9SSD-K","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"glDT_FnQTOOAyIAPLWFZW","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"Wpk4TvxcZOJgAoXjrOsZF","sourceHandle":"x2","target":"bEVCT5QGY3uw0kIfAELKh","targetHandle":"w1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFx2-bEVCT5QGY3uw0kIfAELKhw1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"Wpk4TvxcZOJgAoXjrOsZF","sourceHandle":"y2","target":"JE12g5cqnwmgeTle14Vxw","targetHandle":"w1","data":{"edgeStyle":"solid"},"selected":true,"id":"reactflow__edge-Wpk4TvxcZOJgAoXjrOsZFy2-yvdfoly5WHHTq2Puss355w1","selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"JE12g5cqnwmgeTle14Vxw","sourceHandle":"z2","target":"UQ8N7gcVpRLAYXgUNHBt5","targetHandle":"y1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355z2-UQ8N7gcVpRLAYXgUNHBt5y1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"JE12g5cqnwmgeTle14Vxw","sourceHandle":"z2","target":"iNsXTtcIHsI_i-mCfjGYn","targetHandle":"y2","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355z2-iNsXTtcIHsI_i-mCfjGYny2","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"JE12g5cqnwmgeTle14Vxw","sourceHandle":"y2","target":"At5exN7ZAx2IzY3cTCzHm","targetHandle":"z2","data":{"edgeStyle":"solid"},"id":"reactflow__edge-JE12g5cqnwmgeTle14Vxwy2-At5exN7ZAx2IzY3cTCzHmz2","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"At5exN7ZAx2IzY3cTCzHm","sourceHandle":"x2","target":"yvdfoly5WHHTq2Puss355","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-At5exN7ZAx2IzY3cTCzHmx2-yvdfoly5WHHTq2Puss355w1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"y2","target":"vZxdswGLHCPi5GSuXEcHJ","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355y2-vZxdswGLHCPi5GSuXEcHJz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"y2","target":"a-_iIE7UdoXzD00fD9MxN","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355y2-a-_iIE7UdoXzD00fD9MxNz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"y2","target":"J0enF8UTVzY3H4n3pbPIF","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355y2-J0enF8UTVzY3H4n3pbPIFz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"y2","target":"W4WwTmgZGnWmiYsB0ezml","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355y2-W4WwTmgZGnWmiYsB0ezmlz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0.8 8","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"y2","target":"mXCKtLUvwVJkHrpHzOecq","targetHandle":"z1","data":{"edgeStyle":"dashed"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355y2-mXCKtLUvwVJkHrpHzOecqz1","selected":true,"selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"z2","target":"jXtqI8k4Abz-vr01IcpWL","targetHandle":"w1","data":{"edgeStyle":"solid"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355z2-jXtqI8k4Abz-vr01IcpWLw1","selected":true,"type":"step","selectable":true,"focusable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"yvdfoly5WHHTq2Puss355","sourceHandle":"z2","target":"XzXLGjJr2F8Ln7gP0e5N8","targetHandle":"w2","data":{"edgeStyle":"solid"},"id":"reactflow__edge-yvdfoly5WHHTq2Puss355z2-XzXLGjJr2F8Ln7gP0e5N8w2","selected":true,"type":"step","focusable":true,"selectable":true},{"style":{"strokeDasharray":"0","strokeLinecap":"round","strokeWidth":3.5,"stroke":"#2b78e4"},"source":"MKVcPM2EzAr2_Ieyp9Fu3","sourceHandle":"y2","target":"iA0C1mFlM_73GcL9XNJmF","targetHandle":"z1","data":{"edgeStyle":"solid"},"selected":true,"selectable":true,"focusable":true,"id":"reactflow__edge-MKVcPM2EzAr2_Ieyp9Fu3y2-iA0C1mFlM_73GcL9XNJmFz1"}]} \ No newline at end of file diff --git a/src/data/roadmaps/api/api.md b/src/data/roadmaps/api/api.md new file mode 100644 index 000000000..17caaf3af --- /dev/null +++ b/src/data/roadmaps/api/api.md @@ -0,0 +1,63 @@ +--- +jsonUrl: '/jsons/roadmaps/api.json' +pdfUrl: '/pdfs/roadmaps/api.pdf' +order: 9 +isForkable: false +briefTitle: 'API Design' +briefDescription: 'Step by step guide to learn how to design and build robust APIs.' +title: 'API Design' +description: 'Step by step guide to learn how to design and build robust APIs.' +isNew: true +hasTopics: true +dimensions: + width: 968 + height: 2317.91 +schema: + headline: 'API Design' + description: 'Step by step guide to learn how to design and build robust APIs.' + imageUrl: 'https://roadmap.sh/roadmaps/api.png' + datePublished: '2023-05-17' + dateModified: '2023-05-17' +seo: + title: 'API Design' + description: 'Step by step guide to learn how to design and build robust APIs in 2024.' + keywords: + - 'guide to becoming a api designer' + - 'guide to becoming an api engineer' + - 'api developer' + - 'api engineer' + - 'api skills' + - 'guide to api' + - 'asp.net developer roadmap' + - 'asp net developer roadmap' + - 'asp developer roadmap' + - 'api roadmap' + - 'api skills' + - 'api skills test' + - 'skills for api' + - 'cloud development' + - 'what is api' + - 'api quiz' + - 'api interview questions' + - 'api engineer roadmap' + - 'api developer roadmap' + - 'become an api developer' + - 'api developer career path' + - 'api developer' + - 'modern api developer' +relatedRoadmaps: + - 'backend' + - 'devops' + - 'python' + - 'golang' + - 'java' + - 'nodejs' +sitemap: + priority: 1 + changefreq: 'monthly' +tags: + - 'roadmap' + - 'main-sitemap' + - 'skill-roadmap' +renderer: 'editor' +--- diff --git a/src/data/roadmaps/api/content/api-documentation-tools@5R9yKfN1vItuv__HgCwP7.md b/src/data/roadmaps/api/content/api-documentation-tools@5R9yKfN1vItuv__HgCwP7.md new file mode 100644 index 000000000..a1caff94d --- /dev/null +++ b/src/data/roadmaps/api/content/api-documentation-tools@5R9yKfN1vItuv__HgCwP7.md @@ -0,0 +1,3 @@ +# API Documentation Tools + +API Documentation Tools are instrumental in conveying the intricacies of API design to both technical developers and non-technical stakeholders. These tools help in creating comprehensive, easy-to-understand, and searchable documentation encompassing all the elements of an API such as its functions, classes, return types, arguments, and more. Thorough documentation is central in API design as it fosters seamless adoption, effective implementation, and efficient troubleshooting of APIs. Various tools exist including Swagger, DapperDox, and ReDoc, each with unique functionalities to suit different API documentation requirements. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-gateways@MJeUD4fOHaJu1oxk4uQ-x.md b/src/data/roadmaps/api/content/api-gateways@MJeUD4fOHaJu1oxk4uQ-x.md new file mode 100644 index 000000000..651ae1241 --- /dev/null +++ b/src/data/roadmaps/api/content/api-gateways@MJeUD4fOHaJu1oxk4uQ-x.md @@ -0,0 +1,3 @@ +# API Gateways + +API Gateways act as the main point of entry in a microservices architecture, often responsible for request routing, composition, and protocol translation. They play a significant role in API design by providing a shared layer to handle non-business tasks. This not only simplifies how consumers interact with the backend services but also helps in maintaining the security, enforcing policies, and providing analytics over the API usage. When designing APIs, understanding and implementing efficient API Gateways is an invaluable skill, as these gateways form a crucial component of any well-structured, scalable API architecture. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-integration-patterns@R3aRhqCslwhegMfHtxg5z.md b/src/data/roadmaps/api/content/api-integration-patterns@R3aRhqCslwhegMfHtxg5z.md new file mode 100644 index 000000000..1be42bd17 --- /dev/null +++ b/src/data/roadmaps/api/content/api-integration-patterns@R3aRhqCslwhegMfHtxg5z.md @@ -0,0 +1,3 @@ +# API Integration Patterns + +API Integration Patterns, in the context of API Design, refers to the common paradigms and approaches used to enable communication between services. These patterns dictate how different APIs interact and exchange data, allowing software applications to work cohesively. They play a vital role in application development by providing a standard method for connecting diverse software components. By understanding and implementing these patterns, developers can design more robust, scalable, and interoperable APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-keys--management@tzUJwXu_scwQHnPPT0oY-.md b/src/data/roadmaps/api/content/api-keys--management@tzUJwXu_scwQHnPPT0oY-.md new file mode 100644 index 000000000..39ed6717d --- /dev/null +++ b/src/data/roadmaps/api/content/api-keys--management@tzUJwXu_scwQHnPPT0oY-.md @@ -0,0 +1,3 @@ +# API Keys & Management + +API keys and management is an integral part of API design. An API key is a unique identifier used to authenticate a user, developer, or calling program to an API. This ensures security and control over API endpoints, as only those with a valid API key can make requests. API Management, on the other hand, refers to the practices and tools that enable an organization to govern and monitor its API usage. It involves all the aspects of managing APIs including design, deployment, documentation, security, versioning, and analytics. Both elements play crucial roles in securing and organizing API access for efficient and controlled data sharing and communication. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-lifecycle-management@At5exN7ZAx2IzY3cTCzHm.md b/src/data/roadmaps/api/content/api-lifecycle-management@At5exN7ZAx2IzY3cTCzHm.md new file mode 100644 index 000000000..b1b4bece2 --- /dev/null +++ b/src/data/roadmaps/api/content/api-lifecycle-management@At5exN7ZAx2IzY3cTCzHm.md @@ -0,0 +1,3 @@ +# API Lifecycle Management + +API Lifecycle Management is a crucial aspect in API design that oversees the process of creating, managing, and retiring APIs. This involves various stages from initial planning, designing, testing, deployment, to eventual retirement of the API. Proper lifecycle management ensures that an API meets the requirements, is reliable, and that it evolves with the needs of end users and developers. Moreover, it helps in maintaining the security, performance, and accessibility of the API throughout its lifetime. This comprehensive approach enables organizations to make the most of their APIs, mitigate issues, and facilitate successful digital transformation. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-performance@d9ZXdU73jiCdeNHQv1_DH.md b/src/data/roadmaps/api/content/api-performance@d9ZXdU73jiCdeNHQv1_DH.md new file mode 100644 index 000000000..791a4289e --- /dev/null +++ b/src/data/roadmaps/api/content/api-performance@d9ZXdU73jiCdeNHQv1_DH.md @@ -0,0 +1,3 @@ +# API Performance + +When we talk about API design, one crucial aspect that demands our attention is API Performance. API Performance refers to the efficiency and speed at which a developed API can execute tasks and communicate with other programs or software components. This fundamental aspect can directly impact the responsiveness of an application, determining how quickly data can be exchanged, processed, and presented to the end-user. Improving the API performance often resolves problems related to the user experience and enhances the overall performance of the application that the API is integrated with. API performance, therefore, plays a pivotal role both in facilitating optimized interactions between systems and in determining the overall success of the digital products that rely on such interfaces. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-security@qIJ6dUppjAjOTA8eQbp0n.md b/src/data/roadmaps/api/content/api-security@qIJ6dUppjAjOTA8eQbp0n.md new file mode 100644 index 000000000..25ba03c7c --- /dev/null +++ b/src/data/roadmaps/api/content/api-security@qIJ6dUppjAjOTA8eQbp0n.md @@ -0,0 +1,3 @@ +# API Security + +API Security refers to the practices and products that are used to secure application programming interfaces (APIs). In the context of design, it is an essential component that helps ensure that a deployed API achieves its objectives in a safe and secure manner. This includes safeguarding the data, preventing unauthorized access, and protecting the system that hosts the API. API security encompasses the strategies, procedures and technology used to protect APIs from malicious attacks or unauthorized access while guaranteeing optimum performance, availability, and data privacy. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/api-testing@Wpk4TvxcZOJgAoXjrOsZF.md b/src/data/roadmaps/api/content/api-testing@Wpk4TvxcZOJgAoXjrOsZF.md new file mode 100644 index 000000000..7700696a5 --- /dev/null +++ b/src/data/roadmaps/api/content/api-testing@Wpk4TvxcZOJgAoXjrOsZF.md @@ -0,0 +1,3 @@ +# API Testing + +API Testing refers to the process of checking the functionality, reliability, performance, and security of Application Programming Interfaces (APIs). It plays a crucial role in API design as it ensures that the APIs work correctly and as expected. This kind of testing does not require a user interface and mainly focuses on the business logic layer of the software architecture. API Testing is integral to guarantee that the data communication and responses between different software systems are error-free and streamlined. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/attribute-based-access-control-abac@dZTe_kxIUQsc9N3w920aR.md b/src/data/roadmaps/api/content/attribute-based-access-control-abac@dZTe_kxIUQsc9N3w920aR.md new file mode 100644 index 000000000..dfb6c927f --- /dev/null +++ b/src/data/roadmaps/api/content/attribute-based-access-control-abac@dZTe_kxIUQsc9N3w920aR.md @@ -0,0 +1,3 @@ +# Attribute Based Access Control (ABAC) - An Authorization Method in API Design + +Attribute Based Access Control (ABAC) is a flexible and powerful authorization method in the realm of API Design. Distinct from Role-Based Access Control (RBAC), which relies on predefined roles and permissions, ABAC uses attributes to build policies and make decisions. These attributes can be associated with the user, the action they want to perform, targeted resources, or the environment. With ABAC, finer-grained access control can be achieved, thereby improving the security and efficiency of APIs. This approach is widely used in complex and dynamic environments where access control requirements can be multifaceted and deeply context-dependent. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/authentication-methods@cQnQ9v3mH27MGNwetz3JW.md b/src/data/roadmaps/api/content/authentication-methods@cQnQ9v3mH27MGNwetz3JW.md new file mode 100644 index 000000000..12379efe6 --- /dev/null +++ b/src/data/roadmaps/api/content/authentication-methods@cQnQ9v3mH27MGNwetz3JW.md @@ -0,0 +1,3 @@ +# Authentication Methods in API Design + +Application Programming Interfaces (APIs) are critical components in software development that allow different software systems to communicate and share functionality. To ensure secure communication, it's essential to authenticate the parties involved in the API transactions. The authentication process confirms the identity of the API user. There are numerous authentication methods available when designing an API, each with its own pros and cons. This includes Basic Authentication, API Key Authentication, OAuth, and JWT among others. Understanding these different methods and their best use cases is fundamental to designing secure and effective APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/authorization-methods@nHbn8_sMY7J8o6ckbD-ER.md b/src/data/roadmaps/api/content/authorization-methods@nHbn8_sMY7J8o6ckbD-ER.md new file mode 100644 index 000000000..4ba6866d0 --- /dev/null +++ b/src/data/roadmaps/api/content/authorization-methods@nHbn8_sMY7J8o6ckbD-ER.md @@ -0,0 +1,3 @@ +# Authorization Methods in API Design + +In API design, authorization methods play a crucial role in ensuring the security and integrity of data transactions. They are the mechanisms through which an API identifies and validates a user, system, or application before granting them access to specific resources. These methods include Basic Authentication, OAuth, Token-based authentication, JSON Web Tokens (JWT), and API Key based, among others. So, understanding these methods enhances the ability to design APIs that effectively protect resources while allowing necessary access. Each method has its own pros and cons, usage scenarios and security features that make them more suitable for certain situations rather than others. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/basic-auth@0FzHERK5AeYL5wv1FBJbH.md b/src/data/roadmaps/api/content/basic-auth@0FzHERK5AeYL5wv1FBJbH.md new file mode 100644 index 000000000..20278ceeb --- /dev/null +++ b/src/data/roadmaps/api/content/basic-auth@0FzHERK5AeYL5wv1FBJbH.md @@ -0,0 +1,3 @@ +# Basic Auth in API Design + +Basic Auth, short for Basic Authentication, is a simple method often used in API design for handling user authentication. In this method, client credentials, consisting of a username and password pair, are passed to the API server in a field in the HTTP header. The server then verifies these credentials before granting access to protected resources. Although Basic Auth is straightforward to implement, it is less secure compared to more advanced methods since it involves transmitting credentials in an encoded, but not encrypted, format. It is often used in cases where simplicity is paramount, or High security levels are not required. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/basics-of-dns@v4nJYD9yiIEUviLPhVTCD.md b/src/data/roadmaps/api/content/basics-of-dns@v4nJYD9yiIEUviLPhVTCD.md new file mode 100644 index 000000000..6ef1fbf98 --- /dev/null +++ b/src/data/roadmaps/api/content/basics-of-dns@v4nJYD9yiIEUviLPhVTCD.md @@ -0,0 +1,3 @@ +# Basics of DNS + +When discussing the foundational elements of API Design, the Basics of DNS (Domain Name System) can't be overlooked. DNS plays a fundamental role in the way APIs function, acting as the internet's equivalent of a phone book, it interprets human-friendly hostnames into IP addresses that APIs need for communication. Understanding this complex system is essential as it allows for better comprehension of the navigation and messaging flow in API Design. For API developers, knowledge about DNS can significantly aid in troubleshooting connectivity issues, ensuring secure connections, and optimizing API architecture with more efficient calls. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/batch-processing@X68HXAAV-nKo-V4Fu1o72.md b/src/data/roadmaps/api/content/batch-processing@X68HXAAV-nKo-V4Fu1o72.md new file mode 100644 index 000000000..670186bed --- /dev/null +++ b/src/data/roadmaps/api/content/batch-processing@X68HXAAV-nKo-V4Fu1o72.md @@ -0,0 +1,3 @@ +# Batch Processing in API Design + +Batch Processing refers to the method of handling bulk data requests in API design. Here, multiple API requests are packed and processed as a single group or 'batch'. Instead of making numerous individual API calls, a user can make one batch request with numerous operations. This approach can increase performance and efficiency by reducing the overhead of establishing and closing multiple connections. The concept of 'batch processing' in API design is particularly useful in data-intensive applications or systems where the need for processing high volumes of data is prevalent. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/best-practices@q1yaf-RbHIQsOqfzjn4k4.md b/src/data/roadmaps/api/content/best-practices@q1yaf-RbHIQsOqfzjn4k4.md new file mode 100644 index 000000000..84ed65702 --- /dev/null +++ b/src/data/roadmaps/api/content/best-practices@q1yaf-RbHIQsOqfzjn4k4.md @@ -0,0 +1,3 @@ +# Best Practices in API Design + +API design has rapidly emerged as a vital component of software development. When designing an API, it is crucial to follow best practices to ensure optimization, scalability, and efficiency. The best practices in API design revolve around principles such as simplicity, consistency, security, and proper documentation among others. These practices not only smoothens the development process but also makes the API more user-friendly, stable, and easily maintainable. Thus, following the best practices in API design is not an option but rather a must for developers and organizations looking to create APIs that last longer and perform better. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/building-json--restful-apis@awdoiCHz7Yc3kYac_iy-a.md b/src/data/roadmaps/api/content/building-json--restful-apis@awdoiCHz7Yc3kYac_iy-a.md new file mode 100644 index 000000000..fede26f5e --- /dev/null +++ b/src/data/roadmaps/api/content/building-json--restful-apis@awdoiCHz7Yc3kYac_iy-a.md @@ -0,0 +1,3 @@ +# Building JSON / RESTful APIs + +Building JSON/RESTful APIs involves designing and implementing APIs that adhere to the architectural constraints of Representational State Transfer (REST). These APIs use JSON (JavaScript Object Notation) as a format for information interchange, due to its lightweight, easy-to-understand, and universally accepted nature. A well-designed RESTful API, utilizing JSON, is key in developing applications that are scalable, maintainable, and easily integrated with other systems. This design approach enables the resources on a server to be accessed and manipulated using standard HTTP protocols, facilitating communication between different services and systems. Furthermore, it enables client-server interactions to be stateless, meaning each request from a client must contain all the information needed by the server to understand and process the request. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/caching-strategies@PrvRCR4HCdGar0vcUbG_a.md b/src/data/roadmaps/api/content/caching-strategies@PrvRCR4HCdGar0vcUbG_a.md new file mode 100644 index 000000000..e015894ef --- /dev/null +++ b/src/data/roadmaps/api/content/caching-strategies@PrvRCR4HCdGar0vcUbG_a.md @@ -0,0 +1,3 @@ +# Caching Strategies in API Design + +Caching in API design serves as a technique that allows you to store copies of data temporarily in places where you can access it more readily. By obtaining this data from high-speed storage rather than slower storage sources, you can help improve the overall speed and performance of the API. Multiple strategies such as HTTP caching, database caching, application caching, and CDN caching can be implemented, each with its own sets of advantages and considerations. Understanding different caching strategies in the context of API design is crucial for designing efficient, high-performing APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/ccpa@a-_iIE7UdoXzD00fD9MxN.md b/src/data/roadmaps/api/content/ccpa@a-_iIE7UdoXzD00fD9MxN.md new file mode 100644 index 000000000..c93c67983 --- /dev/null +++ b/src/data/roadmaps/api/content/ccpa@a-_iIE7UdoXzD00fD9MxN.md @@ -0,0 +1,3 @@ +# CCPA under Standards and Compliance in API Design + +The California Consumer Privacy Act (CCPA) is a pivotal state statute meant to enhance privacy rights and consumer protection for individuals within California, United States. API Design greatly impacts compliance with CCPA, as improper management and exposure of user data can potentially violate this law. Crucially, designing APIs means considering data privacy, security, and user consent from the very foundation. Programmatically, CCPA compliance may involve structuring APIs to respond to user demands such as data access, data deletion, and opt-out requests. It imposes a significant responsibility on API developers to enforce user control over data and maintain rigorous standards of data protection. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/common-vulnerabilities@G70wvcOM1Isrx5ZBvS2xP.md b/src/data/roadmaps/api/content/common-vulnerabilities@G70wvcOM1Isrx5ZBvS2xP.md new file mode 100644 index 000000000..f47338697 --- /dev/null +++ b/src/data/roadmaps/api/content/common-vulnerabilities@G70wvcOM1Isrx5ZBvS2xP.md @@ -0,0 +1,3 @@ +# Common Vulnerabilities in API Design + +API design is a critical component of modern software development, enabling various applications to communicate and share data. However, as the use of APIs expands, so does the potential for security vulnerabilities. Understanding common vulnerabilities in API design is crucial to protecting sensitive data and maintaining a secure system. These vulnerabilities might arise due to lack of proper validation, weak authentication mechanisms, insecure endpoint configurations among others. This topic will delve into these common vulnerabilities, focusing on their identification, potential impacts, and how to design APIs with security best practices to mitigate these threats. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/content-negotiation@TX_hg7EobNJhmWKsMCaT1.md b/src/data/roadmaps/api/content/content-negotiation@TX_hg7EobNJhmWKsMCaT1.md new file mode 100644 index 000000000..7e1c8fee4 --- /dev/null +++ b/src/data/roadmaps/api/content/content-negotiation@TX_hg7EobNJhmWKsMCaT1.md @@ -0,0 +1,3 @@ +# Content Negotiation in API Design + +In the context of API design, Content Negotiation refers to the process where the client and the server communicate about the data representation which is acceptable for both of them. It allows clients to indicate the preferred response format, such as JSON, XML, or HTML. This mechanism leads to flexible and adaptable APIs, enhancing their usability. Understanding and efficiently utilizing content negotiation is an integral part of mastering API design basics. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/contract-testing@NqeBglhzukVMMEF9p2CXc.md b/src/data/roadmaps/api/content/contract-testing@NqeBglhzukVMMEF9p2CXc.md new file mode 100644 index 000000000..904545344 --- /dev/null +++ b/src/data/roadmaps/api/content/contract-testing@NqeBglhzukVMMEF9p2CXc.md @@ -0,0 +1,3 @@ +# Contract Testing in API Design + +Contract Testing is a critical aspect of maintaining a robust and reliable API infrastructure. In the realm of API design, Contract Testing refers to the method of ensuring that APIs work as anticipated and that changes to them do not break their intended functionality. This approach validates the interaction between two different systems, typically consumer and provider ( API), ensuring they comply with their agreed-upon contract. By defining clear and concise contracts for our APIs, developers can avoid common deployment issues and enhance system integration processes. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/cookies@UFuX8wcxZQ7dvaQF_2Yp8.md b/src/data/roadmaps/api/content/cookies@UFuX8wcxZQ7dvaQF_2Yp8.md new file mode 100644 index 000000000..547ece306 --- /dev/null +++ b/src/data/roadmaps/api/content/cookies@UFuX8wcxZQ7dvaQF_2Yp8.md @@ -0,0 +1,3 @@ +# Cookies in API Design + +Cookies play an instrumental role in the field of API (Application Programming Interface) design. Essentially, cookies are small bits of data stored on a user's browser that enables stateful HTTP sessions, by storing pertinent information between server communications. In API design, cookies are especially useful when authentication is required. Cookies can store session tokens, thereby allowing users to stay logged in across multiple sessions or different web pages. Understanding cookies and how they function is vital in API design for sustaining user sessions, providing enhanced user experience, and securing user information. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/cors@GRlsBogOlOwuqhMMPyHN3.md b/src/data/roadmaps/api/content/cors@GRlsBogOlOwuqhMMPyHN3.md new file mode 100644 index 000000000..0b2d567c6 --- /dev/null +++ b/src/data/roadmaps/api/content/cors@GRlsBogOlOwuqhMMPyHN3.md @@ -0,0 +1,3 @@ +# CORS under API Design + +Cross-Origin Resource Sharing (CORS) is a critical concept in API Design. It is a mechanism that uses HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. By default, web browsers prohibit web pages from making requests to a different domain than the one the web page came from. CORS is the guideline that lets you configure a set of rules on the server to define which types of cross-domain requests are allowed, providing much-needed flexibility without compromising security. Understanding CORS is crucial in designing APIs that ensure safe and effective inter-domain communication. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/different-api-styles@o8i093VQv-T5Qf1yGqU0R.md b/src/data/roadmaps/api/content/different-api-styles@o8i093VQv-T5Qf1yGqU0R.md new file mode 100644 index 000000000..cbcb86a72 --- /dev/null +++ b/src/data/roadmaps/api/content/different-api-styles@o8i093VQv-T5Qf1yGqU0R.md @@ -0,0 +1,3 @@ +# Different API Styles + +Application Programming Interface (API) design isn't a one-size-fits-all endeavor. APIs can be structured in various styles, each with its own unique characteristics, advantages, and use cases. Early identification of the appropriate API style is crucial in ensuring a functional, efficient and seamless end-user experience. Commonly used API styles include REST, SOAP, GraphQL, and gRPC. Understanding these diverse API styles would help in making better design choices, fostering efficient overall system architecture, and promoting an intuitive and easy-to-use application. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/error-handling--retries@XD1vDtrRQFbLyKJaD1AlA.md b/src/data/roadmaps/api/content/error-handling--retries@XD1vDtrRQFbLyKJaD1AlA.md new file mode 100644 index 000000000..dc2020afe --- /dev/null +++ b/src/data/roadmaps/api/content/error-handling--retries@XD1vDtrRQFbLyKJaD1AlA.md @@ -0,0 +1,5 @@ +# Error Handling / Retries + +When creating effective API designs, addressing Error Handling and Retries forms an essential facet. This is primarily due to the fact that APIs aren't always error-free and instances of network hiccups or input inaccuracies from users can occur. Without robust error handling, such occurrences can easily lead to catastrophic application failure or unsatisfactory user experiences. + +In this context, error handling can refer to validating inputs, managing exceptions, and returning appropriate error message or status codes to the user. Meanwhile, the concept of retries comes into play to ensure maximum request success amidst transient failures. Through correctly implemented retries, an API can repeatedly attempt to execute a request until it is successful, thus ensuring seamless operation. The criteria and mechanisms of retries, including the count, delay, and conditions for retries, are crucial aspects to solidify during the API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/error-handling@8tELdagrOaGCf3nMVs8t3.md b/src/data/roadmaps/api/content/error-handling@8tELdagrOaGCf3nMVs8t3.md new file mode 100644 index 000000000..63e81e1aa --- /dev/null +++ b/src/data/roadmaps/api/content/error-handling@8tELdagrOaGCf3nMVs8t3.md @@ -0,0 +1,3 @@ +# Error Handling in API Design + +Error Handling is a crucial aspect of API design that ensures the stability, usability, and reliability of the API in production. APIs are designed to help systems communicate with each other. However, there can be instances where these systems might encounter exceptions or errors. The process of predicting, catching, and managing these error occurrences is what we refer to as 'Error Handling'. In the context of API Design, it involves defining and implementing specific strategies to detect, manage and inform consumers of any exception or error that occurs while executing requests. Configuring this appropriately provides a more robust and seamless communication experience, enabling developers to debug and rectify issues more efficiently. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/event-driven-architecture@oMfOBkVsgiLvFLicOUdx6.md b/src/data/roadmaps/api/content/event-driven-architecture@oMfOBkVsgiLvFLicOUdx6.md new file mode 100644 index 000000000..2500cd6da --- /dev/null +++ b/src/data/roadmaps/api/content/event-driven-architecture@oMfOBkVsgiLvFLicOUdx6.md @@ -0,0 +1,3 @@ +# Event Driven Architecture in API Design + +Event-driven architecture (EDA) is a software design concept that revolves around the production, interpretation, and consumption of events. With regards to API design, EDA grants systems the flexibility to decentralize analytics, microservices, and operations, thus promoting real-time information sharing and reaction. Event-driven APIs prioritize asynchronous communication, allowing applications to stay responsive even when tackling heavy data loads. For an effective API, adhering to EDA provides data reliability, maturity with a scalable structure, and efficient real-time data processing capabilities. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/functional-testing@6lm3wy9WTAERTqXCn6pFt.md b/src/data/roadmaps/api/content/functional-testing@6lm3wy9WTAERTqXCn6pFt.md new file mode 100644 index 000000000..58fbf8d7b --- /dev/null +++ b/src/data/roadmaps/api/content/functional-testing@6lm3wy9WTAERTqXCn6pFt.md @@ -0,0 +1,3 @@ +# Functional Testing in API Design + +Functional testing in the context of API design involves validating the endpoints and key-value pairs of an API. It ensures the server response works as expected and assesses the functionality of the API -- whether it is performing all the intended functions correctly. Various approaches like testing request-response pairs, error codes, and data accuracy are used. Functional testing can provide invaluable insights into how well an API meets the specified requirements and whether it is ready for integration into applications. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/gdpr@vZxdswGLHCPi5GSuXEcHJ.md b/src/data/roadmaps/api/content/gdpr@vZxdswGLHCPi5GSuXEcHJ.md new file mode 100644 index 000000000..bd43e7f57 --- /dev/null +++ b/src/data/roadmaps/api/content/gdpr@vZxdswGLHCPi5GSuXEcHJ.md @@ -0,0 +1,3 @@ +# GDPR in API Design + +The General Data Protection Regulation (GDPR) is an essential standard in API Design that addresses the storage, transfer, and processing of personal data of individuals within the European Union. With regards to API Design, considerations must be given on how APIs handle, process, and secure the data to conform with GDPR's demands on data privacy and security. This includes requirements for explicit consent, right to erasure, data portability, and privacy by design. Non-compliance with these standards not only leads to hefty fines but may also erode trust from users and clients. As such, understanding the impact and integration of GDPR within API design is pivotal for organizations handling EU residents' data. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/graphql-apis@MKVcPM2EzAr2_Ieyp9Fu3.md b/src/data/roadmaps/api/content/graphql-apis@MKVcPM2EzAr2_Ieyp9Fu3.md new file mode 100644 index 000000000..2e2b82102 --- /dev/null +++ b/src/data/roadmaps/api/content/graphql-apis@MKVcPM2EzAr2_Ieyp9Fu3.md @@ -0,0 +1,3 @@ +# GraphQL APIs + +GraphQL is an open-source data query and manipulation language for APIs, and a runtime for executing those queries with your existing data. Unlike REST, where you have predefined data return structures for each endpoint, GraphQL APIs are designed around a type system and enable the client application to precisely specify what data it needs from the server. This gives a lot of flexibility and efficiency, leading to fewer round trips to the server and significantly enhancing the performance of the client application. Whether you are building a small project or an enterprise-scale application, understanding and implementing GraphQL APIs can result in cleaner, more manageable code. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/handling-crud-operations@zXxEiM5HeOn7W-Vue0tQf.md b/src/data/roadmaps/api/content/handling-crud-operations@zXxEiM5HeOn7W-Vue0tQf.md new file mode 100644 index 000000000..cd6b9ccbb --- /dev/null +++ b/src/data/roadmaps/api/content/handling-crud-operations@zXxEiM5HeOn7W-Vue0tQf.md @@ -0,0 +1,5 @@ +# Handling CRUD Operations in API Design + +When designing APIs, one needs to account for various types of interactions with data - these typically revolve around the CRUD operations; Create, Read, Update, and Delete. Whether the API is designed for a banking app or a social media platform, the need to create new data, read or retrieve existing data, update or modify that data, and delete unnecessary data is universal. + +Therefore, mastering CRUD operations in API design is a fundamental skill. Effective handling of CRUD operations facilitates seamless interaction between the front-end and back-end systems, and ensures proper data management, thereby improving user experience. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/hateoas@LByD1vhzunhY1uY1YGZHP.md b/src/data/roadmaps/api/content/hateoas@LByD1vhzunhY1uY1YGZHP.md new file mode 100644 index 000000000..bd6466890 --- /dev/null +++ b/src/data/roadmaps/api/content/hateoas@LByD1vhzunhY1uY1YGZHP.md @@ -0,0 +1,3 @@ +# HATEOAS in API Design + +Hypertext As The Engine Of Application State (HATEOAS) is a key concept in the design of RESTful APIs (Application Programming Interfaces). It implies that the API delivers data as well as information about available interactions. By utilizing hypermedia, it contributes to the self-descriptiveness and discoverability of the API. When correctly implemented, clients only need generic knowledge about hypermedia, not specific API semantics, which can significantly simplify client implementations and make APIs more flexible to changes. The principle of HATEOAS can enforce a more structured, standardized approach to API design and development. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/hipaa@W4WwTmgZGnWmiYsB0ezml.md b/src/data/roadmaps/api/content/hipaa@W4WwTmgZGnWmiYsB0ezml.md new file mode 100644 index 000000000..24abb37b1 --- /dev/null +++ b/src/data/roadmaps/api/content/hipaa@W4WwTmgZGnWmiYsB0ezml.md @@ -0,0 +1,3 @@ +# HIPAA in API Design + +HIPAA (Health Insurance Portability and Accountability Act) is a critical standard when it comes to API design in the healthcare industry. In essence, it provides the mandate for protecting sensitive patient data. Any organization dealing with protected health information (PHI) must ensure all required physical, network, and process security measures are in place. In the context of API design, HIPAA compliance means structuring endpoints, data transmission, and storage methods that align with these crucial safeguards. This encompasses encryption, access controls, audit controls, and integrity controls. Hence, understanding HIPAA is fundamental for API designers working in the healthcare domain. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http-caching@qAolZHf_jp8hCdtqHZwC8.md b/src/data/roadmaps/api/content/http-caching@qAolZHf_jp8hCdtqHZwC8.md new file mode 100644 index 000000000..a64a52f62 --- /dev/null +++ b/src/data/roadmaps/api/content/http-caching@qAolZHf_jp8hCdtqHZwC8.md @@ -0,0 +1,3 @@ +# HTTP Caching in API Design + +HTTP caching is a key aspect of API design which involves storing copies of responses to HTTP requests to speed up future requests. When an API receives the same request multiple times, instead of processing each request separately, it can use a previously stored response, thereby improving performance and efficiency. The cache is governed by headers on the HTTP requests and responses. Understanding and implementing HTTP caching in API design can drastically reduce latency, network traffic and improve the speed of an API. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http-headers@rE-0yibRH6B2UBKp351cf.md b/src/data/roadmaps/api/content/http-headers@rE-0yibRH6B2UBKp351cf.md new file mode 100644 index 000000000..47592732d --- /dev/null +++ b/src/data/roadmaps/api/content/http-headers@rE-0yibRH6B2UBKp351cf.md @@ -0,0 +1,3 @@ +# HTTP Headers in API Design + +HTTP Headers play a crucial role in API Design as they provide essential information between the client and server regarding the data to be exchanged. Headers are part of the HTTP request and response message, with types including Standard, Non-standard, Common or Uncommon headers. They can define parameters such as content type, authentication, response status, cookies, and more. Understanding and effectively utilizing HTTP Headers is key to designing robust and secure APIs. A well-defined set of headers ensures successful data exchange, handles errors gracefully, and improves overall communication between the client and server. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http-methods@rADHM-6NAxEjzmgiHefDX.md b/src/data/roadmaps/api/content/http-methods@rADHM-6NAxEjzmgiHefDX.md new file mode 100644 index 000000000..6ded77af6 --- /dev/null +++ b/src/data/roadmaps/api/content/http-methods@rADHM-6NAxEjzmgiHefDX.md @@ -0,0 +1,3 @@ +# HTTP Methods + +HTTP (Hypertext Transfer Protocol) Methods play a significant role in API design. They define the type of request a client can make to a server, providing the framework for interaction between client and server. Understanding HTTP methods is paramount to creating a robust and effective API. Some of the common HTTP methods used in API design include GET, POST, PUT, DELETE, and PATCH. Each of these methods signifies a different type of request, allowing for various interactions with your API endpoints. This in turn creates a more dynamic, functional, and user-friendly API. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http-status-codes@7szYyzLifKsepNU0c2KnN.md b/src/data/roadmaps/api/content/http-status-codes@7szYyzLifKsepNU0c2KnN.md new file mode 100644 index 000000000..61203ab39 --- /dev/null +++ b/src/data/roadmaps/api/content/http-status-codes@7szYyzLifKsepNU0c2KnN.md @@ -0,0 +1,3 @@ +# HTTP Status Codes + +HTTP Status Codes are an essential part of API Design, providing important information about the result of a request made to a server. They are 3-digit numbers where the first digit defines the class of response, while the last two digits do not have any categorization value. For instance, '200' stands for a successful HTTP request, while '404' signifies that a requested resource could not be found on the server. Efficient use of these codes can enhance API's robustness, making it more understandable and easier to debug. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http-versions@ACALE93mL4gnX5ThRIdRp.md b/src/data/roadmaps/api/content/http-versions@ACALE93mL4gnX5ThRIdRp.md new file mode 100644 index 000000000..b0727baa3 --- /dev/null +++ b/src/data/roadmaps/api/content/http-versions@ACALE93mL4gnX5ThRIdRp.md @@ -0,0 +1,3 @@ +# HTTP Versions in API Design + +HTTP or Hypertext Transfer Protocol is pivotal in the world of API design. HTTP versions specify how data should be packaged and transported, as well as how web servers and browsers should respond to commands. Understanding different HTTP versions and their features is essential for API designers as it directly impacts how well an API can communicate with other software and systems. From HTTP/1.0, the initial version of HTTP to HTTP/2 and the latest version HTTP/3, each version brings in improvements in speed, data transmission capabilities, and security. Selecting an appropriate HTTP version is crucial for API efficiency and performance. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/http@2HdKzAIQi15pr3YHHrbPp.md b/src/data/roadmaps/api/content/http@2HdKzAIQi15pr3YHHrbPp.md new file mode 100644 index 000000000..60e869ae9 --- /dev/null +++ b/src/data/roadmaps/api/content/http@2HdKzAIQi15pr3YHHrbPp.md @@ -0,0 +1,3 @@ +# HTTP in API Design + +HTTP, or Hypertext Transfer Protocol, is a fundamental piece of any API design. It is the protocol used for transmitting hypermedia data on the web, such as HTML webpages or JSON from a web API. Understanding HTTP is crucial in API design as it provides the structure for how requests and responses should be constructed and handled. It dictates how endpoints are defined, how data should be transferred, and what status codes should be used to convey specific scenarios. A solid grounding in HTTP principles allows for more robust, efficient and secure API designs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/idempotency@20KEgZH6cu_UokqWpV-9I.md b/src/data/roadmaps/api/content/idempotency@20KEgZH6cu_UokqWpV-9I.md new file mode 100644 index 000000000..5140569b9 --- /dev/null +++ b/src/data/roadmaps/api/content/idempotency@20KEgZH6cu_UokqWpV-9I.md @@ -0,0 +1,3 @@ +# Idempotency in API Design + +Idempotency in API design refers to the concept where multiple identical requests have the same effect as a single request. This means that no matter how many times a client sends the same request to the server, the server's state stays the same after the first request. Designing APIs to be idempotent is essential for reliability, as it allows retries without side-effects, reduces complexity in distributed systems, and provides better user experience in unstable network conditions. Understanding idempotency concepts can increase the robustness and fault tolerance of your APIs. It is usually applicable to `PUT`, `DELETE`, and sometimes `POST` methods in RESTful APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/integration-testing@qZELS5vw2feS7QfyD7spX.md b/src/data/roadmaps/api/content/integration-testing@qZELS5vw2feS7QfyD7spX.md new file mode 100644 index 000000000..e86c02128 --- /dev/null +++ b/src/data/roadmaps/api/content/integration-testing@qZELS5vw2feS7QfyD7spX.md @@ -0,0 +1,3 @@ +# Integration Testing in API Design + +Integration testing is a critical aspect of API design. It is a level of software testing where individual units or components are combined and tested as a group. The main purpose of integration testing in API design is to expose faults and discrepancies in the interaction between integrated units. This testing approach ensures that the different parts of an API work together seamlessly, to deliver the necessary functionality and performance. It helps detect issues related to the network, database, and performance, which unit tests cannot uncover. Thus, this level of testing is instrumental in validating the reliability, efficiency, and functionality of an API's integrated components. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/jwt@tWg68AHLIr1gIZA1za3jp.md b/src/data/roadmaps/api/content/jwt@tWg68AHLIr1gIZA1za3jp.md new file mode 100644 index 000000000..c22dec6ec --- /dev/null +++ b/src/data/roadmaps/api/content/jwt@tWg68AHLIr1gIZA1za3jp.md @@ -0,0 +1,3 @@ +# JSON Web Token (JWT) in API Design + +JSON Web Tokens, or JWT, are a popular and secure method of transferring information between two parties in the domain of API design. As a compact, URL-safe means of representing claims to be transferred between two parties, they play a vital role in security and authorization in modern APIs. By encoding these claims, the information can be verified and trusted with a digital signature - ensuring that the API end-points can handle requests in a secure and reliable way. JWT is a relatively lightweight and scalable method that brings improved authentication and information exchange processes in API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/kafka@boYX1QcJullypfX4sevdy.md b/src/data/roadmaps/api/content/kafka@boYX1QcJullypfX4sevdy.md new file mode 100644 index 000000000..88b917aee --- /dev/null +++ b/src/data/roadmaps/api/content/kafka@boYX1QcJullypfX4sevdy.md @@ -0,0 +1,3 @@ +# Kafka in API Design + +Apache Kafka is a real-time, fault-tolerant, and highly reliable messaging system that's integral to API design. It's primarily used to build real-time data streaming applications and microservices due to its inherent ability to handle high volume data and multi-subscriber support. In the context of API design, Kafka provides a robust messaging queue system that enables cloud-based platforms and services to communicate seamlessly with each other in a real-time environment. Moreover, the API designers use Kafka APIs such as Producer API, Consumer API, Streams API, and Connect API which enable the transmission and manipulation of messages within the Kafka ecosystem. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/learn-the-basics@duKkpzPjUU_-8kyJGHqRX.md b/src/data/roadmaps/api/content/learn-the-basics@duKkpzPjUU_-8kyJGHqRX.md new file mode 100644 index 000000000..530e312f7 --- /dev/null +++ b/src/data/roadmaps/api/content/learn-the-basics@duKkpzPjUU_-8kyJGHqRX.md @@ -0,0 +1,3 @@ +# Learn the Basics of API Design + +Application Programming Interfaces (APIs) are an integral part of modern development, allowing software applications to communicate and use functions from other software applications or services. API design, therefore, becomes a key part of any software development process. Furthermore, the basics of API design encompass understanding the principles of what an API is, how it works, and the various types of APIs, such as REST, SOAP, and GraphQL. This also includes understanding the standards and best practices in API design to ensure the development of powerful, user-friendly, and secure APIs. The foundation of API Design lies in this knowledge, setting the stage for more complex API designing and development. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/load-balancing@p5wsniYnOS7cbHd92RxGk.md b/src/data/roadmaps/api/content/load-balancing@p5wsniYnOS7cbHd92RxGk.md new file mode 100644 index 000000000..72b4d7448 --- /dev/null +++ b/src/data/roadmaps/api/content/load-balancing@p5wsniYnOS7cbHd92RxGk.md @@ -0,0 +1,3 @@ +# Load Balancing in API Design + +Load Balancing plays a crucial role in the domain of API Design. It primarily revolves around evenly and efficiently distributing network traffic across a group of backend servers, also known as a server farm or server pool. When it comes to API design, implementing load balancing algorithms is of immense importance to ensure that no single server bears too much demand. This allows for high availability and reliability by rerouting the traffic in case of server failure, effectively enhancing application performance and contributing to a positive user experience. Therefore, it's a vital tactic in ensuring the scalability and robustness of system architectures which heavily rely on API interactions. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/load-testing@7JNEx_cbqnAx3esvwZMOd.md b/src/data/roadmaps/api/content/load-testing@7JNEx_cbqnAx3esvwZMOd.md new file mode 100644 index 000000000..96f1855db --- /dev/null +++ b/src/data/roadmaps/api/content/load-testing@7JNEx_cbqnAx3esvwZMOd.md @@ -0,0 +1,3 @@ +# Load Testing in API Design + +Load testing is a crucial aspect of API design that ensures reliability, efficiency and performance under varying loads. It primarily focuses on identifying the maximum capacity of the API in terms of the volume of requests it can handle and its subsequent behavior when this threshold is reached or overloaded. By simulating varying degrees of user load, developers can identify and rectify bottlenecks or breakdown points in the system, hence enhancing overall API resilience. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/messaging-queues@IkPZel5zxXWIx90Qx7fZI.md b/src/data/roadmaps/api/content/messaging-queues@IkPZel5zxXWIx90Qx7fZI.md new file mode 100644 index 000000000..8a975fd84 --- /dev/null +++ b/src/data/roadmaps/api/content/messaging-queues@IkPZel5zxXWIx90Qx7fZI.md @@ -0,0 +1,3 @@ +# Messaging Queues in API Design + +Messaging Queues play a fundamental role in API design, particularly in creating robust, decoupled, and efficient systems. These queues act like a buffer, storing messages or data sent from a sender (producer), allowing a receiver (consumer) to retrieve and process them at its own pace. In the context of API design, this concept enables developers to handle high-volume data processing requirements, providing an asynchronous communication protocol between multiple services. The benefits of messaging queues in API design include better system scalability, fault tolerance, and increased overall system resiliency. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/microservices-architecture@PPeBbooE121zrgNwpVTiA.md b/src/data/roadmaps/api/content/microservices-architecture@PPeBbooE121zrgNwpVTiA.md new file mode 100644 index 000000000..119aede79 --- /dev/null +++ b/src/data/roadmaps/api/content/microservices-architecture@PPeBbooE121zrgNwpVTiA.md @@ -0,0 +1,3 @@ +# Microservices Architecture + +When it comes to API Design, Microservices Architecture plays a crucial role. It represents a unique method of developing software systems that focuses on building single-function modules with well-defined interfaces. Each microservice runs a unique process and communicates through a well-defined, lightweight mechanism (often HTTP resources API) to serve a specific business goal. This architecture allows rapid, reliable, and scalable deployment of large, complex applications. It facilitates the organization of the development team around independently deployable units, thereby enhancing productivity and speed. When designing an API, it's essential to adapt this model to get a flexible and scalable construction. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/mocking-apis@bEVCT5QGY3uw0kIfAELKh.md b/src/data/roadmaps/api/content/mocking-apis@bEVCT5QGY3uw0kIfAELKh.md new file mode 100644 index 000000000..a1c90409b --- /dev/null +++ b/src/data/roadmaps/api/content/mocking-apis@bEVCT5QGY3uw0kIfAELKh.md @@ -0,0 +1,3 @@ +# Mocking APIs under API Testing + +API mocking is a crucial aspect of API design and testing. It involves simulating the behaviors of real APIs to test various aspects of the system without the need of the real API being readily available. During the stages of development and testing, the API might be undefined or changes in the API can be expected, hence mocking comes into the picture. In such cases, it helps software developers and testers to isolate the system and work independently, enhancing the control over the input and output of the test. The focus here ranges from testing the API for functionality, reliability, performance, to security. Therefore, understanding and implementing effective API mocking strategies can significantly streamline the API design and development process. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/oauth-20@TLuNtQ6HKYQXmglyVk8-t.md b/src/data/roadmaps/api/content/oauth-20@TLuNtQ6HKYQXmglyVk8-t.md new file mode 100644 index 000000000..f782c01e1 --- /dev/null +++ b/src/data/roadmaps/api/content/oauth-20@TLuNtQ6HKYQXmglyVk8-t.md @@ -0,0 +1,3 @@ +# OAuth 2.0 + +OAuth 2.0 is an authorization framework that allows applications to obtain limited access to user accounts on an HTTP service, such as Facebook, GitHub, DigitalOcean, and others. It works by delegating user authentication to the service that hosts the user account and authorizing third-party applications to access the user account. OAuth 2.0 defines four roles: resource owner, client, resource server and authorization server. With regards to API design, OAuth 2.0 can be used to protect API endpoints by ensuring that the client applications having valid access tokens can only interact with the API. It provides detailed workflow processes and a set of protocols for the client application to get authorization to access resources. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/pagination@pgJDzP3pJjhjr5wTRtPJO.md b/src/data/roadmaps/api/content/pagination@pgJDzP3pJjhjr5wTRtPJO.md new file mode 100644 index 000000000..53be576fc --- /dev/null +++ b/src/data/roadmaps/api/content/pagination@pgJDzP3pJjhjr5wTRtPJO.md @@ -0,0 +1,3 @@ +# Pagination in API Design + +Pagination is a crucial aspect of API design, providing a systematic approach to handling large amounts of data in a manageable way. Instead of returning all data in a single response, which can be overwhelming and inefficient, APIs implement pagination to deliver this data in smaller, more convenient parcels. This allows client applications to fetch data incremently and only as needed, greatly enhancing performance and usability. The design and implementation of pagination can vary, with different strategies such as limit-offset, cursor-based, or time-based pagination, each with its own set of advantages and limitations. An effective API design should carefully consider pagination style, striving for a balance between ease of use, efficiency, and scalability. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/pci-dss@J0enF8UTVzY3H4n3pbPIF.md b/src/data/roadmaps/api/content/pci-dss@J0enF8UTVzY3H4n3pbPIF.md new file mode 100644 index 000000000..ec9c1a7bc --- /dev/null +++ b/src/data/roadmaps/api/content/pci-dss@J0enF8UTVzY3H4n3pbPIF.md @@ -0,0 +1,3 @@ +# PCI DSS in API Design + +Payment Card Industry Data Security Standard (PCI DSS) is a widely accepted set of policies and procedures intended to optimize the security of credit, debit and cash card transactions and protect cardholders against misuse of their personal information. In terms of API Design, building APIs in compliance with PCI DSS is crucial when processing, storing or transmitting credit card information. By adhering to these standards, not only can developers ensure safe and secure API endpoints but also build trust among users by safeguarding their sensitive financial data. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/performance-metrics@nQpczZUcn-TvrfT80dv0Q.md b/src/data/roadmaps/api/content/performance-metrics@nQpczZUcn-TvrfT80dv0Q.md new file mode 100644 index 000000000..7181e72c3 --- /dev/null +++ b/src/data/roadmaps/api/content/performance-metrics@nQpczZUcn-TvrfT80dv0Q.md @@ -0,0 +1,3 @@ +# Performance Metrics in API Design + +API Design performance metrics play a critical role in ensuring APIs are efficient, effective, and absolutely fit for their intended purpose. The performance of an API can profoundly impact the user experience and overall system performance. Therefore, it is crucial to define and monitor a set of performance metrics. These may include response times, throughput, error rates, and others that measure system health and resource utilization. By prioritizing these metrics in the context of API Design, developers can create APIs that not only meet functional requirements but also deliver desired performance levels. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/performance-testing@DQcAV59vr1-ZRnMfbLXpu.md b/src/data/roadmaps/api/content/performance-testing@DQcAV59vr1-ZRnMfbLXpu.md new file mode 100644 index 000000000..186ee53d0 --- /dev/null +++ b/src/data/roadmaps/api/content/performance-testing@DQcAV59vr1-ZRnMfbLXpu.md @@ -0,0 +1,3 @@ +# Performance Testing in API Design + +Performance Testing in API design refers to the practice of evaluating and ensuring that an API operates reliably and efficiently under varying workloads. Properly conducted performance testing can verify an API's speed, response time, reliability, and scalability. As an integral aspect of API design, it checks if API's are effectively meeting expectations for system functionality and demonstrates the potential areas of optimization. Performance testing is essential in maintaining high standards of user experience by preventing unexpected failures, and optimizing API consumer satisfaction. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/pii@mXCKtLUvwVJkHrpHzOecq.md b/src/data/roadmaps/api/content/pii@mXCKtLUvwVJkHrpHzOecq.md new file mode 100644 index 000000000..bf988f545 --- /dev/null +++ b/src/data/roadmaps/api/content/pii@mXCKtLUvwVJkHrpHzOecq.md @@ -0,0 +1,3 @@ +# PII under Standards and Compliance + +Personal Identifiable Information (PII) under Standards and Compliance is a crucial aspect of API Design. It refers to the secure handling and transmission of personal data such as names, addresses, and credit card numbers, which APIs often deal with. In this context, APIs must be built under strict compliance with standards such as GDPR, HIPAA or PCI DSS, which regulate the protection of personal data. These standards ensure that personal data is not misused and that user privacy is respected. Any violations can lead to hefty fines and damage to the company's reputation. Understanding PII and designing APIs in accordance with applicable regulations is vital for a robust, secure, and compliant API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/postman@KQAus72RGqx5f-3-YeJby.md b/src/data/roadmaps/api/content/postman@KQAus72RGqx5f-3-YeJby.md new file mode 100644 index 000000000..9df6bb379 --- /dev/null +++ b/src/data/roadmaps/api/content/postman@KQAus72RGqx5f-3-YeJby.md @@ -0,0 +1,3 @@ +# Postman in API Design + +Postman is a popular tool in web development for designing, testing, and managing APIs. As a collaborative platform, it simplifies each step of the API lifecycle and streamlines collaboration across teams. In context of API design, it can be employed to design and mock APIs, automate testing, and observe responses in a user-friendly interface. API endpoints can be organized into collections also in Postman for a well-structured and organized API design process. Ultimately, its user-friendly interface and comprehensive features position Postman as an indispensable tool in the realm of API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/profiling-and-monitoring@-qdwBg7HvwlbLy3IKCRij.md b/src/data/roadmaps/api/content/profiling-and-monitoring@-qdwBg7HvwlbLy3IKCRij.md new file mode 100644 index 000000000..cb0b14c6e --- /dev/null +++ b/src/data/roadmaps/api/content/profiling-and-monitoring@-qdwBg7HvwlbLy3IKCRij.md @@ -0,0 +1,3 @@ +# Profiling and Monitoring in API Design + +Profiling and monitoring are critical aspects of API design and implementation. Profiling, in this context, refers to the process of analyzing the behavior of your API in order to understand various performance metrics including response times, request rates, error rates, and the overall health and functionality of your API. On the other hand, monitoring is the ongoing process of checking the status of your API to ensure it's functioning as expected while also providing an early warning system for potential issues and improvements. Together, profiling and monitoring your API can lead to a more reliable, efficient, and high-performing service. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/rabbit-mq@H22jAI2W5QLL-b1rq-c56.md b/src/data/roadmaps/api/content/rabbit-mq@H22jAI2W5QLL-b1rq-c56.md new file mode 100644 index 000000000..b3b7e1027 --- /dev/null +++ b/src/data/roadmaps/api/content/rabbit-mq@H22jAI2W5QLL-b1rq-c56.md @@ -0,0 +1,5 @@ +# RabbitMQ in API Design + +RabbitMQ is an open-source message-broker software/system that plays a crucial role in API design, specifically in facilitating effective and efficient inter-process communication. It implements the Advanced Message Queuing Protocol (AMQP) to enable secure and reliable data transmission in various formats such as text, binary, or serialized objects. + +In API design, RabbitMQ comes in handy in decoupling application processes for scalability and robustness, whilst ensuring that data delivery occurs safely and seamlessly. It introduces queuing as a way of handling multiple users or service calls at once hence enhancing responsiveness and performance of APIs. Its queue system elegantly digests API request loads, allowing services to evenly process data while preventing overloading. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/rate-limiting--throttling@tPVtRV818D8zAAuNbqPNa.md b/src/data/roadmaps/api/content/rate-limiting--throttling@tPVtRV818D8zAAuNbqPNa.md new file mode 100644 index 000000000..81a16880e --- /dev/null +++ b/src/data/roadmaps/api/content/rate-limiting--throttling@tPVtRV818D8zAAuNbqPNa.md @@ -0,0 +1,3 @@ +# Rate Limiting / Throttling in API Design + +Rate Limiting, often referred to as Throttling, is a fundamental aspect of API Design aimed at controlling the number of requests a client can make to an API within a specified timeframe. This technique ensures fair usage, enhances security, prevents server overload, and allows an even distribution of resources. It also minimizes the risks associated with abusive behaviors or DDoS attacks. Effective rate limiting strategy involves defining the limits based on the API's capacity and clients' reasonable needs, with flexibility to tweak these limits when necessary. Understanding rate limiting and its significance is crucial for building resilient, secure, and scalable API platforms. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/readmecom@LxWHkhlikUaMT2G8YmVDQ.md b/src/data/roadmaps/api/content/readmecom@LxWHkhlikUaMT2G8YmVDQ.md new file mode 100644 index 000000000..771854f05 --- /dev/null +++ b/src/data/roadmaps/api/content/readmecom@LxWHkhlikUaMT2G8YmVDQ.md @@ -0,0 +1,3 @@ +# Readme.com in the Context of API Design + +Readme.com is an invaluable tool in the realm of API Design, renowned for providing a collaborative platform for creating beautiful, dynamic and intuitive documentation. It's a tool which aids developers in outlining clear, comprehensive documentation for their API interfaces. The API documentation created with Readme.com is not just about the presentation of information, but enhances the reader's understanding by making it interactive. This interactive approach encourages practical learning and offers insights into how the API will behave under different circumstances. With Readme.com, developers can create a user-focused documentation environment that streamlines the learning process and makes their APIs easier to consume and implement. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/real-time-apis@JE12g5cqnwmgeTle14Vxw.md b/src/data/roadmaps/api/content/real-time-apis@JE12g5cqnwmgeTle14Vxw.md new file mode 100644 index 000000000..be0a653f1 --- /dev/null +++ b/src/data/roadmaps/api/content/real-time-apis@JE12g5cqnwmgeTle14Vxw.md @@ -0,0 +1,3 @@ +# Real-time APIs + +In the realm of API Design, Real-time APIs hold significant value as they provide immediate access to the latest data as soon as they become available. Rather than relying on periodic polling for updates, Real-time APIs maintain an open connection between the client and the server which allows immediate, bi-directional data flow. These APIs are commonly used in applications which require real-time information such as live chat programs, financial trading platforms or online multiplayer games. Designing such APIs requires careful consideration of factors such as connection management, data consistency, and efficient handling of high volume data streams. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/reate-limiting@O7wjldZ3yTA2s_F-UnJw_.md b/src/data/roadmaps/api/content/reate-limiting@O7wjldZ3yTA2s_F-UnJw_.md new file mode 100644 index 000000000..530a97e32 --- /dev/null +++ b/src/data/roadmaps/api/content/reate-limiting@O7wjldZ3yTA2s_F-UnJw_.md @@ -0,0 +1,3 @@ +# Rate Limiting in API Design + +Rate Limiting is a critical aspect of API Design that dictates the number of API calls a client can make within a specified timeframe. This helps in managing resource allocation, preventing abuse of the API, and maintaining the overall health of the API system. Proper rate limiting measures should be in place to ensure the API's stability, thereby delivering a consistent and reliable service to all consumers. It works primarily by setting a limit on the frequency of client requests, thereby preventing individual users from overloading the system. It is crucial to design and implement rate limiting carefully for maintaining API availability and performance. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/rest-principles@9WI_z34jIFXwoUQuChyRU.md b/src/data/roadmaps/api/content/rest-principles@9WI_z34jIFXwoUQuChyRU.md new file mode 100644 index 000000000..9c634d176 --- /dev/null +++ b/src/data/roadmaps/api/content/rest-principles@9WI_z34jIFXwoUQuChyRU.md @@ -0,0 +1,3 @@ +# REST Principles in API Design + +REST (Representational State Transfer) is an important architectural style used in API design. It defines a set of rules and conventions through which systems communicate over a network. Key characteristics of REST include statelessness, client-server communication, cacheability, and a uniform interface. Understanding and applying these principles properly can help in designing robust, scalable, and high-performance APIs. REST principles revolve around resources and their manipulation to achieve desired outcomes. By following these principles, developers can ensure that their API design is in line with web standards, thus improving interoperability across different systems. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/restful-apis@BvwdASMvuNQ9DNgzdSZ4o.md b/src/data/roadmaps/api/content/restful-apis@BvwdASMvuNQ9DNgzdSZ4o.md new file mode 100644 index 000000000..8d65c4b42 --- /dev/null +++ b/src/data/roadmaps/api/content/restful-apis@BvwdASMvuNQ9DNgzdSZ4o.md @@ -0,0 +1,3 @@ +# RESTful APIs + +RESTful APIs, or Representational State Transfer APIs, are a set of conventions for designing networked applications. They utilize HTTP methods to read, update and delete data. They offer a simple and standardized way to build web services that can be easily consumed by different clients. The key principles of a RESTful API include stateless client-server communication, cacheable data, and a uniform interface, making the API easy to understand, flexible, and scalable. Moreover, it relies heavily on the use of resources and their representations, making it a popular choice in API design due to its performance, scalability, simplicity, and reliability. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/rfc-7807----problem-details-for-apis@5CxU3inGcSHp-TDg3BQiY.md b/src/data/roadmaps/api/content/rfc-7807----problem-details-for-apis@5CxU3inGcSHp-TDg3BQiY.md new file mode 100644 index 000000000..ff44742d9 --- /dev/null +++ b/src/data/roadmaps/api/content/rfc-7807----problem-details-for-apis@5CxU3inGcSHp-TDg3BQiY.md @@ -0,0 +1,3 @@ +# RFC 7807 - Problem Details for HTTP APIs in Error Handling + +The practice of API Design includes a significant focus on handling errors effectively and transparently. Among the widespread standards being adopted, the RFC 7807 or Problem Details for HTTP APIs plays a crucial role. This specification provides a standardized format for sending problem or error details from an HTTP API so developers engaging with the API do not need to parse non-standard error messages and can anticipate the structure of potential errors. In essence, RFC 7807 improves the usability and comprehension of your API, providing a better developer experience and encouraging the efficient use of your API. Implementing it paves the way to robust and accountable systems, where issues can be traced, identified, and solved more conveniently. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/role-based-access-control-rbac@wFsbmMi5Ey9UyDADdbdPW.md b/src/data/roadmaps/api/content/role-based-access-control-rbac@wFsbmMi5Ey9UyDADdbdPW.md new file mode 100644 index 000000000..ee48cf1ce --- /dev/null +++ b/src/data/roadmaps/api/content/role-based-access-control-rbac@wFsbmMi5Ey9UyDADdbdPW.md @@ -0,0 +1,3 @@ +# Role Based Access Control (RBAC) in API Design + +Role-Based Access Control (RBAC) is a method of managing authorization in API design that assigns system access to users based on their role within an organization. RBAC is crucial in controlling which endpoints a user can call, and what operations they are allowed to execute. In the context of API design, RBAC ensures appropriate levels of access for different types of users to guarantee data security and integrity. It simplifies the process of security administration by assigning privileges based on a user's job function, rather than on an individual basis. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/server-sent-events@iNsXTtcIHsI_i-mCfjGYn.md b/src/data/roadmaps/api/content/server-sent-events@iNsXTtcIHsI_i-mCfjGYn.md new file mode 100644 index 000000000..35e09f651 --- /dev/null +++ b/src/data/roadmaps/api/content/server-sent-events@iNsXTtcIHsI_i-mCfjGYn.md @@ -0,0 +1,3 @@ +# Server Sent Events under Real-time APIs + +Server-Sent Events (SSE) represent an explicit concept in the design of Real-time APIs. Unlike traditional approaches where a client sends a request and awaits a response from the server, SSE enables a server to push data to clients whenever a particular event takes place. SSE is especially fundamental in API design when it comes to the development of applications where real-time data is essential, such as live news updates, real-time gaming, or live-streaming services. Designing APIs with the SSE approach ensures a more dynamic and responsive user experience. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/session-based-auth@eQWoy4CpYP3TJL2bbhPB_.md b/src/data/roadmaps/api/content/session-based-auth@eQWoy4CpYP3TJL2bbhPB_.md new file mode 100644 index 000000000..407e72e29 --- /dev/null +++ b/src/data/roadmaps/api/content/session-based-auth@eQWoy4CpYP3TJL2bbhPB_.md @@ -0,0 +1,7 @@ +# Session Based Authentication in API Design + +Application Programming Interfaces (APIs) are critical for building software applications. Among several key considerations during API design, one is deciding how to implement authentication and security. Session Based Authentication is one popular way to apply security in API design. + +This method revolves around the server creating a session for the user after they successfully log in, associating it with a session identifier. This Session ID is then stored client-side within a cookie. On subsequent requests, the server validates the Session ID before processing the API call. The server will destroy the session after the user logs out, thereby invalidating the Session ID. + +Understanding Session Based Authentication is crucial for secure API design, especially in scenarios where security is a top priority or in legacy systems where this method is prevalent. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/simple-json-apis@TVR-SkErlOHbDKLBGfxep.md b/src/data/roadmaps/api/content/simple-json-apis@TVR-SkErlOHbDKLBGfxep.md new file mode 100644 index 000000000..26e8af4f4 --- /dev/null +++ b/src/data/roadmaps/api/content/simple-json-apis@TVR-SkErlOHbDKLBGfxep.md @@ -0,0 +1,3 @@ +# Simple JSON APIs + +Simple JSON (JavaScript Object Notation) APIs are a popular form of API or "Application Programming Interface" which utilise JSON to exchange data between servers and web applications. This method has gained prominence mainly for its simplicity, light weight, and easy readability. In the context of API design, a well-structured JSON API allows developers to efficiently interact with the backend and retrieve only the data they need in a consistent and comprehensible manner. From reducing redundant data to enabling quick parsing, Simple JSON APIs provide numerous benefits to improve the overall performance of applications. Designing a good JSON API requires careful planning, sound knowledge of HTTP methods, endpoints, error handling mechanisms, and most importantly, a clear understanding of the application's data requirements. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/soap-apis@Wwd-0PjrtViMFWxRGaQey.md b/src/data/roadmaps/api/content/soap-apis@Wwd-0PjrtViMFWxRGaQey.md new file mode 100644 index 000000000..1ae69d782 --- /dev/null +++ b/src/data/roadmaps/api/content/soap-apis@Wwd-0PjrtViMFWxRGaQey.md @@ -0,0 +1,3 @@ +# SOAP APIs + +SOAP (Simple Object Access Protocol) APIs are a standard communication protocol system that permits programs that run on different operating systems (like Linux and Windows) to communicate using Hypertext Transfer Protocol (HTTP) and its Extensible Markup Language (XML). In the context of API Design, SOAP APIs offer a robust and well-defined process for interaction between various software applications, mostly over a network. They are highly extensible, versatile and support a wide range of communications protocols. Despite being more complex compared to other API types like REST, SOAP APIs ensure high reliability and security, making them the choice for certain business-focused, high-transaction applications. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/standards-and-compliance@yvdfoly5WHHTq2Puss355.md b/src/data/roadmaps/api/content/standards-and-compliance@yvdfoly5WHHTq2Puss355.md new file mode 100644 index 000000000..5bad65a9f --- /dev/null +++ b/src/data/roadmaps/api/content/standards-and-compliance@yvdfoly5WHHTq2Puss355.md @@ -0,0 +1,7 @@ +# Standards and Compliance in API Design + +When designing APIs, it's crucial to consider the concept of standards and compliance. Standards represent the set of rules and best practices that guide developers to create well-structured and easily maintainable APIs. They can range from the proper structure of the endpoints, the standardization of error responses, to naming conventions, and the usage of HTTP verbs. + +Compliance on the other hand, emphasizes on meeting protocol requirements or standards such as REST or SOAP. Furthermore, operating within regulated industries can also necessitate certain compliance measures like GDPR, HIPAA and others. Compliance in API Design ensures interoperability and safety of data transmission between systems. + +In essence, Standards and Compliance in API Design contributes towards building more secure, robust, and efficient APIs that are user-friendly and universally understandable. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/stoplight@OpS2NX1lPTOtfjV1wKtC4.md b/src/data/roadmaps/api/content/stoplight@OpS2NX1lPTOtfjV1wKtC4.md new file mode 100644 index 000000000..81b1835d8 --- /dev/null +++ b/src/data/roadmaps/api/content/stoplight@OpS2NX1lPTOtfjV1wKtC4.md @@ -0,0 +1,3 @@ +# Stoplight API Design + +Stoplight is an advanced tool that offers a comprehensive platform for technical teams to handle all aspects of API design. Leveraging Stoplight, teams can design, document and develop APIs in a more collaborative and streamlined manner. It uses an OpenAPI specification and allows users to design APIs visually, making API development easier. With its ability to auto-generate API documentation, performing API mock testing, and providing API management features, Stoplight plays a crucial role in adopting a design-first approach in API development. By using Stoplight, APIs can be designed to be easy-to-use, scalable, and robust from the outset, which ultimately improves the overall development process and quality of the APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/swagger--open-api@5RY7AlfRQydjxWK65Z4cv.md b/src/data/roadmaps/api/content/swagger--open-api@5RY7AlfRQydjxWK65Z4cv.md new file mode 100644 index 000000000..09e64512c --- /dev/null +++ b/src/data/roadmaps/api/content/swagger--open-api@5RY7AlfRQydjxWK65Z4cv.md @@ -0,0 +1,3 @@ +# Swagger / Open API + +Swagger, also known as OpenAPI, is a set of tools specifically used for designing, building, and documenting RESTful Web services. API developers heavily rely on it due to its incredible feature for designing APIs with a clear and easy-to-understand approach. By utilizing the OpenAPI Specification (OAS), developers can accurately define a RESTful API that can easily be used across various programming languages. This powerful universal language is a key component for effective and efficient API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/synchronous-vs-asynchronous-apis@--mmTKhG58_elbUqyn90G.md b/src/data/roadmaps/api/content/synchronous-vs-asynchronous-apis@--mmTKhG58_elbUqyn90G.md new file mode 100644 index 000000000..620ab9831 --- /dev/null +++ b/src/data/roadmaps/api/content/synchronous-vs-asynchronous-apis@--mmTKhG58_elbUqyn90G.md @@ -0,0 +1,5 @@ +# Synchronous vs Asynchronous APIs + +When designing APIs, one critical decision is whether to create a synchronous or asynchronous API. Synchronous APIs are those that hold a connection open and wait for a response before moving on, hence operating in a sequential manner. This can lead to efficient, simple-to-understand coding but can pose performance issues when dealing with long tasks since the caller has to wait until the process finishes. + +On the other hand, Asynchronous APIs do not wait for a response before moving on to the next task, allowing multiple operations to be executed simultaneously. This can result in improved performance and responsiveness especially in applications that need to handle multiple requests concurrently. However, coding for asynchronous APIs can be complex due to issues such as race conditions and callbacks. Understanding the differences between these two types of API design is crucial for creating efficient and effective APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/token-based-auth@QTH7sy9uQZWl6ieBz7erY.md b/src/data/roadmaps/api/content/token-based-auth@QTH7sy9uQZWl6ieBz7erY.md new file mode 100644 index 000000000..3b27db02d --- /dev/null +++ b/src/data/roadmaps/api/content/token-based-auth@QTH7sy9uQZWl6ieBz7erY.md @@ -0,0 +1,3 @@ +# Token Based Auth in API Design + +Token-based authentication is a crucial aspect of API design. It involves providing the user with a token that validates their identity after they have successfully logged in. Once the token is obtained, users can use it to access resources and services provided by the API. This token is usually passed in the headers of subsequent HTTP requests done by the client. One key advantage of token-based auth is that tokens can be created and checked by the server without storing them persistently, which can help to scale applications more easily. This authentication method enhances the security and scalability of web applications and it is mainly used in modern API strategies, including RESTful APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/understand-tcp--ip@KG3wO86F8Of27fU7QRcsn.md b/src/data/roadmaps/api/content/understand-tcp--ip@KG3wO86F8Of27fU7QRcsn.md new file mode 100644 index 000000000..90fc79f7f --- /dev/null +++ b/src/data/roadmaps/api/content/understand-tcp--ip@KG3wO86F8Of27fU7QRcsn.md @@ -0,0 +1,3 @@ +# Understand TCP / IP under Learn the Basics + +When designing APIs, an essential building block is the understanding of TCP/IP. TCP/IP, standing for Transmission Control Protocol/Internet Protocol, is the suite of communications protocols used to connect hosts on the Internet. It provides ordered, error-checked delivery of streams of bytes from a program on one computer to another program on another computer. If you want to understand how APIs communicate over networks, knowing the fundamental working of TCP/IP is indispensable. Fully appreciating this topic will strengthen your grasp on API design and help you make more informed decisions when creating APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/unit-testing@JvmW78cDm84GNhq8VEYZp.md b/src/data/roadmaps/api/content/unit-testing@JvmW78cDm84GNhq8VEYZp.md new file mode 100644 index 000000000..0dce883ff --- /dev/null +++ b/src/data/roadmaps/api/content/unit-testing@JvmW78cDm84GNhq8VEYZp.md @@ -0,0 +1,3 @@ +# Unit Testing in API Design + +Unit Testing, in the context of API design, refers to the process of testing the individual components or functions of an API independently to ensure that each part is working correctly. It is typically performed at the development stage. The chief goal of Unit Testing is to isolate each component and validate its correct operation, thereby increasing confidence in the stability of the API as a whole. It lays a solid foundation for integration testing and ultimately leads to reliable, bug-free APIs. Whether your API is RESTful, SOAP, or GraphQL, unit testing is a critical step in API design and development. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/uri-design@b3qRTLwCC_9uDoPGrd9Bu.md b/src/data/roadmaps/api/content/uri-design@b3qRTLwCC_9uDoPGrd9Bu.md new file mode 100644 index 000000000..e3313b152 --- /dev/null +++ b/src/data/roadmaps/api/content/uri-design@b3qRTLwCC_9uDoPGrd9Bu.md @@ -0,0 +1,3 @@ +# URI Design in API + +URI (Uniform Resource Identifier) is a string of characters used to identify a name or a resource on the Internet. Designing URIs carefully is a crucial part of creating a smooth API interface that is easy to understand, remember and use. Good URI design ensures that related resources are grouped together in a logical manner and can greatly impact the usability and maintainability of an API. It involves crafting standardised, intuitive HTTP paths that take advantage of the hierarchical nature of URLs to provide a better structure to the API. This hierarchy can then be used to expand the API over time without breaking existing clients' functionality. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/url-query--path-parameters@P-rGIk50Bg7nFmWieAW07.md b/src/data/roadmaps/api/content/url-query--path-parameters@P-rGIk50Bg7nFmWieAW07.md new file mode 100644 index 000000000..140232134 --- /dev/null +++ b/src/data/roadmaps/api/content/url-query--path-parameters@P-rGIk50Bg7nFmWieAW07.md @@ -0,0 +1,3 @@ +# URL, Query & Path Parameters + +When designing APIs, an integral part involves dealing with uniform resource locators (URLs), query parameters, and path parameters. These components play crucial parts in how the API sends and retrieves data. The URL forms the basis of the API given that it identifies the resource on the server. Query parameters are used to filter specific results, sorting or showing specific data fields. On the other hand, Path parameters serve as placeholders for variable data that will be input into the URL, allowing us to customize the data response. Understanding the usage of URL, query, and path parameters is of utmost importance for creating efficient, scalable and user-friendly APIs. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/versioning-strategies@itILK2SXvLvAjk1Kul7EK.md b/src/data/roadmaps/api/content/versioning-strategies@itILK2SXvLvAjk1Kul7EK.md new file mode 100644 index 000000000..e6cd2bdc2 --- /dev/null +++ b/src/data/roadmaps/api/content/versioning-strategies@itILK2SXvLvAjk1Kul7EK.md @@ -0,0 +1,3 @@ +# Versioning Strategies in API Design + +API Versioning is a critical component of API Design and Management. As the APIs evolve over time to meet the new business requirements and functionality enhancements, it is crucial to manage the changes in a way that doesn't break the existing client applications. This calls for effective versioning strategies in API design. There are different versioning strategies like URI versioning, Request Header versioning, and Media Type versioning which are adopted based on the ease of implementation, client compatibility, and accessibility. Understanding each strategy and its pros and cons can lead to better API Design and maintainability. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/web-sockets@UQ8N7gcVpRLAYXgUNHBt5.md b/src/data/roadmaps/api/content/web-sockets@UQ8N7gcVpRLAYXgUNHBt5.md new file mode 100644 index 000000000..174c7195d --- /dev/null +++ b/src/data/roadmaps/api/content/web-sockets@UQ8N7gcVpRLAYXgUNHBt5.md @@ -0,0 +1,3 @@ +# Web Sockets in API Design + +Web Sockets provide a long-lived connection between a client and a server over which messages can be sent bi-directionally, in real-time. They play a crucial role in creating real-time APIs by offering a faster and more efficient communication method over the traditional HTTP. In the context of API Design, Web Sockets are used for developing APIs that require real-time data transfer, such as chat applications, live sports updates, and real-time analytics. This paradigm shift from traditional HTTP-based API design to Web Socket-based API design helps create APIs that are more responsive, dynamic, and efficient in handling real-time data. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/webhooks-vs-polling@75NVxS0iwoQXxOHCkWQxH.md b/src/data/roadmaps/api/content/webhooks-vs-polling@75NVxS0iwoQXxOHCkWQxH.md new file mode 100644 index 000000000..b1cdb89d0 --- /dev/null +++ b/src/data/roadmaps/api/content/webhooks-vs-polling@75NVxS0iwoQXxOHCkWQxH.md @@ -0,0 +1,3 @@ +# Webhooks vs Polling in API Design + +When it comes to managing server communication and data exchange in API design, two commonly used methods are webhooks and polling. These two strategies handle updates and data synchronization in different ways. Polling is a technique where the client repeatedly makes a request to the server to check for updates. In this case, it's the client determining the rate of information exchange. Conversely, webhooks operate on a 'push' mechanism. The server sends updates to the client as they happen, providing real-time, efficient data synchronization. Determining which method to use often depends on the specifics of the API design requirement including the frequency of data changes, server load, and application's real-time need. \ No newline at end of file diff --git a/src/data/roadmaps/api/content/what-are-apis@r8M3quACGO2piu0u_R4hO.md b/src/data/roadmaps/api/content/what-are-apis@r8M3quACGO2piu0u_R4hO.md new file mode 100644 index 000000000..12fe3c4e4 --- /dev/null +++ b/src/data/roadmaps/api/content/what-are-apis@r8M3quACGO2piu0u_R4hO.md @@ -0,0 +1,3 @@ +# What are APIs + +APIs, or Application Programming Interfaces, provide a manner in which software applications communicate with each other. They abstract the complexity of applications to allow developers to use only the essentials of the software they are working with. They define the methods and data formats an application should use in order to perform tasks, like sending, retrieving, or modifying data. Understanding APIs is integral to mastering modern software development, primarily because they allow applications to exchange data and functionality with ease, thus enabling integration and convergence of technological services. Therefore, a solid understanding of what APIs are forms the basic cornerstone of API design. \ No newline at end of file diff --git a/src/data/roadmaps/api/faqs.astro b/src/data/roadmaps/api/faqs.astro new file mode 100644 index 000000000..e69de29bb diff --git a/src/lib/promise.ts b/src/lib/promise.ts new file mode 100644 index 000000000..4165cc018 --- /dev/null +++ b/src/lib/promise.ts @@ -0,0 +1,47 @@ +type PromiseInput = Array | (() => Promise)>; + +/** + * Run promises in parallel with a variable batch size. + * + * @category Promise + * @param promises Array of promises to run in parallel + * @param batchSize Number of promises to run concurrently + * @param ignoreErrors Whether to ignore errors and continue running promises even if some fail + * @returns Promise that resolves when all promises are settled + */ +export async function runPromisesInBatchSequentially( + promises: PromiseInput, + batchSize: number, + ignoreErrors = false, +): Promise { + const results: T[] = []; + + for (let i = 0; i < promises.length; i += batchSize) { + const batch = promises.slice(i, i + batchSize); + await Promise.all( + batch.map((promise) => { + if (promise instanceof Promise) { + return promise + .then((result) => results.push(result)) + .catch((error) => { + if (!ignoreErrors) { + throw error; + } + return null; + }); + } else { + return promise() + .then((result) => results.push(result)) + .catch((error) => { + if (!ignoreErrors) { + throw error; + } + return null; + }); + } + }), + ); + } + + return results; +} diff --git a/src/lib/roadmap-topic.ts b/src/lib/roadmap-topic.ts index 034a1c551..2f8b90022 100644 --- a/src/lib/roadmap-topic.ts +++ b/src/lib/roadmap-topic.ts @@ -7,12 +7,18 @@ import type { RoadmapFrontmatter } from './roadmap'; // -> /src/data/roadmaps/vue/content/102-ecosystem // /vue/ecosystem function generateTopicUrl(filePath: string) { - return filePath + let result = filePath .replace('/src/data/roadmaps/', '/') // Remove the base `/src/data/roadmaps` from path - .replace('/content', '') // Remove the `/[roadmapId]/content` - .replace(/\/\d+-/g, '/') // Remove ordering info `/101-ecosystem` + .replace('/content', ''); // Remove the `/[roadmapId]/content` + + if (result.match(/\/\d+-/g)) { + result = result.replace(/\/\d+-/g, '/'); // Remove ordering info `/101-ecosystem` + } + result = result .replace(/\/index\.md$/, '') // Make the `/index.md` to become the parent folder only .replace(/\.md$/, ''); // Remove `.md` from the end of file + + return result; } export interface RoadmapTopicFileType { @@ -34,7 +40,7 @@ export async function getRoadmapTopicFiles(): Promise< '/src/data/roadmaps/*/content/**/*.md', { eager: true, - } + }, ); const mapping: Record = {}; diff --git a/src/lib/roadmap.ts b/src/lib/roadmap.ts index 953f0e83e..bac7dfefc 100644 --- a/src/lib/roadmap.ts +++ b/src/lib/roadmap.ts @@ -11,6 +11,8 @@ export function resourceTitleFromId(id: string): string { .join(' '); } +export type AllowedRoadmapRenderer = 'balsamiq' | 'editor'; + export interface RoadmapFrontmatter { pdfUrl: string; order: number; @@ -53,6 +55,7 @@ export interface RoadmapFrontmatter { changefreq: string; }; tags: string[]; + renderer?: AllowedRoadmapRenderer; } export type RoadmapFileType = MarkdownFileType & { diff --git a/src/lib/slugger.ts b/src/lib/slugger.ts new file mode 100644 index 000000000..6932f46ed --- /dev/null +++ b/src/lib/slugger.ts @@ -0,0 +1,8 @@ +const regex = /[^A-Za-z0-9_\- ]/g; +export function slugify(value: string): string { + if (typeof value !== 'string') { + return ''; + } + + return value.toLowerCase().replace(regex, '').trim().replace(/ /g, '-'); +} diff --git a/src/pages/[roadmapId]/index.astro b/src/pages/[roadmapId]/index.astro index c0e85a904..c659da8a4 100644 --- a/src/pages/[roadmapId]/index.astro +++ b/src/pages/[roadmapId]/index.astro @@ -1,4 +1,5 @@ --- +import { EditorRoadmap } from '../../components/EditorRoadmap/EditorRoadmap'; import FAQs, { type FAQType } from '../../components/FAQs/FAQs.astro'; import FrameRenderer from '../../components/FrameRenderer/FrameRenderer.astro'; import RelatedRoadmaps from '../../components/RelatedRoadmaps.astro'; @@ -113,11 +114,20 @@ const ogImageUrl = canSubmitContribution={true} /> - + {roadmapData?.renderer === 'editor' ? ( + + ) : ( + + )}
    ) } @@ -126,12 +136,13 @@ const ogImageUrl = { roadmapId === 'docker' && ( -

    +

    Roadmap owner Insight Partners is an investor in Docker.

    ) diff --git a/src/pages/[roadmapId]/svg.astro b/src/pages/[roadmapId]/svg.astro new file mode 100644 index 000000000..1d9823898 --- /dev/null +++ b/src/pages/[roadmapId]/svg.astro @@ -0,0 +1,63 @@ +--- +import { EditorRoadmap } from '../../components/EditorRoadmap/EditorRoadmap'; +import FrameRenderer from '../../components/FrameRenderer/FrameRenderer.astro'; +import SkeletonLayout from '../../layouts/SkeletonLayout.astro'; +import { getOpenGraphImageUrl } from '../../lib/open-graph'; +import { type RoadmapFrontmatter, getRoadmapIds } from '../../lib/roadmap'; + +export async function getStaticPaths() { + const roadmapIds = await getRoadmapIds(); + + return roadmapIds.map((roadmapId) => ({ + params: { roadmapId }, + })); +} + +interface Params extends Record { + roadmapId: string; +} + +const { roadmapId } = Astro.params as Params; +const roadmapFile = await import( + `../../data/roadmaps/${roadmapId}/${roadmapId}.md` +); +const roadmapData = roadmapFile.frontmatter as RoadmapFrontmatter; + +const ogImageUrl = + roadmapData?.seo?.ogImageUrl || + getOpenGraphImageUrl({ + group: 'roadmap', + resourceId: roadmapId, + }); +--- + + +
    + { + roadmapData?.renderer === 'editor' ? ( + + ) : ( + + ) + } +
    +
    diff --git a/src/pages/get-started.astro b/src/pages/get-started.astro index 3ae1a3842..bc6d06305 100644 --- a/src/pages/get-started.astro +++ b/src/pages/get-started.astro @@ -28,7 +28,7 @@ import { PenSquare, Component, Waypoints, - CheckSquare, + CheckSquare, Braces, } from 'lucide-react'; import { SectionBadge } from '../components/GetStarted/SectionBadge'; import { TipItem } from '../components/GetStarted/TipItem'; @@ -159,17 +159,15 @@ import { TipItem } from '../components/GetStarted/TipItem'; /> @@ -216,12 +214,21 @@ import { TipItem } from '../components/GetStarted/TipItem'; title='Are you a Backend Developer?' description='Explore the general backend roadmap or dive into a specific technology like Node.js, Python, Java etc' > - +
    + + + +
    ({ id: bestPractice.id,