From 8088eb433b5becd097aeca5d0f6ce3cc25e6771f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Zwoli=C5=84ski?= Date: Fri, 22 Jul 2022 18:00:30 +0200 Subject: [PATCH] Talk #27 2022r: rust and graphql for backend --- .../Cargo.lock | 1408 +++++++++++++++++ .../Cargo.toml | 15 + .../src/data.rs | 84 + .../src/graphql.rs | 147 ++ .../src/main.rs | 42 + .../talk.pdf | Bin 0 -> 89742 bytes .../talk.tex | 256 +++ 7 files changed, 1952 insertions(+) create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.lock create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.toml create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/src/data.rs create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/src/graphql.rs create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/src/main.rs create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/talk.pdf create mode 100644 talk-archive/2022-27-rust-and-graphql-for-backend/talk.tex diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.lock b/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.lock new file mode 100644 index 0000000..cf0280e --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.lock @@ -0,0 +1,1408 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ascii_utils" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a" + +[[package]] +name = "async-graphql" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7bef6458f7fb35c16443c6c8af7d219c54e676f47c5a47fd834c8bb8f3bd16" +dependencies = [ + "async-graphql-derive", + "async-graphql-parser", + "async-graphql-value", + "async-stream", + "async-trait", + "bytes", + "fast_chemail", + "fnv", + "futures-util", + "http", + "indexmap", + "mime", + "multer", + "num-traits", + "once_cell", + "pin-project-lite", + "regex", + "serde", + "serde_json", + "static_assertions", + "tempfile", + "thiserror", + "tracing", + "tracing-futures", +] + +[[package]] +name = "async-graphql-axum" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fab501bb1d574a276ff773a5af40fa820f60c9dc96a6d26db82d560abbdbe13" +dependencies = [ + "async-graphql", + "async-trait", + "axum", + "bytes", + "futures-util", + "http-body", + "serde_json", + "serde_urlencoded", + "tokio-util", + "tower-service", +] + +[[package]] +name = "async-graphql-derive" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c50c6f67f2cc6a0f22e8efdf1e92b459151feefd4c2ae8adc8c1a223e0ebd89" +dependencies = [ + "Inflector", + "async-graphql-parser", + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "thiserror", +] + +[[package]] +name = "async-graphql-parser" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a73c90d34c7456bf28a764bfa201c41ac1929b3c376af1815d5f6b176bf74fe4" +dependencies = [ + "async-graphql-value", + "pest", + "serde", + "serde_json", +] + +[[package]] +name = "async-graphql-value" +version = "4.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79f082786fccd251a8e9615df7f8d45dc8c5305f89062e79a9be570bcd08585" +dependencies = [ + "bytes", + "indexmap", + "serde", + "serde_json", +] + +[[package]] +name = "async-stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +dependencies = [ + "async-stream-impl", + "futures-core", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-trait" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "axum" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b9496f0c1d1afb7a2af4338bbe1d969cddfead41d87a9fb3aaa6d0bbc7af648" +dependencies = [ + "async-trait", + "axum-core", + "base64", + "bitflags", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sha-1", + "sync_wrapper", + "tokio", + "tokio-tungstenite", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4f44a0e6200e9d11a1cdc989e4b358f6e3d354fbf48478f345a17f4e43f8635" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] + +[[package]] +name = "base64" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0b3de4a0c5e67e16066a0715723abd91edc2f9001d09c46e1dca929351e130e" +dependencies = [ + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cpufeatures" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4529658bdda7fd6769b8614be250cdcfc3aeb0ee72fe66f9e41e5e5eb73eac02" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "649c91bc01e8b1eac09fb91e8dbc7d517684ca6be8ebc75bb9cafc894f9fdb6f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc69c5bfcbd2fc09a0f38451d2daf0e372e367986a83906d1b0dbc88134fb5" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fast_chemail" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "495a39d30d624c2caabe6312bfead73e7717692b44e0b32df168c275a2e8e9e4" +dependencies = [ + "ascii_utils", +] + +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + +[[package]] +name = "futures" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" + +[[package]] +name = "futures-executor" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" + +[[package]] +name = "futures-macro" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" + +[[package]] +name = "futures-task" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" + +[[package]] +name = "futures-util" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "headers" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" +dependencies = [ + "base64", + "bitflags", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha-1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + +[[package]] +name = "httparse" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "496ce29bb5a52785b44e0f7ca2847ae0bb839c9bd28f69acac9b99d461c0c04c" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c929dc5c39e335a03c405292728118860721b10190d98c2a0f0efd5baafbac" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +dependencies = [ + "autocfg", + "hashbrown", + "serde", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" + +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "multer" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30ba6d97eb198c5e8a35d67d5779d6680cca35652a60ee90fc23dc431d4fde8" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin", + "version_check", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78203e83c48cffbe01e4a2d35d566ca4de445d79a85372fc64e378bfc812a260" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "710faf75e1b33345361201d36d04e98ac1ed8909151a017ed384700836104c74" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro-crate" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +dependencies = [ + "thiserror", + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "thiserror" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11c75893af559bc8e10716548bdef5cb2b983f8e637db9d0e15126b61b484ee2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "futures", + "futures-task", + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "sha-1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + +[[package]] +name = "ucd-trie" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89570599c4fe5585de2b388aab47e99f7fa4e9238a1399f707a02e356058141c" + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + +[[package]] +name = "unicode-normalization" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + +[[package]] +name = "wrocrust-gql-talk" +version = "0.1.0" +dependencies = [ + "async-graphql", + "async-graphql-axum", + "async-stream", + "axum", + "futures", + "serde", + "tokio", +] diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.toml b/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.toml new file mode 100644 index 0000000..af1093f --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "wrocrust-gql-talk" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = "0.5" +tokio = { version = "1", features = ["full"] } +serde = { version = "1", features = ["derive"] } + +async-graphql-axum = "4" +async-graphql = { version = "4", features = ["tracing"] } + +futures = "0.3" +async-stream = "0.3" diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/src/data.rs b/talk-archive/2022-27-rust-and-graphql-for-backend/src/data.rs new file mode 100644 index 0000000..331d170 --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/src/data.rs @@ -0,0 +1,84 @@ +use crate::graphql::{Brand, Car, User}; + +pub(crate) type Users = Vec; +pub(crate) type Cars = Vec; + +pub(crate) fn users() -> Users { + vec![ + User { + id: 0, + name: "Json".to_string(), + surname: "Bourne".to_string(), + age: 19, + car_id: 4, + }, + User { + id: 1, + name: "Adam".to_string(), + surname: "Adams".to_string(), + age: 28, + car_id: 3, + }, + User { + id: 2, + name: "Cameron".to_string(), + surname: "Nelson".to_string(), + age: 71, + car_id: 2, + }, + User { + id: 3, + name: "Dawn".to_string(), + surname: "Lauer".to_string(), + age: 21, + car_id: 1, + }, + User { + id: 4, + name: "Billy".to_string(), + surname: "Blaser".to_string(), + age: 66, + car_id: 0, + }, + ] +} + +pub(crate) fn cars() -> Cars { + vec![ + Car { + id: 0, + brand: Brand::Ford, + model: "Focus".to_string(), + year: 2015, + owner_id: 4, + }, + Car { + id: 1, + brand: Brand::Fiat, + model: "Stilo".to_string(), + year: 2001, + owner_id: 3, + }, + Car { + id: 2, + brand: Brand::Opel, + model: "Astra".to_string(), + year: 2011, + owner_id: 2, + }, + Car { + id: 3, + brand: Brand::Ford, + model: "Mondeo".to_string(), + year: 2018, + owner_id: 1, + }, + Car { + id: 4, + brand: Brand::Fiat, + model: "Panda".to_string(), + year: 2005, + owner_id: 0, + }, + ] +} diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/src/graphql.rs b/talk-archive/2022-27-rust-and-graphql-for-backend/src/graphql.rs new file mode 100644 index 0000000..1e9fcc3 --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/src/graphql.rs @@ -0,0 +1,147 @@ +use crate::data::{self, Cars, Users}; +use async_graphql::*; +use async_stream::stream; +use futures::stream::Stream; +use tokio::sync::broadcast; + +pub type GqlSchema = Schema; + +pub fn schema() -> GqlSchema { + let (tx, _) = broadcast::channel(1); + Schema::build( + Query, + Mutation { + users_tx: tx.clone(), + }, + Subscription { users_tx: tx }, + ) + .data(data::users()) + .data(data::cars()) + .finish() +} + +/// The root query type +#[derive(Description)] +pub struct Query; + +#[Object(use_type_description)] // to get the doc from Query type +impl Query { + /// Get all users registered in the service + async fn users<'ctx>( + &self, + ctx: &Context<'ctx>, + #[graphql(desc = "Query at most this amount of users", default = 15)] limit: usize, + ) -> Result<&'ctx [User]> { + let users = ctx.data::()?; + let limit = std::cmp::min(limit, users.len()); + Ok(&users[..limit]) + } + + /// Get all cars registered in the service + async fn cars<'ctx>(&self, ctx: &Context<'ctx>) -> Result<&'ctx [Car]> { + let cars = ctx.data::()?; + Ok(&cars[..]) + } +} + +pub struct Mutation { + users_tx: broadcast::Sender, +} + +#[Object] +impl Mutation { + /// Notify all listeners that the user needs help + async fn call_for_help<'ctx>( + &self, + ctx: &Context<'ctx>, + #[graphql(desc = "Id of the user calling for help")] user_id: usize, + ) -> Result<&'ctx User> { + let users = ctx.data::()?; + let user = users.iter().find(|u| u.id == user_id).ok_or("Not found")?; + + self.users_tx.send(user.clone())?; + Ok(user) + } +} + +pub struct Subscription { + users_tx: broadcast::Sender, +} + +#[Subscription] +impl Subscription { + /// Listen to the users' help calls + async fn subscribe_for_help_calls(&self) -> impl Stream { + let mut users_rx = self.users_tx.subscribe(); + stream! { + while let Ok(user) = users_rx.recv().await { + yield user; + } + } + } +} + +/// Representation of the user +#[derive(SimpleObject, Clone)] +#[graphql(complex)] +pub struct User { + /// User's id + pub id: usize, + /// User's name + pub name: String, + /// User's surname + pub surname: String, + /// User's age + pub age: u32, + /// User's car id + #[graphql(skip)] + pub car_id: usize, +} + +#[ComplexObject] +impl User { + /// User's car + async fn car<'ctx>(&self, ctx: &Context<'ctx>) -> Result<&'ctx Car> { + let cars = ctx.data::()?; + cars.iter() + .find(|c| c.id == self.car_id) + .ok_or_else(|| "Not found".into()) + } +} + +/// All the car brands supported by service +#[derive(Enum, Description, Eq, PartialEq, Clone, Copy)] +pub enum Brand { + Fiat, + Ford, + Opel, +} + +/// Representation of the car +#[derive(Description, SimpleObject)] +#[graphql(complex)] +pub struct Car { + /// Car's id + pub id: usize, + /// Car's brand + pub brand: Brand, + /// Car's model + pub model: String, + /// Car's production year + pub year: u32, + /// Car's owner id + #[graphql(skip)] + pub owner_id: usize, +} + +#[ComplexObject] +impl Car { + /// Car's owner + async fn owner<'ctx>(&self, ctx: &Context<'ctx>) -> Result<&'ctx User> { + let users = ctx.data::()?; + users + .iter() + .find(|u| u.id == self.owner_id) + .ok_or_else(|| "Not found".into()) + } +} diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/src/main.rs b/talk-archive/2022-27-rust-and-graphql-for-backend/src/main.rs new file mode 100644 index 0000000..ca9bdb4 --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/src/main.rs @@ -0,0 +1,42 @@ +use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; +use async_graphql_axum::{GraphQLRequest, GraphQLResponse, GraphQLSubscription}; +use axum::{ + response::{self, IntoResponse}, + routing::get, + Extension, Router, +}; +use std::net::SocketAddr; + +pub mod data; +pub mod graphql; + +use graphql::GqlSchema; + +async fn graphql_handler(schema: Extension, req: GraphQLRequest) -> GraphQLResponse { + schema.execute(req.into_inner()).await.into() +} + +async fn graphql_playground() -> impl IntoResponse { + response::Html(playground_source( + GraphQLPlaygroundConfig::new("/graphql").subscription_endpoint("/ws"), + )) +} + +#[tokio::main] +async fn main() { + let gql_schema = graphql::schema(); + + let app = Router::new() + .route("/graphql", get(graphql_playground).post(graphql_handler)) + .route("/ws", GraphQLSubscription::new(gql_schema.clone())) + .layer(Extension(gql_schema)); + + let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); + + println!("listening on {}", addr); + + axum::Server::bind(&addr) + .serve(app.into_make_service()) + .await + .unwrap(); +} diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/talk.pdf b/talk-archive/2022-27-rust-and-graphql-for-backend/talk.pdf new file mode 100644 index 0000000000000000000000000000000000000000..46f9bf50a122a42ff89421e0c1bc1de27352af16 GIT binary patch literal 89742 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
Z(5ZzD zK4XoUN5G(>$M*I!kA#ExIToyZE!r18#9Rv#CH)Scu0fQ2$h2J5k)G%Jn@-;iH zN)1Q$ZL3{uQPAoI*4ewm!-rj-NtpV=KO&LM3GcygA2pLSNy$eM_0J2OU(UpA>i7)e zMmc>fKb}blsW`Krq>4(eDWnI&Mv7~;*qapSy&KfbEqF>dcj{T{=zLiW4Z;H~i=V`| zrH`;FUTnS@q=HG4Z0jGBcVrAYmjsWbJ2l)UtJnVRRyXSRVObAu>p-gkDuNNItR=L| z`?}F;#oHvA7V@Fn?onr-v!z&6(+}=jB!~&s*J*BUdn!;#cwMHpREBlm4PMhjX}piF zZaJz``|>cCkIlI7Y~9$;$tWv7wYCU%wa@S7an!sj!$h-qbhUVVGjSnZFqnQB=W-V& zEnY{P(c9P_myqOhR$;bcMS4GIS0-2PF34|qTiVngDr{k^$MGkS0{ z{)O*o@>48OqTuoEy)yo@U0tLA-}0Oi(~3E&gmg81hQbs3^hxy1^ycqQRr&$7KmRaK zyV3?ryq6Mjw>O|;7u(J~l_tns^vTJ0uG!w(VRc(R>w}QIdz2%7vLp2_sxZNH-X>b< zb644Qe>n*eM1|y6!K(p9pZWZ1H&$4U*c=9G?bN&&K6Jlr^~K5sX}rgfuam4dE}R{u zk#Nk-U*+N>^W_0&Jf5rl+G^Ey+A-xq88CT}zE=4tQn6#n;0vaIIVEyK15^4JC>}l1LQ)*8Q<5j=u zr!U!GBnoBrYwM0BJML&?^FZXAJwldQzH@0dq|R2%TK~7c_L6YY`t!{h2yL+J9u)Z) zz`ZsL;{VK&Xve7Xfhuk)=2XU)`79ZPDy1?;ugcbJpL*l9QQ)EgcpA|v7Ch2V-&y7e zVSv>q&q@r#jpHYzq&EnbUG%@KB#rHfm(BH`Q2R^sh#pbGOdYRXbvzhAZ>x?^(F;`w z$AtY5i$87WG1#CZb96l%@Miw@pQ;=a(!ASuR_j}hm#>s#;Tv{_3zG-+aWi?tL3gU7 z%A=npoioo#-5FiuotbT;ks2K^x3V#`hX_hpb?R&}%+TW?qe1pEbBDtgohZqxi|=Yo zj#{o|rFa)YPs8{g#8wKl#JY8>@jQ@8$O~L0c>=ZdEZ_pA@PSH6J`DR;~Yu5z15%3Uy}dmpop0L)h~RT;4z6;T}-;c#)q^ z^y61k*n-kzQl?b|20LrIzy>$_Ax>M(^m+xY#V!P-ac4G# zTIL=g?|U_dBeFbv^awKuCUc@}p3S7qu)%RKsK3NN%r-&Mdq~N;O@FFP54rb_KI!wR zn_~AJPe}uBm&N_FLqv}DI|}f&=1vg>3vl=$?ognH;`wMVzQiz|x{rTw{2c45^uMka zCab?9ceSH@=+in5XS5^iZ<4cEjUJ$dbr|Qq3Sz;_wcYwE>1>c7TJl)eKJ0>ZXK^PO z!G~OEcb4~$5C0wM=TmtkbIn1d^9o5d z_#?zw8b^S9?0C7&b<%mbN}BYfi7=Fo8hU7=qjjF+)H#OkF}jb8U^Tj5h*8FsJR_Jd zi$^$`;X-&1Sa?h#Y{H7EIc!gAUO)vsG_|Osx9J{JwF|UZHG&3^lDl%?qgcE*zNcCb z;^@@=D3`sqP=8kCS!JP&D>bNO51`D9OK?j2O1ji2CvuiIC}MVAxl7*7sRKUb3w@SU z#i5L7C)Vcky+A0Kya^AiEMbyk21}6xcsC8)x3&gGPhX&Rw3sVmQ z{6YNeyphMJT$Ph72Nm*&%2vrnlh_{7xrT-HJgVRq`RDPOKOh*^RC&Ozyz#q?bNs1o z@F#f`OwP?5Nz%j%4L4S=<&HBkV2<8(AvBn7{tUTih@Kkeq{8yvNJTC?HD+L0b%7Ds zW6-f9;^*o!l*Bt?FX~HN@d$~k`kK5t-w9{O=ryig4`on@pb#SL`hv(=dgnSAbQq6b z@Zo1fpv*iIvQ*X@fmKKGN5CL8VU|=4CCVXExh2BR>Nu`XR=m49VZ>4y{TO$&BVOx& zQSfz+@FKQKx&A~3jlbK#^9jM$yPq9O?Etj7AsQw(nC8RRx|uUmq(y?f!<(R5#0Bn; zST(?0LQItNv}{o1Fr~KECz6_WQ;#rvhA(b2K|M;^W;#R>orKlXa{c>qwIkw? zpjzopK97%zB)}Y$8G80-7k6m_trSQj7{5{TM`6ONe_Ra=ocMZ2o&whsSi{~AhlWv; zQA&(+ z0*$Gav_oCtavC@>Pam*_F-?@M{?}v2Dm9}ntd;51mmbeeZhUKAT)GVT>(q}b~S?P~eC(NrQt*n*~~A0HmbgeL9y zIje)2cRBFV*Ee0^TeYEizfX$^e}NRnLCfx8T{o@+TFE662H!gxQ@qq;uT(~1li2t( z?W@;D;zN)r3+@=u+uotxe09O{s{8XHb|2HqOHO~MRS ztzi;II-8pRp&4!hj)N@KakvMWSQzIJea?5 zm!3)4aTak5sv_ja3ly6keMMfvL6u!3?bJQzo%ke;ld^*$x;o23yD@`M#ptu#(?!hDxmj@e;mHEX6G+WG^?|*I;#nP9 z!+DMdy!RcRe}Z@2)CAj!P&|t^!Qj2u7%&y?LjI6W?O0PcI0uTFKG4HlY$_u%RSf~( zjciCW=X2}NQc_t)K2$q+AG3&7{{c|+AlYB*4&Hxl(w~RuYXcC;lOBiKZ?cdiaQ}29 zi4+4LGSr`C!APGEutI7MmJDY43{+_}aw3QCP*~F!+<#=}r#XBF`@N#Rr&qk}R!vaH z4`a@6XRRXoO9kb(%*Qjs`(z#Y)1{oNH96|jAeZ=orY}VDG^{a2#&qD%<15wc*WzCn zw+|*FFCnZ8{Nz8;5o_8eaMH_4UhOQ!7izJF&VR>+sj?lHku`G_Hu~7%+&1CjmDp3GX~4IJ=O?C&Mc{XEq}Ayrmg6^@Ggxu{l0K9ym)!3DPIbH#+IEKSlVj z`DsCJ(KtWlIR6%z=C%x}$I z=iO7MkHg}N7cYK{YnZ7FQ_F?4FBxw^Wr^?42ERTXL%aeC5liHY8hcXwWmirfS+l!9 z!5s2`>7U2af}67H9_IcfUS75J75S3>>)|LB6Fmn}`dMYT4B5E*#IK-L6hj~U^oLX1 z?Dd7#Of_N$2S0oLC?v({432@oW76DWz8qT7V+{SLzN)A9Sr=Ja7MNi-cU&xy_|woO z1shRz)wIg!nG%^HB92w8tEe}UNGzxZ`q85lciMjj9KCns1_^$Vda5*TX`c2(4*Y)R_(57Qn`sxR_EpB!aw@8} zO-F7dD`$d%SUyp9{2u7~(0k-2lXep7^+foY>W~7A1DJHYsUTu1RwTV&xD^=7LzlDj zLIxJZ`d-pC2}hJ-2Nyi2lufHVSh~8#!SGuYIw%~X-S6ptFKHCwbSlF5F{hM*aSrfR zXV|4<@S%a{VhCvR4o^3GtFYB_hn81y|BijIrRd-3z+pTd>6kcSASMPVOx#{IL>u}d z1&IXI@MxJhWE3a&@^i5@#;?!JUuc+hP9h%*qx`|9lvW(9FBJE5s7YSE4QU*0g_4j+ zl=yGUTB%(+4`|V@QHdZB3-7f6;y&@S2%G8Y6 zHh*jAT~!l$wmfE3VNv~-G4?!AnD$V@f+Ej6(E^=bSo-o<#c}E5hB#06R06zub^rE9x_hr#MGnYvvNz_+yG@BoToDInxF+lCr}l$qT(lsC_4@BUMMg5U;d z?py`kib{T6QAclOnK@yF=h6sKB zhr;GWyc1)zj_f^~RPOHw&(ss)U2~HtZDD58FXBA~cSlU28JDOEs4hFDkyyr+v(bl8 zwytfQP^rpB9yh;u%jPvqWMa`+fU&M(R=t9Sf?kpDPFzM^&hd@Sb2ggs z(8_)qnnpkc&2s-n^}V>J^S;FwcFYX&0nL-x9OWPT)&rlCQ1nQV^R*Ubj%hl&RP9zO zgUX)2?!N?XhkC-gXnzp_(v1X9w}zwo`*g8kd{0atK+2;VA0t$bw64};X`NS1^B6nA zXh197fh5$>{0l71wovrn?0B626&PgW_zxn;M8L?%$jb7cF|r4>v{L$iY+5L4p=;1DV+i+>e>nwqPrni`ui6%}lFBI+Bzt8s;! zKDc;zHSBIL#sQrE-^D0dpra=tm8NFEF-|Q&|0@6jbo{@WamlECBNG#!_yyI#_yRyj zK#ZUiOu$FhHhr;UDhDmDH*g3}(50zdzwgj_togtI9vp z%6+%-fKmijcY1}4#L9pyGz77JTuV07S=xed`h8LTP=-J)4&IOsEsUVt0J;^xOD3oQ z6R!H1{Nqr5NEm>AxNrbtFkjr;dh@-=g4RC}VCiXVnwtUETZC*U0LTMUvbkoS0H=FCML%QX2AZ}fcosn&?&p1EL+!oejEY4)AY>lUK{HhfK$37 z0A9jVef0ceIk5!j41MGMm{-^DcB6j8#smoZP>c>h7(vs7Y-7L1evCoWKST7dw*U^n zXZ1Z}@DTdn-|wHfKT!iRHa1mTzxlro!!$}*wf2gzG5Vet-=> z#^hyu-wl4qUwr;CEW_g;^h43s8993H zJoC>6NVZ?;WuV{own%;D@W$s~Pm^o``c48%BirX!K_Q%C0$Y7$)bPZJVf>A^#j1C& z*(w4yeN-*+vD;M8J`iJ*Z~Wa!$8>LZ4_+KSlJ_v^uLka49mR!_p_QlCgn9=@Kmj;7 z0ypCobkctZAf5pFO>-#MPvIc|G*fJ?(o}@LN#`8^W-aieUG<4!X#Myvn-5?IU_hD$ zKVm#MfT)q(@Ko$RpbzZ&$1Vb^PIS^Q-P2x9dbLBpIceL(Uc^!9mQ?osk6fJIQxnE- zbnkMwA8f~Ov6mV8gtxFhFnz{PbnkKVd-^d*{eUm%o~MV~wN%rp-vD~(0mDc7H>IhU z+=VNEl+@L}`#7ujut%kteZ9NltV90A?yT5C)UkWLZ-90H8oA#bnT`98lpe0XY%D=;=e-HcY&efWkd$Pdp?(WJ3t z3o~u|P)qSkV%)^j1mVm_Tr5K-9aYo5j=^U02L<+#ix!gWjTtjo|0?W(p z)gXhejU_qihXWGbUy=TJa~pg}B*w(hv6|Jw?p5x8FzoakuA>U)%M6b>mB(6ZP4|Lr zvrjQ~A>ku;MW?FvLoL2kX?g)`;m#-ew9+w_Uj}iWfW0A+hiIJ3NhqI}3vW;|@4XBe z`mFzz56<+@y0Tjk?a6A^sAfA@rV%+IX+9kw)YtWM%4P#`d7b#=;f zp5u}M-JtD$g`!Lba4==jR1FbQx7qD!(l+YsLhAQId{$&nyg^S>Er~I$w#pboE2Oym zmmQ8sh@sR@o@`yv6im{j7*@c7&dcn`5eB+aF@Twi2ZK&FQl|@ZIf9PDJCtVmnBRs zkbZ^HTXDc>X#*MKxjXfJ%T#(YZeOayw<0Zy$5bkp7@yJ%&vs-}4J>ZDDNnSVLNhvv z`$v583nAM6Y|G~p?3RqE&>lb(Q)fY7%HgIQ+W>B7`~-dnZq4g*Ux$qA1-mu zH`I1=zMR_DC>Hh*7v&*qtobll!6+|Ojuj0cdtqSplqFoCv8hWZ(w8s8<3}MY$#gT0(Zer3072SXO;x zr*Qg0=^m`;qu%Q6T;E^f@+#+5dPtiN{)@w99V22ke6VJ2n+FYU`mV0!V-AmCda_@Z zaCYfrPpD)m<{zr6n1y)=_ODZSx zVzqB-8_Wf8n@G-Rx zL&hL#vMHSGaB7v zJ6O+T4e1$Ft`(!PqKQJiyX0N+;pb^SZK(d1c}nYd#s)AG$wthX>@ z`ZT2qPmJsaCkK58Ju@9&*=6l`2U=ieJW0~Rf=Al$)KY9tdopLqZMh$lg$HT&lvr6r ztJxa)FuQZ7h+PTQ*U)LWg?XO#p1%%u52#Z~-Wj?PQ5T<JpA9n@d?=RURSo7;$1`DrrkW(eOxl>or=zEY(z57gZp0Z$B}9b0%ApS-H-)#ohrWn^wV8GP%%e9C1dcJ%v~<&aZ~!15TU3}> ztz}A#49EJpn-IRyhGw7Wq=bAF!s^=7ck{P!_jv%zza(vm&KfsH4WUK`e67n%2Q8;? zol#YH%CX8Dyf#3_M8rqt3R6UyV0Uzs#uo-N@pSsqKJnaWz;!*rJMGw>`G^E|Gh+IW zrAN5Ltx4Au71MUZK@lS!qi&;_Onkd37zMfS`sw+mh>}u6`}}oskH2`68y>L@PFaq+ zOrS;Y6;m&N8mmb_h=Ews_rCD%W=df5`a&$<7T`#ICvLeoSk99BX2IvUFz#YWmS<#7 zy0gj_86y&yeu43FoIA3iyMd0ep`ZaOwhTS`{0==Zw{`<+eltFrDDC0cZvQvTS0APO zntXPCq8ALIj^j5b(?N)y%pK*BXcv_d=v6%}sQNeUN1p_hy)>L+dRODscp<-A9=YB> zwkK>fH{G$sF4iRo+B29gW&)0x5 z1|=`Gb?kS9o^-Qb@|^Bpq#J)SC44Xbb^R+acF$V;+6LtyyiWBe%u-B|Vp^(L z^g9uB>!G2SOT*~UVFC0mq&?l&Dy6#5&~>NB*jOlRE2rPVJ1Q^zIfsl;oBp7-81^uQ z!kfmyJ@i>M@Gm;qZ8P2Rg{${J=M%E0?r=LM`LM)VLZ2^;DgJ@7xxg%~)kzx9`n595 zx(y+Y`*PP#rl*38?93KMJTz6E3 zKT=2Rvi>C;5CyZj#a(dZ=k^|*8wAc%)gIQ4d)zCF{u*GSix5G`mWxHfeCcd((NeqA zOCKwGFTomJPhYmE#Ycq+%s{}mk4#+P?50JXEL_(ruZtgCmi7FWZe}2&A)|L_8P$%h z1_|oz5jV*7VH*9mc@l*+xfJV~pS7@v3Vds{CShY59Jcb|hB)k)A07~jrOaW_*S3N=z`K+>~vy`RraUv=AUqDzMAGwx+6Ce_ zJFTuE2>Y77+-V|T;CxE&5R=3GG9G=yBQzd(D7z@zDpka=5)`FwLypfYcU;_-$U2>8nqjm zQNhcmAur~@HOh{P2W+0ZpH`4nz_e}zT3gy)aY@%W%lc>ZF3tYkNFlglsrTBjX3IXC zrajHj{Z4iXp5qpT=f-N03+@j0+~K~OJX zFtu89#XFKXg?*Y#+n~Kr7rbh42afFz_H^OMjBp~6SHgj9%jr+Gn4DGmirmgOh=m2? zc=$y6!$>1^?ATBSJrClb75EjI1A0P;S7-l#Oze47XLW7aXC#`te(}9*XA+}}-X7J# zh1{fs>ZP|m*AxQ_+bq&V^N+~%6!>wibiW1PNxj@tbkbNaOkO% z+|s;1X2P7LumTq?vzb3se=pE|NU&CP&a)HCjqr3sIhqo}B!#U!=Y0T5n`YB)4c(N{ zFzm#Oaq&IA`3$6A>I7m%u{WswgE^acLW6-Umx=t;!OZEckjNsxmf zCzLDe)gh<|+MNtXqgz0@_Xgc;mkKRLlO{Sinx8$Je0$0DMdMsdm`;g4Bst@i0R zl4-e>Hg{BN=x>>p2rUD4r)0TOC}z5)V~VJ|ztbKXt$^!QZnRIg-zC80w;jmqE)n~m zsC2}1I@#4e|w_C$Sf zL(M;>hu?rcM&$WuMY8cKX@PdPzFFOd$wh^fTponO8%UqD#8#@a`9q?ew!NtF5u})` zFjg-OXIMXrjIbKSyCy5S38w_hhz}IF^TJ8{sms!<_<1%(goSDAVdJG^<}V6v`fOen z7K*=7ojE8A{aHvFu(@VzDz*}Pxp9nZQ89rcdkLyEtNUgToQ6t;oC%9d6;Lol3BJ#K z>*`F#D@i`_evJ6dnufQqxE4Q$!u57hC1T7RIx#Azl5Nc0?ZfcEq^YUK?{_6;Lg(%h zc|d{h0rEEq(+7K4g82nIz5yzE4-V2FtZwvB+7Cy3u@;FaQ7S|vYg`XgFxw)W&^G!q zHGMNG4x$vKF#ygZg+dLLKrPf>uS0LnTVeVbn~pP;!b8YUo4h z;BJ%D?;eD71xM2fi>^$-lQcnUG8>E9n@@ZdGd|||3&+X44d{FW3orCSA6MYkwZzdB zb?Nui^)QS+r((`Vm06P&nM9J|5dyGjVb8LM0y&mqhzl7?9ggcjl7E~l=hv)YxoxAgToP@o=Y9n~y&J3rHhhKAwqIBloPoQ3m68!3#5p9!8DJ7>X3r6;0XsW%*AUQfT?dKAv>mDP za5cERT1VA81-XyW#mzMMXQy&J^eIX%P@e#NYOUb*Qle_@` zHLPJ|J()j;goCllW;WPEqyc2O;sW$C8;ZNa8(2s4dD&BOn%X>LnyTe7cFNKqA!YAT ztu-LL_L5S3YT-OK$S8i!%nI`dw!J_DSeYad&O@u3RC|djQSzYc-`Cvf@@~PgYVa5P zDc*T| z$!2t9_1wg)XXWueY`gMX$9)qfnnnr!6D|+?94B78PEs%DFvKxrK}d`^h~e>mr-7{d zngE7ORUQRPN+cjmVb5K_Fs{4ceA1nsMp_qKF3*Jk%Tw}|v5P`QXaMAb_T-eb1$5M| zo8O-L4c?Gq-4ZsJ4?0wbw3W%xFn=l9Hd0*r&zxe0Q8kWf)B-F2X*=zT!)Mo;W_9lN z5NHTw)=MLjwi=y`^Q%!xxg^0Nlf(`^>9!c^`Kpx`w`-vgl2=vaT4i?(lMCO#W^6-n zJ*8l!am9#%@tScrqF2f->;wq_Zuyk66*5x1)&IR}V$VfwGD~iMx%tCjt{?q2MrJy@ zsei$BaS$b`mFF<)F;!@sPgz@pnV2h%8ne}13=hqG9~N>hgQT|K`z<5sce0b@Cp$yT zwuNQ{$~)8*31s9Y$`zo_e~NPwNVAJkM8`8yL9HP5@GLY>FsX)Q>h!|`sVcxdg#wZy z&U%NrX8vR(KqPLpi%^$h>l)$8Zgz}HRZ&O)iih&!t_O%mpK2qZ==P8POn9yy$JYv;+?iJi*qX7IRO~osAHDkv=9sVLLxk!!G)(_EK%H2lQA&xk5P`!y zvOG-fW&qMzx*eu?^K5!+1`9Hl4i%83$AOyALuqI@!34>>KTSHGBLFBYyK8DVexIXI zIzBQ0)>{oG^OQbX#hy0T8fhTJjH13*BW1Ck7E0kMUv|z>idosm2By+hbej%=ok8up zx72*ytTXs7r=6vP&0&**40IXP`yr}BJJy2U>%PyG#5WdT7N>nxn8|NnkPC8Pyf^}Tt*@cheV>;| z9v19`XHfre&`_%MvVmid&?)G3?yFBGb$m%U`Sg_uFaRd?Fmt)YrAsmHeNrKybJa-U zlrkvs-AbXW5DsD&;^LcABf#4S(K&AkrSp*=>$Pd{@>pC%PIQ!*V%!sXHOjky78^&rJTOvk)qd3|{H`3^r&q74KrB}MEAF_W7phn2zxcM|$yMIS`~mB! zglcZ>+#@vvmnXy&>7^;w*LtAoG@}6_y62=~5XB245qFhTg}O^4xK$2;=H?xo_m1}! zeZPP~i$p#3Rh;QKRC8{i=`IBdxU`Y51Nj46Dj4l|ht14ULMsQEV{tgWkIo4Cg}9{I;fgilpxixNG1~=G9m1{$1^Z6irD;FEr0cwoKN0 zId_D#q)6vZ=aI!D)6Kj-Wt83I+$Fi3<;Gy&3OQpaoxw10BG@OH!X19YD(sU&=_yXJ z2y?$-%DEmGDaVM>O_^!sRhhSF0Ws!o8qNZ*1$~#l+Z`h0=3i`I>)p9UcCFKgF8w{{ zObmY=I^kwnT!T*`rB|v}gZnH0>@UK`$ZgHf0A1-IeN|Yr+4>q|%gfjS;@nDzD%JVT z6n@RXpNazdl{Pear(8r5D=YEHE_L5x-jXkOp>)v&aDJvyU@QgK=JZm;yZIsymieg* za>f*26#rrGyfkZBB3lUFi+sF?4b-CMgm10v7nn2?+M6Iy4D)iAItpRWcq3g>kXj@Ttw$w$v|CPYKYjHHi0cR@SWmG`;#Aq=p zp%L$Xz7-X7yqJSRH_&T14(MXypX@634W^yVI2sv-3av>lfz zl04|}lZw5lqPgndBSXLFLtyWaMlO}EwUWA)<3GlvYa*Hm8lAe5kz~F*Hva9b5^01P z5c3tkHaCR_TlNvl`|0Oru^T~sl0NHy=t327!YFj)n(E)quPRcI;v{*9~VJ)(NkV^lrPn&@Of;HSv_Mj%tDk*OnyD)KGXtEA;W3OBRW$~8W$^R+_2@o^`r z9~6?k%iM)2)5inSvJH&-&N?~XNoOSX;$cJ;&d&vS zC4|-A)(aM7JhfHspCw0P4vmz0o@rKeyw<~GRXZL>*n4O?z-keeQ>6-P9%fb14Ah3T zz$hsbgD16F=+P!Z=>dkpVzl83-E-ozaxQ8WWu#E;ygPsQpviK04^uW^jm8nzGiGKU z^e1v9pvwR-D$)i0f~15D=)Cb{HgMu&X)Wgb#%pV;HrGt2u;Joj+t3~9-l#|I!#4_L z9j3#d8$n@YyWpJ(%zVwc)YjmU-Cxr&!GRW*M+k}SZ;z&C05)FcKvYlRbdWwwQ66f3 zV*a3K?Z|fZL4uPM9Zo#6oFB@zbH5=P$?%q{YV0+k-{`kW68vgvAJ{G#x9JtPkF@&V zQZHj6fJw-fg0c9P*_e|60w%q<$pHS{92Jv)ZpoMF{dy`Fr}N9ZKS-vFD_{!Me6Z zN4SBt%mI0}TEr>L$cZwt);}*-f=Hz}^zKWtWCXwIL}ORhrdK&V6`3uZn#M|7IR$Kj&2sJ~=<8y`|wFT3XrQQB!E*W7w&P ztGdTY2Qx}Coz9Qf5O>_S*p6tTQ=d7!d->(fuO zxr?8FG;ZZ(FPuVgk~sz(@>@c8{VD1njdw(L$jKlOGF{ycACr-GThUX3na=}H-;pvX3JBvM&ioHF+8N; zjzN*IdFvgZa_`w>iY206JaD#JfE^(ZH%`}TZO%YMl)DV3oGh#XbaKc6lZaT)vMRy0 zn77ejd+4Eki`h+60Ilp*F)ApYtcd8zB5LheJ_Ll48=lJa2s|BV42wYZrlpF>wb5uV zIQGnV!XFNh-PE{F?R>(GBn-D{h{3rjy&8&5=8meN=G?00Qi*Oy2cQ@+_&1fe;c)fK zeN^^nIsW+@sj|{$!=kF54L|YK+^wy}4o)v6%N@g}(gagKoB)sfa(8x&qTHAFsw5a# zZ<4`(%iucj&9P|U@NA3_iC-diRJ%p4OJX}h0wiQuteN=;3c)*yAZWjy2u5 zmwqmz$XUnS%b9bmEoVFyF!U5<;IR<%CLRlD2spTI6A zWHw9~92qdvmHeJ!M-$XIsLbDI)tm@}Ny+*j<_Tx%Rsl$+_&d>{&4ZE7+|4RG(&Xx41#~p{Q=yD#Han}XR=vz6IqzTbzjH7ItsM=mCEympbW1Q z)wE98^23kXekeJl9_v3y_T%n-9dcE$Q`&FOKIHHj$V*{;=A; zfq8Hdb9ZcCE0D;)n4m7Qk!DH7wLNOW68Gy_Z9#!Cu01o%*$zN6F3xLMe_1G zTr71OzELs*Z}bM-l6XW{)&cWkRC8hqSQ(n>vhKlmx>h;BOnqg^!RO{`k-O(dcjPqJ z6^E&o3wcz_i|RD;V#0$|wjzkRr;}~gn|t{J!d9N;YzU!SQEYc`m{dO@`&U+RTXK`= zd5gbyvAlJNIt8mkt>~~$%wMf7)olAXTp*B3=erhm6bO8Rhkn%&jVY^rY^2dMtgS+( zLL2M9^(`M5WT5&YQ@l7GXml0F*zttLOS&$2Dk$k7w+yFLO#q44UYZ^up*Zo;JzLwC zjDYf}^s`ep1VOwG-Hp-0jTv-9C#*!ojTi+eU1(H4(VPsiNU3BBA3ds`iPug*X_~yF z$xE*JubKeM=5SunbQhDCNn9*q^Y2|jcAAZmozT-u%CcZC9X4w+&f1UN&}8`PQBE)y zzcU{-43yU$-RrFo4~)c>*IjZUqOwBV0Z0LqbaUuDV`Xfng>!P}^WK+jFYBpaKSgEw z-d@cyS|L7a;Of**jrM3D5ShGLCe&4-u_TS@ULg&0Qg(_vTrVJ{-4#E$QmHm<;RN^2 z3bB{dwEH@c)-YQzUZrc1bOqBYNgf0edf+>meY(LU<%#L=+-q_^2PA5y;}YN!uT~Q9 zE_J584gCq?@zG&W{PXj0A$rXX8?M3C5e?gbFNBc&jOMNHmJ2LxjwbI&`sJO4W6pwh z4nG_R0NsgmSlI3saxdO@`xznwZb=J>G;TR3`4A&Oo}JI#1CB}>M9ce2z~nn+?Md`W zj&|8-V(@~nmZrkDOEL()Zd8u{J^?`Trzx_{UVZR$1n!YATe;}i(QgkK6e_lOBT*Ia zkSug=m(S?#dLI!fv0UWh$4ueDqWv`yTYc+6<_?4|8FI22{~EwkR-g#g0$AmIP^P@QK>G z&}BGNal&GDyX2=F^ryG#qE(Df`57h0RkNz?_r&Ic@Dp|i`@Q`~^CkH&!@Gqn?LP7O zt<9bLNzB5x*An2hvCZ8xiMkhYTq>YMx+5yjz_(T+OCptN2)mt^(PvR_+O!rc>tr}5 zz&>at7$|CJ?@TCMZa5fuZNu?i<^ek|)w;LXLZ8IB08 zjUt7_0tmR31s>ll7b(Y>7`dNSLzU{e3xjDza_M^?F$vQy@qyM}pvtBe)elM&1@DmF zvhNT(vGrd#;+Q`!KPuIjMwj*SLkJeiSM|`dB$(jWEalQRtFI@z?M*xrC#+WjZ)8?J zJ{j%fWJc4FEnC)Q*tuTIgBK2Aa5Glk&sR^ZaIgz@#J}U0Dl|3KTlN4nl9C(sXh;?dhKZ6m(#jr zqZTu%iHT?25qpO~obl+?>fvmjdRhqT8_Ie-e3BG9oA?6R3DZEXj>0wr-QQOG*klaQ+?nN& z9e*FAEeRQ@a8=A}L6elIb1de??>?Xpa!0tAbG^_vcy zlXYv{wu}1?jdknMU9L3*2J)bjh=QD^D!x{eDtNH^yG-=g2{Ubfm47Y)MUA$?sY{Nrv=xh+2 zY-An1#(Imu$Zf=NR@(}%Z|xfojGDtf$Zj9aO5x9FG)+S5@Z2R9sHW`+w>7*cTJWrC zl2`(a%uXhtntkDQC!`EvpfUAT^3M1KUI{AP(R_mRhPn_xk(ft&NBW@Mq1vKTx(Wpz zi|40b6%OX0d(^yWO0U6A;hP2W|8@_=09-z1Z9sf2l2GJ#-8-cG!p zkiJrap|C&32<@JAlBs5(r<1s>vEpV*SSoB$V-P*c4t=!*y2g|0E6Po?J&;kvHtF6^ z)#s0iCj-I^-=G>>Zvt$}RK4H2^o@;DPXoum*}l~!awd!&dM8&fJ#M#%=im#YSlsW= zr+j+qT;{dRTt9>74esQ-#ulRVTqGB$tQ8P68Ts2EkiVE|wQwer&<2&BzNlp?>w zm@0&6(ys z`~`%e-01i(kpmXS{}MT1V&q`>PsV_WfP<0!za|biS=bo=H*i1zMK5My?QG&mKrd!( z;A|pdVq|A*0>#G%<>c&WVqgR1z7f;>&rxiR%`OKa5k^7E)nQQhFJAyciOHbPz@}da zic%!4B!wWT)FCYNSMBdjQUVwx;C|*u7ktm{uiwmTc6Q^n+w*Nl?Pbp&3};yPBWnaT z1QQUPVc-MMNMMvEJRSs4fB>K_0RnzN=t*D-D6n^NnZ5^vgUDc_y#qf?iZ-D>iY6Jv zXrWCD!aV>Nb_@U#0079SAd#T}0RVmkiWhw0;7Sew#4EUFK=XT`B}99O1bAO{hw>NzfOT|Le>5D{%9B`@D4&|O<;onU=UUmAji*oglnYN ziWFuJe0=cm@Va%#3F!Nl3xP0JQ#s)r9sW8-uX6zz(2!iNG*REPz}y2yggC)BIpt{(hdo0QZ4Eu&;5i zwE_xnc4l?WtOMhiFt33F*8nXF7$A9tRpU_)A`ZZP_L+L2`WQ$7FW{X)`3!Za8+&fY z`u+`BcmUC4Z}7ZD&D2YnAxEM@2E7yy-%vp}4M@%5oYHrIZL3=U7G%pk%#+64bsQXBUBcL{pc>q&CiVW~RWJ73N6A3^2??C-aw2k584?u2)6B4I)52e{(_RQ?BRs zFQ@N|pIQ*`-EMso;#qnKz*?>N77PVQlbBz?PcHa(>*VjQ_iyBbANKt(t;9Mk*k`rr zZ}snQS-+e@+A2TTS-gvI{-_>wfG*J6Zw8j&PgND#5ZJ}ZQ?Di~3Pv}WqdoUpuT3yf za()g1whqO_#?Pz%7b5nLCL;z4+`K43e(wzm06YZ57e20MZ58hPD;N@QT(2s^)5e#Z z7-<{pz{#rbJv1b6UrmiZJrIFs^jk~dPv0pp{LSLzOi~s;%vQ==)(mQ$t6u=uyO+11B zZ9l7!8GD!5nYY+45hDwb91XIt&G!WhF2$EPhh~xn`d!^XZZKlDesnI%u9!?(%sM{5bQB+H~-#xqfa- zVJ%|pzcXPnvPbolgJUnB(M6P>dupJzP3^)jb8&u~BUfx|YR*c}UUedN7Jv74Z}C75 zAnVD}aD+9adECm}cbqlJ#83MhAJX;ywmlMjeaaTrO0nEnc>+Qu@WX*N5R)BgimMU( z(kNIzoa!xeVeJBPX-@G=Mj-Su|5*+;vTC0CHvTJgVU1jVKGIt;zhG!c3D8>K*{D^z zdws9tnidqfY2s(X;v+1Y&|Gs=wC0N*S8W=V3UTSA0)p3ERtA8$^7!g_ek*-6c^oR9 zv78nU-jLgRc%IDeTjYIph^~2&MRhb1Ojk1J^C@;!bHP2kZlDP}DcHv_xe70} zbV|Pl+{4c6H)0!dwHh<{;gI?%rXiqkoS+yihP?g_9xVVnT%)wGypUgX*OUdpBhETl zlv#)a7y#gBPEP3up9(ZQ}u z${S{j9E7zoVOxRnXZNp2f0TJUKUDpE_Z37SuO5Xo0XG);?V-6bj(<{n>(G@S$?T+4 zFZ()t=~`ll9WUNi-k4>12&~Ei{5$VDZn8T(eei8;$R!*cgxMN<0o7;5j-S* z`ydFkW>3dDCGg6~bR51wwShF=s zpyoNn@s14s?FM=D-d~M|iydnoF2m)j&HH6J{K`B&1Nm^gM6$E_(5>>S zqtq$T7d9@l3`NTu}=3

H< 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 DIi=yz literal 0 HcmV?d00001 diff --git a/talk-archive/2022-27-rust-and-graphql-for-backend/talk.tex b/talk-archive/2022-27-rust-and-graphql-for-backend/talk.tex new file mode 100644 index 0000000..01ac38a --- /dev/null +++ b/talk-archive/2022-27-rust-and-graphql-for-backend/talk.tex @@ -0,0 +1,256 @@ +\documentclass{beamer} +\usepackage{minted} +\usepackage{forest} + +\title{Rust and GraphQL for backend} +\subtitle{Schema creation and basic features} +\author{Maciek ZwoliƄski} +\date{June 2022} + +\begin{document} + \frame { + \maketitle + } + \note { + GraphQL is a powerful and strongly typed way to expose your services for the clients. It is more and more often seen in various backends. + + During this talk we will learn what is graphql and how to use it. We will play with it's basic features and try to create our own graphs of data. + } + \note { + Not-really-sure-what developer trying to take Rust for everything. I'm currently working in SatRev, developing ground and flight software for managing nanosatellites. + Also cats, linux and pizza lover. + } + \note { + GraphQL is a query language for describing the resources you want to get and also all the machinery for executing those queries in your backend. + It was created by facebook for their internal use and then open sourced in 2015. + Since then it gained some popularity and was implemented in many popular programming languages. + } + \begin{frame}{Graphql Schema} + \centering + \begin{forest} + [Root + [Query + [users] + [userById] + ] + [Mutation (optional) + [addUser] + [removeUser] + ] + [Subscription (optional) + [userRegistered] + ] + ] + \end{forest} + \end{frame} + \begin{frame}[fragile] + \scriptsize + \begin{minted}{rust} + struct User { + id: usize, + name: String, + surname: String, + age: u32, + car_id: Optional, // references car.id + } + + enum Brand { + Fiat, + Ford, + Opel, + } + + struct Car { + id: usize, + brand: Brand, + model: String, + year: u32, + owner_id: usize, // references user.id + } + \end{minted} + \end{frame} + \note { + Do you know REST? + + Consider having some resources, let's say users and cars. We could define them as follows: + + We're gonna use Rust for our definitions. We'll also make it look like if we had some relational database under the hood even tho there will be none during this talk :) + + We'd probably want to have one to many relation for the user and his cars but let's just keep it simple at this moment. + } + \begin{frame}[fragile]{REST API}{Overfetching} + \begin{columns} + \begin{column}{0.48\textwidth} + \scriptsize + \begin{minted}[autogobble]{javascript} + GET /users -> [ + { + "id": 0, // this is unused + "name": "Will", + "surname": "Smith", + "age": 32, + "car_id": null // so is this + }, + ... + ] + \end{minted} + \end{column} + \begin{column}{0.48\textwidth} + Users: + \begin{itemize} + \item Will Smith, 32 years + \item ... + \end{itemize} + \end{column} + \end{columns} + \end{frame} + \begin{frame}[fragile]{REST API}{Underfetching} + \begin{columns} + \begin{column}{0.48\textwidth} + \scriptsize + \begin{minted}[autogobble]{javascript} + GET /users -> [ + { + "name": "Will", + "car_id": 1, + ... // unused + }, + { + "name": "Agnieszka", + "car_id": 3, + ... // unused + }, + ... + ] + GET /cars/1 -> { + "brand": "Opel", + "model": "Astra", + "year": 1999 // unused + } + GET /cars/3 -> { + "brand": "Ford", + "model": "Focus", + "year": 2010 // unused + } + \end{minted} + \end{column} + \begin{column}{0.48\textwidth} + Users: + \begin{itemize} + \item Will, Opel Astra + \item Agnieszka, Ford Focus + \item ... + \end{itemize} + \end{column} + \end{columns} + \end{frame} + \begin{frame}[fragile]{GraphQL API}{Declarative fetching} + \begin{columns} + \begin{column}{0.2\textwidth} + \scriptsize + \begin{minted}[autogobble]{javascript} + query { + users { + name, + surname, + age + } + } + + + + query { + users { + name, + car { + brand, + model + } + } + } + + \end{minted} + \end{column} + \begin{column}{0.35\textwidth} + \scriptsize + \begin{minted}[autogobble]{javascript} + "users": [ + { + "name": "Will", + "surname": "Smith", + "age": 32, + }, + ... + ] + + + "users": [ + { + "name": "Will", + "car": { + "brand": "Opel" + "model": "Astra" + } + }, + ... + ] + \end{minted} + \end{column} + \begin{column}{0.44\textwidth} + \footnotesize + Users: + \begin{itemize} + \item Will Smith, 32 years + \item ... + \end{itemize} + \vspace{5.5em} + Users: + \begin{itemize} + \item Will, Opel Astra + \item ... + \end{itemize} + \vspace{5em} + \end{column} + \end{columns} + \end{frame} + \begin{frame}[fragile]{REST API}{Overfetching/Underfetching} + \begin{minted}{javascript} + GET /users_with_cars ? + + GET /users?fields=name,surname ? + + GET /users?cars=true&fields=name,surname + &car_fields=brand,model ? + \end{minted} + \end{frame} + \note { + Should we make an endpoint users\_with\_cars which will have different model of what it returns? Or maybe cars\_with\_owners would better suit our potential api consumers? + + Or maybe we could add optional query params to control how fetched resources look like? + + But this would be a complete mess when writing api documentation and having many different possible schemas returned from one endpoint + } + \frame { + Server side crates: + + \quad- \underline{async-graphql} + + \quad- juniper + + \vspace{0.5em} + + \small{both integrates well with popular backend crates like actix-web, axum, rocket, warp...} + + \vspace{2em} + + Client side crates: + + \quad- graphql\_client + + \quad- cynic + + \vspace{0.5em} + + \small{you can choose from different designs of strong typing but subscriptions are not quite there yet} + } +\end{document}