├── .dockerignore ├── .github └── workflows │ └── prod.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── README.md ├── build.rs ├── docker-compose.yml ├── migrations ├── 20230418001048_tables.down.sql └── 20230418001048_tables.up.sql ├── sqlx-data.json └── src └── main.rs /.dockerignore: -------------------------------------------------------------------------------- 1 | /target 2 | .git 3 | .gitignore -------------------------------------------------------------------------------- /.github/workflows/prod.yml: -------------------------------------------------------------------------------- 1 | name: Build, Test and Deploy to Prod 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | 8 | env: 9 | SQLX_OFFLINE: true 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Checkout code 17 | uses: actions/checkout@v2 18 | 19 | - name: Cache dependencies 20 | uses: actions/cache@v3 21 | with: 22 | path: | 23 | ~/.cargo 24 | target/ 25 | key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} 26 | restore-keys: ${{ runner.os }}-cargo- 27 | 28 | - name: Install Rust 29 | uses: actions-rs/toolchain@v1 30 | with: 31 | profile: minimal 32 | toolchain: stable 33 | 34 | - name: Build and test code 35 | run: | 36 | cargo build --verbose 37 | cargo test --verbose 38 | 39 | - name: Set up Docker Buildx 40 | uses: docker/setup-buildx-action@v2 41 | 42 | - name: Log in to Docker Hub 43 | uses: docker/login-action@v2 44 | with: 45 | username: ${{ secrets.DOCKER_USERNAME }} 46 | password: ${{ secrets.DOCKER_PASSWORD }} 47 | 48 | - name: Build and push Docker images 49 | uses: docker/bake-action@v2.3.0 50 | with: 51 | push: true 52 | set: | 53 | *.cache-from=type=gha 54 | *.cache-to=type=gha,mode=max 55 | 56 | deploy: 57 | needs: build 58 | runs-on: ubuntu-latest 59 | 60 | steps: 61 | - name: Checkout code 62 | uses: actions/checkout@v2 63 | 64 | - name: Log in to Docker Hub 65 | uses: docker/login-action@v1 66 | with: 67 | username: ${{ secrets.DOCKER_USERNAME }} 68 | password: ${{ secrets.DOCKER_PASSWORD }} 69 | 70 | - name: Install sshpass 71 | run: sudo apt-get install sshpass 72 | 73 | - name: Copy docker-compose.yml to droplet 74 | run: sshpass -v -p ${{ secrets.DROPLET_PASSWORD }} scp -o StrictHostKeyChecking=no docker-compose.yml root@${{ vars.DROPLET_IP }}:~ 75 | 76 | - name: Deploy 77 | uses: appleboy/ssh-action@master 78 | with: 79 | host: ${{ vars.DROPLET_IP }} 80 | username: root 81 | password: ${{ secrets.DROPLET_PASSWORD }} 82 | script: | 83 | cd ~ 84 | export POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD }} 85 | docker-compose down 86 | docker-compose pull 87 | docker-compose up -d -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .env 3 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.20.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "ahash" 22 | version = "0.7.6" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 25 | dependencies = [ 26 | "getrandom", 27 | "once_cell", 28 | "version_check", 29 | ] 30 | 31 | [[package]] 32 | name = "ahash" 33 | version = "0.8.3" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" 36 | dependencies = [ 37 | "cfg-if", 38 | "once_cell", 39 | "version_check", 40 | ] 41 | 42 | [[package]] 43 | name = "allocator-api2" 44 | version = "0.2.16" 45 | source = "registry+https://github.com/rust-lang/crates.io-index" 46 | checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" 47 | 48 | [[package]] 49 | name = "anyhow" 50 | version = "1.0.72" 51 | source = "registry+https://github.com/rust-lang/crates.io-index" 52 | checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" 53 | 54 | [[package]] 55 | name = "api-deployment-example" 56 | version = "0.1.0" 57 | dependencies = [ 58 | "anyhow", 59 | "axum", 60 | "dotenvy", 61 | "hyper", 62 | "serde", 63 | "sqlx", 64 | "tokio", 65 | "tower", 66 | ] 67 | 68 | [[package]] 69 | name = "async-trait" 70 | version = "0.1.71" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "a564d521dd56509c4c47480d00b80ee55f7e385ae48db5744c67ad50c92d2ebf" 73 | dependencies = [ 74 | "proc-macro2", 75 | "quote", 76 | "syn 2.0.26", 77 | ] 78 | 79 | [[package]] 80 | name = "atoi" 81 | version = "1.0.0" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e" 84 | dependencies = [ 85 | "num-traits", 86 | ] 87 | 88 | [[package]] 89 | name = "autocfg" 90 | version = "1.1.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 93 | 94 | [[package]] 95 | name = "axum" 96 | version = "0.6.19" 97 | source = "registry+https://github.com/rust-lang/crates.io-index" 98 | checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" 99 | dependencies = [ 100 | "async-trait", 101 | "axum-core", 102 | "bitflags", 103 | "bytes", 104 | "futures-util", 105 | "http", 106 | "http-body", 107 | "hyper", 108 | "itoa", 109 | "matchit", 110 | "memchr", 111 | "mime", 112 | "percent-encoding", 113 | "pin-project-lite", 114 | "rustversion", 115 | "serde", 116 | "serde_json", 117 | "serde_path_to_error", 118 | "serde_urlencoded", 119 | "sync_wrapper", 120 | "tokio", 121 | "tower", 122 | "tower-layer", 123 | "tower-service", 124 | ] 125 | 126 | [[package]] 127 | name = "axum-core" 128 | version = "0.3.4" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" 131 | dependencies = [ 132 | "async-trait", 133 | "bytes", 134 | "futures-util", 135 | "http", 136 | "http-body", 137 | "mime", 138 | "rustversion", 139 | "tower-layer", 140 | "tower-service", 141 | ] 142 | 143 | [[package]] 144 | name = "backtrace" 145 | version = "0.3.68" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" 148 | dependencies = [ 149 | "addr2line", 150 | "cc", 151 | "cfg-if", 152 | "libc", 153 | "miniz_oxide", 154 | "object", 155 | "rustc-demangle", 156 | ] 157 | 158 | [[package]] 159 | name = "base64" 160 | version = "0.13.1" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" 163 | 164 | [[package]] 165 | name = "base64" 166 | version = "0.21.2" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" 169 | 170 | [[package]] 171 | name = "bitflags" 172 | version = "1.3.2" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 175 | 176 | [[package]] 177 | name = "block-buffer" 178 | version = "0.10.4" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 181 | dependencies = [ 182 | "generic-array", 183 | ] 184 | 185 | [[package]] 186 | name = "bumpalo" 187 | version = "3.13.0" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" 190 | 191 | [[package]] 192 | name = "byteorder" 193 | version = "1.4.3" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 196 | 197 | [[package]] 198 | name = "bytes" 199 | version = "1.4.0" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" 202 | 203 | [[package]] 204 | name = "cc" 205 | version = "1.0.79" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 208 | 209 | [[package]] 210 | name = "cfg-if" 211 | version = "1.0.0" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 214 | 215 | [[package]] 216 | name = "cpufeatures" 217 | version = "0.2.9" 218 | source = "registry+https://github.com/rust-lang/crates.io-index" 219 | checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" 220 | dependencies = [ 221 | "libc", 222 | ] 223 | 224 | [[package]] 225 | name = "crc" 226 | version = "3.0.1" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" 229 | dependencies = [ 230 | "crc-catalog", 231 | ] 232 | 233 | [[package]] 234 | name = "crc-catalog" 235 | version = "2.2.0" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" 238 | 239 | [[package]] 240 | name = "crossbeam-queue" 241 | version = "0.3.8" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" 244 | dependencies = [ 245 | "cfg-if", 246 | "crossbeam-utils", 247 | ] 248 | 249 | [[package]] 250 | name = "crossbeam-utils" 251 | version = "0.8.16" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" 254 | dependencies = [ 255 | "cfg-if", 256 | ] 257 | 258 | [[package]] 259 | name = "crypto-common" 260 | version = "0.1.6" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 263 | dependencies = [ 264 | "generic-array", 265 | "typenum", 266 | ] 267 | 268 | [[package]] 269 | name = "digest" 270 | version = "0.10.7" 271 | source = "registry+https://github.com/rust-lang/crates.io-index" 272 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 273 | dependencies = [ 274 | "block-buffer", 275 | "crypto-common", 276 | "subtle", 277 | ] 278 | 279 | [[package]] 280 | name = "dirs" 281 | version = "4.0.0" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 284 | dependencies = [ 285 | "dirs-sys", 286 | ] 287 | 288 | [[package]] 289 | name = "dirs-sys" 290 | version = "0.3.7" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 293 | dependencies = [ 294 | "libc", 295 | "redox_users", 296 | "winapi", 297 | ] 298 | 299 | [[package]] 300 | name = "dotenvy" 301 | version = "0.15.7" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" 304 | 305 | [[package]] 306 | name = "either" 307 | version = "1.8.1" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" 310 | dependencies = [ 311 | "serde", 312 | ] 313 | 314 | [[package]] 315 | name = "event-listener" 316 | version = "2.5.3" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 319 | 320 | [[package]] 321 | name = "fnv" 322 | version = "1.0.7" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 325 | 326 | [[package]] 327 | name = "form_urlencoded" 328 | version = "1.2.0" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" 331 | dependencies = [ 332 | "percent-encoding", 333 | ] 334 | 335 | [[package]] 336 | name = "futures-channel" 337 | version = "0.3.28" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" 340 | dependencies = [ 341 | "futures-core", 342 | "futures-sink", 343 | ] 344 | 345 | [[package]] 346 | name = "futures-core" 347 | version = "0.3.28" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 350 | 351 | [[package]] 352 | name = "futures-intrusive" 353 | version = "0.4.2" 354 | source = "registry+https://github.com/rust-lang/crates.io-index" 355 | checksum = "a604f7a68fbf8103337523b1fadc8ade7361ee3f112f7c680ad179651616aed5" 356 | dependencies = [ 357 | "futures-core", 358 | "lock_api", 359 | "parking_lot", 360 | ] 361 | 362 | [[package]] 363 | name = "futures-sink" 364 | version = "0.3.28" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 367 | 368 | [[package]] 369 | name = "futures-task" 370 | version = "0.3.28" 371 | source = "registry+https://github.com/rust-lang/crates.io-index" 372 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 373 | 374 | [[package]] 375 | name = "futures-util" 376 | version = "0.3.28" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 379 | dependencies = [ 380 | "futures-core", 381 | "futures-sink", 382 | "futures-task", 383 | "pin-project-lite", 384 | "pin-utils", 385 | ] 386 | 387 | [[package]] 388 | name = "generic-array" 389 | version = "0.14.7" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 392 | dependencies = [ 393 | "typenum", 394 | "version_check", 395 | ] 396 | 397 | [[package]] 398 | name = "getrandom" 399 | version = "0.2.10" 400 | source = "registry+https://github.com/rust-lang/crates.io-index" 401 | checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" 402 | dependencies = [ 403 | "cfg-if", 404 | "libc", 405 | "wasi", 406 | ] 407 | 408 | [[package]] 409 | name = "gimli" 410 | version = "0.27.3" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" 413 | 414 | [[package]] 415 | name = "h2" 416 | version = "0.3.20" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" 419 | dependencies = [ 420 | "bytes", 421 | "fnv", 422 | "futures-core", 423 | "futures-sink", 424 | "futures-util", 425 | "http", 426 | "indexmap", 427 | "slab", 428 | "tokio", 429 | "tokio-util", 430 | "tracing", 431 | ] 432 | 433 | [[package]] 434 | name = "hashbrown" 435 | version = "0.12.3" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 438 | 439 | [[package]] 440 | name = "hashbrown" 441 | version = "0.14.0" 442 | source = "registry+https://github.com/rust-lang/crates.io-index" 443 | checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" 444 | dependencies = [ 445 | "ahash 0.8.3", 446 | "allocator-api2", 447 | ] 448 | 449 | [[package]] 450 | name = "hashlink" 451 | version = "0.8.3" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f" 454 | dependencies = [ 455 | "hashbrown 0.14.0", 456 | ] 457 | 458 | [[package]] 459 | name = "heck" 460 | version = "0.4.1" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" 463 | dependencies = [ 464 | "unicode-segmentation", 465 | ] 466 | 467 | [[package]] 468 | name = "hermit-abi" 469 | version = "0.3.2" 470 | source = "registry+https://github.com/rust-lang/crates.io-index" 471 | checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" 472 | 473 | [[package]] 474 | name = "hex" 475 | version = "0.4.3" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 478 | 479 | [[package]] 480 | name = "hkdf" 481 | version = "0.12.3" 482 | source = "registry+https://github.com/rust-lang/crates.io-index" 483 | checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" 484 | dependencies = [ 485 | "hmac", 486 | ] 487 | 488 | [[package]] 489 | name = "hmac" 490 | version = "0.12.1" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 493 | dependencies = [ 494 | "digest", 495 | ] 496 | 497 | [[package]] 498 | name = "http" 499 | version = "0.2.9" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" 502 | dependencies = [ 503 | "bytes", 504 | "fnv", 505 | "itoa", 506 | ] 507 | 508 | [[package]] 509 | name = "http-body" 510 | version = "0.4.5" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" 513 | dependencies = [ 514 | "bytes", 515 | "http", 516 | "pin-project-lite", 517 | ] 518 | 519 | [[package]] 520 | name = "httparse" 521 | version = "1.8.0" 522 | source = "registry+https://github.com/rust-lang/crates.io-index" 523 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" 524 | 525 | [[package]] 526 | name = "httpdate" 527 | version = "1.0.2" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" 530 | 531 | [[package]] 532 | name = "hyper" 533 | version = "0.14.27" 534 | source = "registry+https://github.com/rust-lang/crates.io-index" 535 | checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" 536 | dependencies = [ 537 | "bytes", 538 | "futures-channel", 539 | "futures-core", 540 | "futures-util", 541 | "h2", 542 | "http", 543 | "http-body", 544 | "httparse", 545 | "httpdate", 546 | "itoa", 547 | "pin-project-lite", 548 | "socket2", 549 | "tokio", 550 | "tower-service", 551 | "tracing", 552 | "want", 553 | ] 554 | 555 | [[package]] 556 | name = "idna" 557 | version = "0.4.0" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" 560 | dependencies = [ 561 | "unicode-bidi", 562 | "unicode-normalization", 563 | ] 564 | 565 | [[package]] 566 | name = "indexmap" 567 | version = "1.9.3" 568 | source = "registry+https://github.com/rust-lang/crates.io-index" 569 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 570 | dependencies = [ 571 | "autocfg", 572 | "hashbrown 0.12.3", 573 | ] 574 | 575 | [[package]] 576 | name = "instant" 577 | version = "0.1.12" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 580 | dependencies = [ 581 | "cfg-if", 582 | ] 583 | 584 | [[package]] 585 | name = "itertools" 586 | version = "0.10.5" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 589 | dependencies = [ 590 | "either", 591 | ] 592 | 593 | [[package]] 594 | name = "itoa" 595 | version = "1.0.9" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" 598 | 599 | [[package]] 600 | name = "js-sys" 601 | version = "0.3.64" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" 604 | dependencies = [ 605 | "wasm-bindgen", 606 | ] 607 | 608 | [[package]] 609 | name = "libc" 610 | version = "0.2.147" 611 | source = "registry+https://github.com/rust-lang/crates.io-index" 612 | checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" 613 | 614 | [[package]] 615 | name = "lock_api" 616 | version = "0.4.10" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" 619 | dependencies = [ 620 | "autocfg", 621 | "scopeguard", 622 | ] 623 | 624 | [[package]] 625 | name = "log" 626 | version = "0.4.19" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" 629 | 630 | [[package]] 631 | name = "matchit" 632 | version = "0.7.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" 635 | 636 | [[package]] 637 | name = "md-5" 638 | version = "0.10.5" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" 641 | dependencies = [ 642 | "digest", 643 | ] 644 | 645 | [[package]] 646 | name = "memchr" 647 | version = "2.5.0" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 650 | 651 | [[package]] 652 | name = "mime" 653 | version = "0.3.17" 654 | source = "registry+https://github.com/rust-lang/crates.io-index" 655 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 656 | 657 | [[package]] 658 | name = "minimal-lexical" 659 | version = "0.2.1" 660 | source = "registry+https://github.com/rust-lang/crates.io-index" 661 | checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" 662 | 663 | [[package]] 664 | name = "miniz_oxide" 665 | version = "0.7.1" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" 668 | dependencies = [ 669 | "adler", 670 | ] 671 | 672 | [[package]] 673 | name = "mio" 674 | version = "0.8.8" 675 | source = "registry+https://github.com/rust-lang/crates.io-index" 676 | checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" 677 | dependencies = [ 678 | "libc", 679 | "wasi", 680 | "windows-sys", 681 | ] 682 | 683 | [[package]] 684 | name = "nom" 685 | version = "7.1.3" 686 | source = "registry+https://github.com/rust-lang/crates.io-index" 687 | checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" 688 | dependencies = [ 689 | "memchr", 690 | "minimal-lexical", 691 | ] 692 | 693 | [[package]] 694 | name = "num-traits" 695 | version = "0.2.15" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" 698 | dependencies = [ 699 | "autocfg", 700 | ] 701 | 702 | [[package]] 703 | name = "num_cpus" 704 | version = "1.16.0" 705 | source = "registry+https://github.com/rust-lang/crates.io-index" 706 | checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" 707 | dependencies = [ 708 | "hermit-abi", 709 | "libc", 710 | ] 711 | 712 | [[package]] 713 | name = "object" 714 | version = "0.31.1" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" 717 | dependencies = [ 718 | "memchr", 719 | ] 720 | 721 | [[package]] 722 | name = "once_cell" 723 | version = "1.18.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" 726 | 727 | [[package]] 728 | name = "parking_lot" 729 | version = "0.11.2" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" 732 | dependencies = [ 733 | "instant", 734 | "lock_api", 735 | "parking_lot_core", 736 | ] 737 | 738 | [[package]] 739 | name = "parking_lot_core" 740 | version = "0.8.6" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" 743 | dependencies = [ 744 | "cfg-if", 745 | "instant", 746 | "libc", 747 | "redox_syscall", 748 | "smallvec", 749 | "winapi", 750 | ] 751 | 752 | [[package]] 753 | name = "paste" 754 | version = "1.0.14" 755 | source = "registry+https://github.com/rust-lang/crates.io-index" 756 | checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" 757 | 758 | [[package]] 759 | name = "percent-encoding" 760 | version = "2.3.0" 761 | source = "registry+https://github.com/rust-lang/crates.io-index" 762 | checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" 763 | 764 | [[package]] 765 | name = "pin-project" 766 | version = "1.1.2" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" 769 | dependencies = [ 770 | "pin-project-internal", 771 | ] 772 | 773 | [[package]] 774 | name = "pin-project-internal" 775 | version = "1.1.2" 776 | source = "registry+https://github.com/rust-lang/crates.io-index" 777 | checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" 778 | dependencies = [ 779 | "proc-macro2", 780 | "quote", 781 | "syn 2.0.26", 782 | ] 783 | 784 | [[package]] 785 | name = "pin-project-lite" 786 | version = "0.2.10" 787 | source = "registry+https://github.com/rust-lang/crates.io-index" 788 | checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" 789 | 790 | [[package]] 791 | name = "pin-utils" 792 | version = "0.1.0" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 795 | 796 | [[package]] 797 | name = "ppv-lite86" 798 | version = "0.2.17" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 801 | 802 | [[package]] 803 | name = "proc-macro2" 804 | version = "1.0.66" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" 807 | dependencies = [ 808 | "unicode-ident", 809 | ] 810 | 811 | [[package]] 812 | name = "quote" 813 | version = "1.0.31" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" 816 | dependencies = [ 817 | "proc-macro2", 818 | ] 819 | 820 | [[package]] 821 | name = "rand" 822 | version = "0.8.5" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 825 | dependencies = [ 826 | "libc", 827 | "rand_chacha", 828 | "rand_core", 829 | ] 830 | 831 | [[package]] 832 | name = "rand_chacha" 833 | version = "0.3.1" 834 | source = "registry+https://github.com/rust-lang/crates.io-index" 835 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 836 | dependencies = [ 837 | "ppv-lite86", 838 | "rand_core", 839 | ] 840 | 841 | [[package]] 842 | name = "rand_core" 843 | version = "0.6.4" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 846 | dependencies = [ 847 | "getrandom", 848 | ] 849 | 850 | [[package]] 851 | name = "redox_syscall" 852 | version = "0.2.16" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 855 | dependencies = [ 856 | "bitflags", 857 | ] 858 | 859 | [[package]] 860 | name = "redox_users" 861 | version = "0.4.3" 862 | source = "registry+https://github.com/rust-lang/crates.io-index" 863 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 864 | dependencies = [ 865 | "getrandom", 866 | "redox_syscall", 867 | "thiserror", 868 | ] 869 | 870 | [[package]] 871 | name = "ring" 872 | version = "0.16.20" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" 875 | dependencies = [ 876 | "cc", 877 | "libc", 878 | "once_cell", 879 | "spin", 880 | "untrusted", 881 | "web-sys", 882 | "winapi", 883 | ] 884 | 885 | [[package]] 886 | name = "rustc-demangle" 887 | version = "0.1.23" 888 | source = "registry+https://github.com/rust-lang/crates.io-index" 889 | checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" 890 | 891 | [[package]] 892 | name = "rustls" 893 | version = "0.20.8" 894 | source = "registry+https://github.com/rust-lang/crates.io-index" 895 | checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" 896 | dependencies = [ 897 | "log", 898 | "ring", 899 | "sct", 900 | "webpki", 901 | ] 902 | 903 | [[package]] 904 | name = "rustls-pemfile" 905 | version = "1.0.3" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" 908 | dependencies = [ 909 | "base64 0.21.2", 910 | ] 911 | 912 | [[package]] 913 | name = "rustversion" 914 | version = "1.0.14" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" 917 | 918 | [[package]] 919 | name = "ryu" 920 | version = "1.0.15" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" 923 | 924 | [[package]] 925 | name = "scopeguard" 926 | version = "1.2.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 929 | 930 | [[package]] 931 | name = "sct" 932 | version = "0.7.0" 933 | source = "registry+https://github.com/rust-lang/crates.io-index" 934 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" 935 | dependencies = [ 936 | "ring", 937 | "untrusted", 938 | ] 939 | 940 | [[package]] 941 | name = "serde" 942 | version = "1.0.171" 943 | source = "registry+https://github.com/rust-lang/crates.io-index" 944 | checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" 945 | dependencies = [ 946 | "serde_derive", 947 | ] 948 | 949 | [[package]] 950 | name = "serde_derive" 951 | version = "1.0.171" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" 954 | dependencies = [ 955 | "proc-macro2", 956 | "quote", 957 | "syn 2.0.26", 958 | ] 959 | 960 | [[package]] 961 | name = "serde_json" 962 | version = "1.0.103" 963 | source = "registry+https://github.com/rust-lang/crates.io-index" 964 | checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" 965 | dependencies = [ 966 | "itoa", 967 | "ryu", 968 | "serde", 969 | ] 970 | 971 | [[package]] 972 | name = "serde_path_to_error" 973 | version = "0.1.14" 974 | source = "registry+https://github.com/rust-lang/crates.io-index" 975 | checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" 976 | dependencies = [ 977 | "itoa", 978 | "serde", 979 | ] 980 | 981 | [[package]] 982 | name = "serde_urlencoded" 983 | version = "0.7.1" 984 | source = "registry+https://github.com/rust-lang/crates.io-index" 985 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 986 | dependencies = [ 987 | "form_urlencoded", 988 | "itoa", 989 | "ryu", 990 | "serde", 991 | ] 992 | 993 | [[package]] 994 | name = "sha1" 995 | version = "0.10.5" 996 | source = "registry+https://github.com/rust-lang/crates.io-index" 997 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 998 | dependencies = [ 999 | "cfg-if", 1000 | "cpufeatures", 1001 | "digest", 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "sha2" 1006 | version = "0.10.7" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" 1009 | dependencies = [ 1010 | "cfg-if", 1011 | "cpufeatures", 1012 | "digest", 1013 | ] 1014 | 1015 | [[package]] 1016 | name = "slab" 1017 | version = "0.4.8" 1018 | source = "registry+https://github.com/rust-lang/crates.io-index" 1019 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 1020 | dependencies = [ 1021 | "autocfg", 1022 | ] 1023 | 1024 | [[package]] 1025 | name = "smallvec" 1026 | version = "1.11.0" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" 1029 | 1030 | [[package]] 1031 | name = "socket2" 1032 | version = "0.4.9" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 1035 | dependencies = [ 1036 | "libc", 1037 | "winapi", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "spin" 1042 | version = "0.5.2" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" 1045 | 1046 | [[package]] 1047 | name = "sqlformat" 1048 | version = "0.2.1" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e" 1051 | dependencies = [ 1052 | "itertools", 1053 | "nom", 1054 | "unicode_categories", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "sqlx" 1059 | version = "0.6.3" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "f8de3b03a925878ed54a954f621e64bf55a3c1bd29652d0d1a17830405350188" 1062 | dependencies = [ 1063 | "sqlx-core", 1064 | "sqlx-macros", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "sqlx-core" 1069 | version = "0.6.3" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "fa8241483a83a3f33aa5fff7e7d9def398ff9990b2752b6c6112b83c6d246029" 1072 | dependencies = [ 1073 | "ahash 0.7.6", 1074 | "atoi", 1075 | "base64 0.13.1", 1076 | "bitflags", 1077 | "byteorder", 1078 | "bytes", 1079 | "crc", 1080 | "crossbeam-queue", 1081 | "dirs", 1082 | "dotenvy", 1083 | "either", 1084 | "event-listener", 1085 | "futures-channel", 1086 | "futures-core", 1087 | "futures-intrusive", 1088 | "futures-util", 1089 | "hashlink", 1090 | "hex", 1091 | "hkdf", 1092 | "hmac", 1093 | "indexmap", 1094 | "itoa", 1095 | "libc", 1096 | "log", 1097 | "md-5", 1098 | "memchr", 1099 | "once_cell", 1100 | "paste", 1101 | "percent-encoding", 1102 | "rand", 1103 | "rustls", 1104 | "rustls-pemfile", 1105 | "serde", 1106 | "serde_json", 1107 | "sha1", 1108 | "sha2", 1109 | "smallvec", 1110 | "sqlformat", 1111 | "sqlx-rt", 1112 | "stringprep", 1113 | "thiserror", 1114 | "tokio-stream", 1115 | "url", 1116 | "webpki-roots", 1117 | "whoami", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "sqlx-macros" 1122 | version = "0.6.3" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "9966e64ae989e7e575b19d7265cb79d7fc3cbbdf179835cb0d716f294c2049c9" 1125 | dependencies = [ 1126 | "dotenvy", 1127 | "either", 1128 | "heck", 1129 | "hex", 1130 | "once_cell", 1131 | "proc-macro2", 1132 | "quote", 1133 | "serde", 1134 | "serde_json", 1135 | "sha2", 1136 | "sqlx-core", 1137 | "sqlx-rt", 1138 | "syn 1.0.109", 1139 | "url", 1140 | ] 1141 | 1142 | [[package]] 1143 | name = "sqlx-rt" 1144 | version = "0.6.3" 1145 | source = "registry+https://github.com/rust-lang/crates.io-index" 1146 | checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" 1147 | dependencies = [ 1148 | "once_cell", 1149 | "tokio", 1150 | "tokio-rustls", 1151 | ] 1152 | 1153 | [[package]] 1154 | name = "stringprep" 1155 | version = "0.1.3" 1156 | source = "registry+https://github.com/rust-lang/crates.io-index" 1157 | checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da" 1158 | dependencies = [ 1159 | "unicode-bidi", 1160 | "unicode-normalization", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "subtle" 1165 | version = "2.5.0" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" 1168 | 1169 | [[package]] 1170 | name = "syn" 1171 | version = "1.0.109" 1172 | source = "registry+https://github.com/rust-lang/crates.io-index" 1173 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 1174 | dependencies = [ 1175 | "proc-macro2", 1176 | "quote", 1177 | "unicode-ident", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "syn" 1182 | version = "2.0.26" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" 1185 | dependencies = [ 1186 | "proc-macro2", 1187 | "quote", 1188 | "unicode-ident", 1189 | ] 1190 | 1191 | [[package]] 1192 | name = "sync_wrapper" 1193 | version = "0.1.2" 1194 | source = "registry+https://github.com/rust-lang/crates.io-index" 1195 | checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" 1196 | 1197 | [[package]] 1198 | name = "thiserror" 1199 | version = "1.0.43" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" 1202 | dependencies = [ 1203 | "thiserror-impl", 1204 | ] 1205 | 1206 | [[package]] 1207 | name = "thiserror-impl" 1208 | version = "1.0.43" 1209 | source = "registry+https://github.com/rust-lang/crates.io-index" 1210 | checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" 1211 | dependencies = [ 1212 | "proc-macro2", 1213 | "quote", 1214 | "syn 2.0.26", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "tinyvec" 1219 | version = "1.6.0" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" 1222 | dependencies = [ 1223 | "tinyvec_macros", 1224 | ] 1225 | 1226 | [[package]] 1227 | name = "tinyvec_macros" 1228 | version = "0.1.1" 1229 | source = "registry+https://github.com/rust-lang/crates.io-index" 1230 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 1231 | 1232 | [[package]] 1233 | name = "tokio" 1234 | version = "1.29.1" 1235 | source = "registry+https://github.com/rust-lang/crates.io-index" 1236 | checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" 1237 | dependencies = [ 1238 | "autocfg", 1239 | "backtrace", 1240 | "bytes", 1241 | "libc", 1242 | "mio", 1243 | "num_cpus", 1244 | "pin-project-lite", 1245 | "socket2", 1246 | "tokio-macros", 1247 | "windows-sys", 1248 | ] 1249 | 1250 | [[package]] 1251 | name = "tokio-macros" 1252 | version = "2.1.0" 1253 | source = "registry+https://github.com/rust-lang/crates.io-index" 1254 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" 1255 | dependencies = [ 1256 | "proc-macro2", 1257 | "quote", 1258 | "syn 2.0.26", 1259 | ] 1260 | 1261 | [[package]] 1262 | name = "tokio-rustls" 1263 | version = "0.23.4" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" 1266 | dependencies = [ 1267 | "rustls", 1268 | "tokio", 1269 | "webpki", 1270 | ] 1271 | 1272 | [[package]] 1273 | name = "tokio-stream" 1274 | version = "0.1.14" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" 1277 | dependencies = [ 1278 | "futures-core", 1279 | "pin-project-lite", 1280 | "tokio", 1281 | ] 1282 | 1283 | [[package]] 1284 | name = "tokio-util" 1285 | version = "0.7.8" 1286 | source = "registry+https://github.com/rust-lang/crates.io-index" 1287 | checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" 1288 | dependencies = [ 1289 | "bytes", 1290 | "futures-core", 1291 | "futures-sink", 1292 | "pin-project-lite", 1293 | "tokio", 1294 | "tracing", 1295 | ] 1296 | 1297 | [[package]] 1298 | name = "tower" 1299 | version = "0.4.13" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" 1302 | dependencies = [ 1303 | "futures-core", 1304 | "futures-util", 1305 | "pin-project", 1306 | "pin-project-lite", 1307 | "tokio", 1308 | "tower-layer", 1309 | "tower-service", 1310 | "tracing", 1311 | ] 1312 | 1313 | [[package]] 1314 | name = "tower-layer" 1315 | version = "0.3.2" 1316 | source = "registry+https://github.com/rust-lang/crates.io-index" 1317 | checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" 1318 | 1319 | [[package]] 1320 | name = "tower-service" 1321 | version = "0.3.2" 1322 | source = "registry+https://github.com/rust-lang/crates.io-index" 1323 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" 1324 | 1325 | [[package]] 1326 | name = "tracing" 1327 | version = "0.1.37" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1330 | dependencies = [ 1331 | "cfg-if", 1332 | "log", 1333 | "pin-project-lite", 1334 | "tracing-core", 1335 | ] 1336 | 1337 | [[package]] 1338 | name = "tracing-core" 1339 | version = "0.1.31" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 1342 | dependencies = [ 1343 | "once_cell", 1344 | ] 1345 | 1346 | [[package]] 1347 | name = "try-lock" 1348 | version = "0.2.4" 1349 | source = "registry+https://github.com/rust-lang/crates.io-index" 1350 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" 1351 | 1352 | [[package]] 1353 | name = "typenum" 1354 | version = "1.16.0" 1355 | source = "registry+https://github.com/rust-lang/crates.io-index" 1356 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1357 | 1358 | [[package]] 1359 | name = "unicode-bidi" 1360 | version = "0.3.13" 1361 | source = "registry+https://github.com/rust-lang/crates.io-index" 1362 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" 1363 | 1364 | [[package]] 1365 | name = "unicode-ident" 1366 | version = "1.0.11" 1367 | source = "registry+https://github.com/rust-lang/crates.io-index" 1368 | checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" 1369 | 1370 | [[package]] 1371 | name = "unicode-normalization" 1372 | version = "0.1.22" 1373 | source = "registry+https://github.com/rust-lang/crates.io-index" 1374 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" 1375 | dependencies = [ 1376 | "tinyvec", 1377 | ] 1378 | 1379 | [[package]] 1380 | name = "unicode-segmentation" 1381 | version = "1.10.1" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" 1384 | 1385 | [[package]] 1386 | name = "unicode_categories" 1387 | version = "0.1.1" 1388 | source = "registry+https://github.com/rust-lang/crates.io-index" 1389 | checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" 1390 | 1391 | [[package]] 1392 | name = "untrusted" 1393 | version = "0.7.1" 1394 | source = "registry+https://github.com/rust-lang/crates.io-index" 1395 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" 1396 | 1397 | [[package]] 1398 | name = "url" 1399 | version = "2.4.0" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" 1402 | dependencies = [ 1403 | "form_urlencoded", 1404 | "idna", 1405 | "percent-encoding", 1406 | ] 1407 | 1408 | [[package]] 1409 | name = "version_check" 1410 | version = "0.9.4" 1411 | source = "registry+https://github.com/rust-lang/crates.io-index" 1412 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1413 | 1414 | [[package]] 1415 | name = "want" 1416 | version = "0.3.1" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 1419 | dependencies = [ 1420 | "try-lock", 1421 | ] 1422 | 1423 | [[package]] 1424 | name = "wasi" 1425 | version = "0.11.0+wasi-snapshot-preview1" 1426 | source = "registry+https://github.com/rust-lang/crates.io-index" 1427 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1428 | 1429 | [[package]] 1430 | name = "wasm-bindgen" 1431 | version = "0.2.87" 1432 | source = "registry+https://github.com/rust-lang/crates.io-index" 1433 | checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" 1434 | dependencies = [ 1435 | "cfg-if", 1436 | "wasm-bindgen-macro", 1437 | ] 1438 | 1439 | [[package]] 1440 | name = "wasm-bindgen-backend" 1441 | version = "0.2.87" 1442 | source = "registry+https://github.com/rust-lang/crates.io-index" 1443 | checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" 1444 | dependencies = [ 1445 | "bumpalo", 1446 | "log", 1447 | "once_cell", 1448 | "proc-macro2", 1449 | "quote", 1450 | "syn 2.0.26", 1451 | "wasm-bindgen-shared", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "wasm-bindgen-macro" 1456 | version = "0.2.87" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" 1459 | dependencies = [ 1460 | "quote", 1461 | "wasm-bindgen-macro-support", 1462 | ] 1463 | 1464 | [[package]] 1465 | name = "wasm-bindgen-macro-support" 1466 | version = "0.2.87" 1467 | source = "registry+https://github.com/rust-lang/crates.io-index" 1468 | checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" 1469 | dependencies = [ 1470 | "proc-macro2", 1471 | "quote", 1472 | "syn 2.0.26", 1473 | "wasm-bindgen-backend", 1474 | "wasm-bindgen-shared", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "wasm-bindgen-shared" 1479 | version = "0.2.87" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" 1482 | 1483 | [[package]] 1484 | name = "web-sys" 1485 | version = "0.3.64" 1486 | source = "registry+https://github.com/rust-lang/crates.io-index" 1487 | checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" 1488 | dependencies = [ 1489 | "js-sys", 1490 | "wasm-bindgen", 1491 | ] 1492 | 1493 | [[package]] 1494 | name = "webpki" 1495 | version = "0.22.0" 1496 | source = "registry+https://github.com/rust-lang/crates.io-index" 1497 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" 1498 | dependencies = [ 1499 | "ring", 1500 | "untrusted", 1501 | ] 1502 | 1503 | [[package]] 1504 | name = "webpki-roots" 1505 | version = "0.22.6" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" 1508 | dependencies = [ 1509 | "webpki", 1510 | ] 1511 | 1512 | [[package]] 1513 | name = "whoami" 1514 | version = "1.4.1" 1515 | source = "registry+https://github.com/rust-lang/crates.io-index" 1516 | checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" 1517 | dependencies = [ 1518 | "wasm-bindgen", 1519 | "web-sys", 1520 | ] 1521 | 1522 | [[package]] 1523 | name = "winapi" 1524 | version = "0.3.9" 1525 | source = "registry+https://github.com/rust-lang/crates.io-index" 1526 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1527 | dependencies = [ 1528 | "winapi-i686-pc-windows-gnu", 1529 | "winapi-x86_64-pc-windows-gnu", 1530 | ] 1531 | 1532 | [[package]] 1533 | name = "winapi-i686-pc-windows-gnu" 1534 | version = "0.4.0" 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" 1536 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1537 | 1538 | [[package]] 1539 | name = "winapi-x86_64-pc-windows-gnu" 1540 | version = "0.4.0" 1541 | source = "registry+https://github.com/rust-lang/crates.io-index" 1542 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1543 | 1544 | [[package]] 1545 | name = "windows-sys" 1546 | version = "0.48.0" 1547 | source = "registry+https://github.com/rust-lang/crates.io-index" 1548 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1549 | dependencies = [ 1550 | "windows-targets", 1551 | ] 1552 | 1553 | [[package]] 1554 | name = "windows-targets" 1555 | version = "0.48.1" 1556 | source = "registry+https://github.com/rust-lang/crates.io-index" 1557 | checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" 1558 | dependencies = [ 1559 | "windows_aarch64_gnullvm", 1560 | "windows_aarch64_msvc", 1561 | "windows_i686_gnu", 1562 | "windows_i686_msvc", 1563 | "windows_x86_64_gnu", 1564 | "windows_x86_64_gnullvm", 1565 | "windows_x86_64_msvc", 1566 | ] 1567 | 1568 | [[package]] 1569 | name = "windows_aarch64_gnullvm" 1570 | version = "0.48.0" 1571 | source = "registry+https://github.com/rust-lang/crates.io-index" 1572 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 1573 | 1574 | [[package]] 1575 | name = "windows_aarch64_msvc" 1576 | version = "0.48.0" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 1579 | 1580 | [[package]] 1581 | name = "windows_i686_gnu" 1582 | version = "0.48.0" 1583 | source = "registry+https://github.com/rust-lang/crates.io-index" 1584 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 1585 | 1586 | [[package]] 1587 | name = "windows_i686_msvc" 1588 | version = "0.48.0" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 1591 | 1592 | [[package]] 1593 | name = "windows_x86_64_gnu" 1594 | version = "0.48.0" 1595 | source = "registry+https://github.com/rust-lang/crates.io-index" 1596 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 1597 | 1598 | [[package]] 1599 | name = "windows_x86_64_gnullvm" 1600 | version = "0.48.0" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 1603 | 1604 | [[package]] 1605 | name = "windows_x86_64_msvc" 1606 | version = "0.48.0" 1607 | source = "registry+https://github.com/rust-lang/crates.io-index" 1608 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 1609 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "api-deployment-example" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | axum = { version = "0.6", features = ["json"] } 10 | tokio = { version = "1", features = ["macros"] } 11 | hyper = { version = "0.14", features = ["full"] } 12 | sqlx = { version = "0.6", features = [ "runtime-tokio-rustls", "postgres", "offline"] } 13 | serde = { version = "1.0", features = ["derive"] } 14 | anyhow = "1.0" 15 | dotenvy = "0.15" 16 | 17 | [dev-dependencies] 18 | tower = { version = "0.4", features = ["util"] } 19 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM messense/rust-musl-cross:x86_64-musl as chef 2 | ENV SQLX_OFFLINE=true 3 | RUN cargo install cargo-chef 4 | WORKDIR /api-deployment-example 5 | 6 | FROM chef AS planner 7 | # Copy source code from previous stage 8 | COPY . . 9 | # Generate info for caching dependencies 10 | RUN cargo chef prepare --recipe-path recipe.json 11 | 12 | FROM chef AS builder 13 | COPY --from=planner /api-deployment-example/recipe.json recipe.json 14 | # Build & cache dependencies 15 | RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json 16 | # Copy source code from previous stage 17 | COPY . . 18 | # Build application 19 | RUN cargo build --release --target x86_64-unknown-linux-musl 20 | 21 | # Create a new stage with a minimal image 22 | FROM scratch 23 | COPY --from=builder /api-deployment-example/target/x86_64-unknown-linux-musl/release/api-deployment-example /api-deployment-example 24 | ENTRYPOINT ["/api-deployment-example"] 25 | EXPOSE 3000 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # API Deployment Example 2 | 3 | ## Setup 4 | 5 | 1. Make sure [Docker](https://www.docker.com/) is installed and running 6 | 2. Make sure [sqlx cli](https://crates.io/crates/sqlx-cli) is installed 7 | 3. Create a `.env` file. This file will store environment variables. Specifically, `DATABASE_URL` and `POSTGRES_PASSWORD`. It should look like this: 8 | ``` 9 | DATABASE_URL=postgres://postgres:postgrespw@localhost:5432 10 | POSTGRES_PASSWORD=postgrespw 11 | ``` 12 | `NOTE:` When deploying the API, make sure to change the default PostgreSQL password. 13 | 4. Update `docker-compose.yml` and change `letsgetrusty` to your own Docker Hub username. 14 | 15 | ## Run Locally 16 | 1. Run an instance of PostgreSQL. This can be done via Docker: 17 | ```bash 18 | docker pull postgres 19 | docker run --name example-db -e POSTGRES_PASSWORD=postgrespw -p 5432:5432 -d postgres 20 | ``` 21 | 2. Run SQL migrations: 22 | ```bash 23 | sqlx migrate run 24 | ``` 25 | 3. Start server: 26 | ```bash 27 | cargo run 28 | ``` 29 | 4. Test routes. I like to use [Postman](https://www.postman.com/). 30 | 31 | ## Run Locally using Docker 32 | 1. Run API via Docker Compose: 33 | ```bash 34 | docker-compose up 35 | ``` 36 | 2. Test routes. I like to use [Postman](https://www.postman.com/). -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | // generated by `sqlx migrate build-script` 2 | fn main() { 3 | // trigger recompilation when a new migration is added 4 | println!("cargo:rerun-if-changed=migrations"); 5 | } 6 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | api: 4 | image: letsgetrusty/api-example 5 | environment: 6 | DATABASE_URL: "postgres://postgres:${POSTGRES_PASSWORD}@db:5432" 7 | build: 8 | context: . 9 | dockerfile: Dockerfile 10 | ports: 11 | - "3000:3000" 12 | depends_on: 13 | - db 14 | db: 15 | image: postgres:15.2-alpine 16 | restart: always 17 | environment: 18 | POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} 19 | ports: 20 | - "5432:5432" 21 | volumes: 22 | - db:/var/lib/postgresql/data 23 | 24 | volumes: 25 | db: 26 | driver: local -------------------------------------------------------------------------------- /migrations/20230418001048_tables.down.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS users; -------------------------------------------------------------------------------- /migrations/20230418001048_tables.up.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS users ( 2 | id SERIAL PRIMARY KEY, 3 | name VARCHAR(255) NOT NULL, 4 | email VARCHAR(255) NOT NULL 5 | ); 6 | -------------------------------------------------------------------------------- /sqlx-data.json: -------------------------------------------------------------------------------- 1 | { 2 | "db": "PostgreSQL", 3 | "26e7e05427bc7dabcd7815d27764fda2baf4cfe60a2d2d6ee2a1f773dccbbce2": { 4 | "describe": { 5 | "columns": [ 6 | { 7 | "name": "id", 8 | "ordinal": 0, 9 | "type_info": "Int4" 10 | }, 11 | { 12 | "name": "name", 13 | "ordinal": 1, 14 | "type_info": "Varchar" 15 | }, 16 | { 17 | "name": "email", 18 | "ordinal": 2, 19 | "type_info": "Varchar" 20 | } 21 | ], 22 | "nullable": [ 23 | false, 24 | false, 25 | false 26 | ], 27 | "parameters": { 28 | "Left": [] 29 | } 30 | }, 31 | "query": "SELECT * FROM users" 32 | }, 33 | "50293c2e54af11d4c2a553e29b671cef087a159c6ee7182d8ca929ecb748f3b7": { 34 | "describe": { 35 | "columns": [], 36 | "nullable": [], 37 | "parameters": { 38 | "Left": [ 39 | "Int4" 40 | ] 41 | } 42 | }, 43 | "query": "DELETE FROM users WHERE id = $1" 44 | }, 45 | "7f8180b71331d2b03816f5354f02c11e0bd21683db0d04c78b6e552e190871d3": { 46 | "describe": { 47 | "columns": [ 48 | { 49 | "name": "id", 50 | "ordinal": 0, 51 | "type_info": "Int4" 52 | }, 53 | { 54 | "name": "name", 55 | "ordinal": 1, 56 | "type_info": "Varchar" 57 | }, 58 | { 59 | "name": "email", 60 | "ordinal": 2, 61 | "type_info": "Varchar" 62 | } 63 | ], 64 | "nullable": [ 65 | false, 66 | false, 67 | false 68 | ], 69 | "parameters": { 70 | "Left": [ 71 | "Varchar", 72 | "Varchar" 73 | ] 74 | } 75 | }, 76 | "query": "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email" 77 | } 78 | } -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use axum::{ 2 | extract::{self, Path}, 3 | http::StatusCode, 4 | routing::{delete, get, post}, 5 | Extension, Json, Router, 6 | }; 7 | 8 | use dotenvy::dotenv; 9 | 10 | use serde::{Deserialize, Serialize}; 11 | use sqlx::postgres::PgPoolOptions; 12 | use sqlx::{Pool, Postgres}; 13 | 14 | #[tokio::main] 15 | async fn main() -> anyhow::Result<()> { 16 | dotenv().ok(); 17 | 18 | let url = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set."); 19 | 20 | let pool = PgPoolOptions::new() 21 | .max_connections(5) 22 | .connect(&url) 23 | .await 24 | .unwrap_or_else(|_| panic!("Failed to create Postgres connection pool! URL: {}", url)); 25 | 26 | sqlx::migrate!("./migrations").run(&pool).await?; 27 | 28 | let addr: std::net::SocketAddr = std::net::SocketAddr::from(([0, 0, 0, 0], 3000)); 29 | 30 | println!("listening on {}", addr); 31 | 32 | axum::Server::bind(&addr) 33 | .serve(app().layer(Extension(pool)).into_make_service()) 34 | .await 35 | .unwrap(); 36 | 37 | Ok(()) 38 | } 39 | 40 | #[derive(Serialize, Deserialize)] 41 | pub struct User { 42 | #[serde(skip_serializing_if = "Option::is_none")] 43 | pub id: Option, 44 | pub name: String, 45 | pub email: String, 46 | } 47 | 48 | /// Having a function that produces our app makes it easy to call it from tests 49 | /// without having to create an HTTP server. 50 | #[allow(dead_code)] 51 | fn app() -> Router { 52 | Router::new() 53 | .route("/", get(handler)) 54 | .route("/user", post(create_user)) 55 | .route("/users", get(get_users)) 56 | .route("/user/:id", delete(delete_user)) 57 | } 58 | 59 | async fn handler() -> &'static str { 60 | "Let's Get Rusty!" 61 | } 62 | 63 | async fn get_users(state: Extension>) -> Json> { 64 | let Extension(pool) = state; 65 | 66 | let records = sqlx::query!("SELECT * FROM users") 67 | .fetch_all(&pool) 68 | .await 69 | .expect("failed to fetch users"); 70 | 71 | let records = records 72 | .iter() 73 | .map(|r| User { 74 | id: Some(r.id), 75 | name: r.name.to_string(), 76 | email: r.email.clone(), 77 | }) 78 | .collect(); 79 | 80 | Json(records) 81 | } 82 | 83 | pub async fn create_user( 84 | state: Extension>, 85 | extract::Json(user): extract::Json, 86 | ) -> Json { 87 | let Extension(pool) = state; 88 | 89 | let row = sqlx::query!( 90 | "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email", 91 | user.name, 92 | user.email 93 | ) 94 | .fetch_one(&pool) 95 | .await 96 | .expect("Failed to create user"); 97 | 98 | Json(User { 99 | id: Some(row.id), 100 | name: row.name, 101 | email: row.email, 102 | }) 103 | } 104 | 105 | pub async fn delete_user(state: Extension>, Path(user_id): Path) -> StatusCode { 106 | let Extension(pool) = state; 107 | 108 | sqlx::query!("DELETE FROM users WHERE id = $1", user_id) 109 | .execute(&pool) 110 | .await 111 | .expect("Failed to delete user"); 112 | 113 | StatusCode::NO_CONTENT 114 | } 115 | 116 | #[cfg(test)] 117 | mod tests { 118 | use super::*; 119 | use axum::{ 120 | body::Body, 121 | http::{Request, StatusCode}, 122 | }; 123 | use tower::util::ServiceExt; // for `oneshot` 124 | 125 | #[tokio::test] 126 | async fn hello_world() { 127 | let app = app(); 128 | 129 | // `Router` implements `tower::Service>` so we can 130 | // call it like any tower service, no need to run an HTTP server. 131 | let response = app 132 | .oneshot(Request::builder().uri("/").body(Body::empty()).unwrap()) 133 | .await 134 | .unwrap(); 135 | 136 | assert_eq!(response.status(), StatusCode::OK); 137 | 138 | let body = hyper::body::to_bytes(response.into_body()).await.unwrap(); 139 | assert_eq!(&body[..], b"Let's Get Rusty!"); 140 | } 141 | } 142 | --------------------------------------------------------------------------------