From cf4a79a126132eb30e368bdf2277a89278ae2a9b Mon Sep 17 00:00:00 2001 From: Bryn Cooke Date: Wed, 11 Oct 2023 09:12:48 +0100 Subject: [PATCH] Fix defaulting in router config (#4010) There are two types of serde defaulting: * container * field Container level defaulting will use an instance of the default implementation and take missing fields from it. Field level defaulting uses either the default implementation or optionally user supplied function to initialize missing fields. When using field level defaulting it is essential that the Default implementation of a struct exactly match the serde annotations. A test checks to ensure that field level defaulting is not used in conjunction with a Default implementation and gives guidance on resolution. *Description here* Fixes #4000 --- **Checklist** Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review. - [ ] Changes are compatible[^1] - [ ] Documentation[^2] completed - [ ] Performance impact assessed and acceptable - Tests added and passing[^3] - [ ] Unit Tests - [ ] Integration Tests - [ ] Manual Tests **Exceptions** *Note any exceptions here* **Notes** [^1]: It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this. [^2]: Configuration is an important part of many changes. Where applicable please try to document configuration examples. [^3]: Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions. Co-authored-by: bryn --- Cargo.lock | 250 +++++++++++------- apollo-router/Cargo.toml | 1 + apollo-router/src/configuration/mod.rs | 15 +- .../src/configuration/persisted_queries.rs | 9 +- ...nfiguration__tests__subgraph_override.snap | 2 +- apollo-router/src/configuration/tests.rs | 112 +++++++- apollo-router/src/context/mod.rs | 4 +- .../src/plugins/authentication/mod.rs | 13 +- apollo-router/src/plugins/coprocessor/mod.rs | 2 +- apollo-router/src/plugins/subscription.rs | 7 +- apollo-router/src/plugins/telemetry/apollo.rs | 39 +-- apollo-router/src/plugins/telemetry/config.rs | 11 +- .../plugins/telemetry/metrics/prometheus.rs | 14 +- .../src/plugins/telemetry/tracing/mod.rs | 14 +- 14 files changed, 282 insertions(+), 211 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30c7dce9b3..ab02a2a6cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -365,6 +365,7 @@ dependencies = [ "rustls-pemfile", "schemars", "serde", + "serde_derive_default", "serde_json", "serde_json_bytes", "serde_urlencoded", @@ -515,8 +516,8 @@ dependencies = [ "mime", "mime_guess", "nom", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "serde", "syn 2.0.29", ] @@ -716,8 +717,8 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -733,8 +734,8 @@ version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -1322,8 +1323,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3907aac66c65520545ae3cb3c195306e20d5ed5c90bfbb992e061cf12a104d0" dependencies = [ "lazy_static", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "str_inflector", "syn 2.0.29", "thiserror", @@ -1523,8 +1524,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" dependencies = [ "heck 0.4.1", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -1923,7 +1924,7 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" dependencies = [ - "quote", + "quote 1.0.33", "syn 1.0.109", ] @@ -1971,8 +1972,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2042,7 +2043,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c65c2ffdafc1564565200967edc4851c7b55422d3913466688907efd05ea26f" dependencies = [ "deno-proc-macro-rules-macros", - "proc-macro2", + "proc-macro2 1.0.66", "syn 2.0.29", ] @@ -2053,8 +2054,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3047b312b7451e3190865713a4dd6e1f821aed614ada219766ebc3024a690435" dependencies = [ "once_cell", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2140,8 +2141,8 @@ dependencies = [ "once_cell", "pmutil", "proc-macro-crate", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "regex", "strum", "strum_macros", @@ -2210,8 +2211,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -2221,8 +2222,8 @@ version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53e0efad4403bfc52dc201159c4b842a246a14b98c64b55dfd0f2d89729dfeb8" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2233,8 +2234,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -2335,8 +2336,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2668,8 +2669,8 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2824,8 +2825,8 @@ version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -2941,8 +2942,8 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba330b70a5341d3bc730b8e205aaee97ddab5d9c448c4f51a7c2d924266fa8f9" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -3032,8 +3033,8 @@ dependencies = [ "graphql-parser", "heck 0.4.1", "lazy_static", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "serde", "serde_json", "syn 1.0.109", @@ -3046,7 +3047,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00bda454f3d313f909298f626115092d348bc231025699f557b27e248475f48c" dependencies = [ "graphql_client_codegen", - "proc-macro2", + "proc-macro2 1.0.66", "syn 1.0.109", ] @@ -3699,8 +3700,8 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8edfc11b8f56ce85e207e62ea21557cfa09bb24a8f6b04ae181b086ff8611c22" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "regex", "syn 1.0.109", ] @@ -3811,8 +3812,8 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b43a5344be08996a47cb02b1ddc737119578a1cd01ae60d91541864df5926db9" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -3998,8 +3999,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -4655,8 +4656,8 @@ checksum = "68ca01446f50dbda87c1786af8770d535423fa8a53aec03b8f4e3d7eb10e0929" dependencies = [ "pest", "pest_meta", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -4698,8 +4699,8 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -4794,8 +4795,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52a40bc70c2c58040d2d8b167ba9a5ff59fc9dab7ad44771cfde3dcfde7a09c6" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -4869,7 +4870,7 @@ version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.66", "syn 1.0.109", ] @@ -4899,8 +4900,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", "version_check", ] @@ -4911,8 +4912,8 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "version_check", ] @@ -4922,6 +4923,15 @@ version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + [[package]] name = "proc-macro2" version = "1.0.66" @@ -5001,8 +5011,8 @@ checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -5035,13 +5045,22 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.66", ] [[package]] @@ -5387,8 +5406,8 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db74e3fdd29d969a0ec1f8e79171a6f0f71d0429293656901db382d248c4c021" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -5520,8 +5539,8 @@ version = "6.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b94b81e5b2c284684141a2fb9e2a31be90638caf040bf9afbc5a0416afe1ac" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "rust-embed-utils", "syn 2.0.29", "walkdir", @@ -5673,8 +5692,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3904a4ba0a9d0211816177fd34b04c7095443f8cdacd11175064fe541c8fe2" dependencies = [ "heck 0.3.3", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -5715,8 +5734,8 @@ version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e85e2a16b12bdb763244c69ab79363d71db2b4b918a2def53f80b02e0574b13c" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "serde_derive_internals", "syn 1.0.109", ] @@ -5819,19 +5838,31 @@ version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] +[[package]] +name = "serde_derive_default" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a99485caec5e9d587a3780cd6ed06a546f9924071315ab7280e148536e7ab148" +dependencies = [ + "quote 0.6.13", + "regex", + "syn 0.15.44", + "thiserror", +] + [[package]] name = "serde_derive_internals" version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -6203,8 +6234,8 @@ checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck 0.3.3", "proc-macro-error", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -6224,8 +6255,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" dependencies = [ "heck 0.4.1", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "rustversion", "syn 2.0.29", ] @@ -6248,14 +6279,25 @@ dependencies = [ "tracing", ] +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", +] + [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "unicode-ident", ] @@ -6265,8 +6307,8 @@ version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "unicode-ident", ] @@ -6370,8 +6412,8 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9601d162c1d77e62c1ea0bc8116cd1caf143ce3af947536c3c9052a1677fe0c" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -6402,8 +6444,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f972445f2c781bb6d47ee4a715db3a0e404a79d977f751fd4eb2b0d44c6eb9d" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -6437,8 +6479,8 @@ version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -6611,8 +6653,8 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -6764,9 +6806,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6fdaae4c2c638bb70fe42803a26fbd6fc6ac8c72f5c59f67ecc2a2dcabf4b07" dependencies = [ "prettyplease", - "proc-macro2", + "proc-macro2 1.0.66", "prost-build", - "quote", + "quote 1.0.33", "syn 1.0.109", ] @@ -6858,8 +6900,8 @@ version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -6962,7 +7004,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "258bc1c4f8e2e73a977812ab339d503e6feeb92700f6d07a6de4d321522d5c08" dependencies = [ "lazy_static", - "quote", + "quote 1.0.33", "syn 1.0.109", ] @@ -6987,8 +7029,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0a91713132798caecb23c977488945566875e7b61b902fb111979871cbff34e" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] @@ -7018,8 +7060,8 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6179333b981641242a768f30f371c9baccbfcc03749627000c500ab88bf4528b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -7048,8 +7090,8 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e60147782cc30833c05fba3bab1d9b5771b2685a2557672ac96fa5d154099c0e" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 1.0.109", ] @@ -7157,6 +7199,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "universal-hash" version = "0.5.1" @@ -7346,8 +7394,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", "wasm-bindgen-shared", ] @@ -7370,7 +7418,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote", + "quote 1.0.33", "wasm-bindgen-macro-support", ] @@ -7380,8 +7428,8 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -7691,8 +7739,8 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.33", "syn 2.0.29", ] diff --git a/apollo-router/Cargo.toml b/apollo-router/Cargo.toml index e40dc0fa84..0a9d52f24f 100644 --- a/apollo-router/Cargo.toml +++ b/apollo-router/Cargo.toml @@ -187,6 +187,7 @@ schemars = { version = "0.8.15", features = ["url"] } shellexpand = "3.1.0" sha2 = "0.10.8" serde = { version = "1.0.188", features = ["derive", "rc"] } +serde_derive_default = "0.1" serde_json_bytes = { version = "0.2.2", features = ["preserve_order"] } serde_json = { version = "1.0.107", features = [ "preserve_order", diff --git a/apollo-router/src/configuration/mod.rs b/apollo-router/src/configuration/mod.rs index 1e7fe18146..e003b92c3d 100644 --- a/apollo-router/src/configuration/mod.rs +++ b/apollo-router/src/configuration/mod.rs @@ -667,8 +667,7 @@ impl Supergraph { /// Configuration for operation limits, parser limits, HTTP limits, etc. #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] -#[serde(deny_unknown_fields)] -#[serde(default)] +#[serde(deny_unknown_fields, default)] pub(crate) struct Limits { /// If set, requests with operations deeper than this maximum /// are rejected with a HTTP 400 Bad Request response and GraphQL error with @@ -776,16 +775,13 @@ pub(crate) struct Router { /// Automatic Persisted Queries (APQ) configuration #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub(crate) struct Apq { /// Activates Automatic Persisted Queries (enabled by default) - #[serde(default = "default_apq")] pub(crate) enabled: bool, - #[serde(default)] pub(crate) router: Router, - #[serde(default)] pub(crate) subgraph: SubgraphConfiguration, } @@ -803,17 +799,12 @@ impl Apq { /// Subgraph level Automatic Persisted Queries (APQ) configuration #[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub(crate) struct SubgraphApq { /// Enable - #[serde(default = "default_subgraph_apq")] pub(crate) enabled: bool, } -fn default_subgraph_apq() -> bool { - false -} - fn default_apq() -> bool { true } diff --git a/apollo-router/src/configuration/persisted_queries.rs b/apollo-router/src/configuration/persisted_queries.rs index 42a9ac2416..bc3af1c545 100644 --- a/apollo-router/src/configuration/persisted_queries.rs +++ b/apollo-router/src/configuration/persisted_queries.rs @@ -4,18 +4,15 @@ use serde::Serialize; /// Persisted Queries (PQ) configuration #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub struct PersistedQueries { /// Activates Persisted Queries (disabled by default) - #[serde(default = "default_pq")] pub enabled: bool, /// Enabling this field configures the router to log any freeform GraphQL request that is not in the persisted query list - #[serde(default = "default_log_unknown")] pub log_unknown: bool, /// Restricts execution of operations that are not found in the Persisted Query List - #[serde(default)] pub safelist: PersistedQueriesSafelist, } @@ -38,14 +35,12 @@ impl PersistedQueries { /// Persisted Queries (PQ) Safelisting configuration #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub struct PersistedQueriesSafelist { /// Enables using the persisted query list as a safelist (disabled by default) - #[serde(default = "default_safelist")] pub enabled: bool, /// Enabling this field configures the router to reject any request that does not include the persisted query ID - #[serde(default = "default_require_id")] pub require_id: bool, } diff --git a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__subgraph_override.snap b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__subgraph_override.snap index e7aff43067..be15b105f8 100644 --- a/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__subgraph_override.snap +++ b/apollo-router/src/configuration/snapshots/apollo_router__configuration__tests__subgraph_override.snap @@ -17,7 +17,7 @@ expression: schema "all": { "description": "options applying to all subgraphs", "default": { - "a": false, + "a": true, "b": 0 }, "type": "object", diff --git a/apollo-router/src/configuration/tests.rs b/apollo-router/src/configuration/tests.rs index 3f7f1f10bf..b01b139378 100644 --- a/apollo-router/src/configuration/tests.rs +++ b/apollo-router/src/configuration/tests.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fs; +use std::path::Path; use std::path::PathBuf; use http::Uri; @@ -773,16 +774,17 @@ struct TestSubgraphOverride { subgraph: SubgraphConfiguration, } -#[derive(Debug, Clone, Default, Deserialize, Serialize, JsonSchema)] +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(default)] struct PluginConfig { - #[serde(default = "set_true")] a: bool, - #[serde(default)] b: u8, } -fn set_true() -> bool { - true +impl Default for PluginConfig { + fn default() -> Self { + Self { a: true, b: 0 } + } } #[test] @@ -853,3 +855,103 @@ fn test_subgraph_override_json() { // since products did not set the `a` field, it should take the override value from `all` assert!(!data.subgraph.subgraphs.get("products").unwrap().a); } + +#[test] +fn test_deserialize_derive_default() { + // There are two types of serde defaulting: + // + // * container + // * field + // + // Container level defaulting will use an instance of the default implementation and take missing fields from it. + // Field level defaulting uses either the default implementation or optionally user supplied function to initialize missing fields. + // + // When using field level defaulting it is essential that the Default implementation of a struct exactly match the serde annotations. + // + // This test checks to ensure that field level defaulting is not used in conjunction with a Default implementation + + // Walk every source file and check that #[derive(Default)] is not used. + let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + path.push("src"); + fn it(path: &Path) -> impl Iterator { + WalkDir::new(path).into_iter().filter_map(|e| e.ok()) + } + + // Check for derive where Deserialize is used + let deserialize_regex = + Regex::new(r"^\s*#[\s\n]*\[derive\s*\((.*,)?\s*Deserialize\s*(,.*)?\)\s*\]\s*$").unwrap(); + let default_regex = + Regex::new(r"^\s*#[\s\n]*\[derive\s*\((.*,)?\s*Default\s*(,.*)?\)\s*\]\s*$").unwrap(); + + let mut errors = Vec::new(); + for source_file in it(&path).filter(|e| e.file_name().to_string_lossy().ends_with(".rs")) { + // Read the source file into a vec of lines + let source = fs::read_to_string(source_file.path()).expect("failed to read file"); + let lines: Vec<&str> = source.lines().collect(); + for (line_number, line) in lines.iter().enumerate() { + if deserialize_regex.is_match(line) { + // Get the struct name + if let Some(struct_name) = find_struct_name(&lines, line_number) { + let manual_implementation = format!("impl Default for {} ", struct_name); + + let has_field_level_defaults = + has_field_level_serde_defaults(&lines, line_number); + let has_manual_default_impl = + lines.iter().any(|f| f.contains(&manual_implementation)); + let has_derive_default_impl = default_regex.is_match(line); + + if (has_manual_default_impl || has_derive_default_impl) + && has_field_level_defaults + { + errors.push(format!( + "{}:{} struct {} has field level #[serde(default=\"...\")] and also implements Default. Either use #[derive(serde_derive_default::Default)] at the container OR move the defaults into the Default implementation and use #[serde(default)] at the container level", + source_file + .path() + .strip_prefix(path.parent().unwrap().parent().unwrap()) + .unwrap() + .to_string_lossy(), + line_number + 1, + struct_name)); + } + } + } + } + } + + if !errors.is_empty() { + panic!("Serde errors found:\n{}", errors.join("\n")); + } +} + +fn has_field_level_serde_defaults(lines: &[&str], line_number: usize) -> bool { + let serde_field_default = Regex::new( + r#"^\s*#[\s\n]*\[serde\s*\((.*,)?\s*default\s*=\s*"[a-zA-Z0-9_:]+"\s*(,.*)?\)\s*\]\s*$"#, + ) + .unwrap(); + lines + .iter() + .skip(line_number + 1) + .take(500) + .take_while(|line| !line.contains('}')) + .any(|line| serde_field_default.is_match(line)) +} + +fn find_struct_name(lines: &[&str], line_number: usize) -> Option { + let struct_enum_union_regex = + Regex::new(r"^.*(struct|enum|union)\s([a-zA-Z0-9_]+).*$").unwrap(); + + lines + .iter() + .skip(line_number + 1) + .take(5) + .filter_map(|line| { + struct_enum_union_regex.captures(line).and_then(|c| { + if c.get(1).unwrap().as_str() == "struct" { + Some(c.get(2).unwrap().as_str().to_string()) + } else { + None + } + }) + }) + .next() +} diff --git a/apollo-router/src/context/mod.rs b/apollo-router/src/context/mod.rs index 83bdb2bc80..f55571dd66 100644 --- a/apollo-router/src/context/mod.rs +++ b/apollo-router/src/context/mod.rs @@ -39,17 +39,17 @@ pub(crate) type Entries = Arc>; /// plugins should restrict themselves to the [`Context::get`] and [`Context::upsert`] /// functions to minimise the possibility of mis-sequenced updates. #[derive(Clone, Deserialize, Serialize, Derivative)] +#[serde(default)] #[derivative(Debug)] pub struct Context { // Allows adding custom entries to the context. entries: Entries, - #[serde(skip, default)] + #[serde(skip)] pub(crate) private_entries: Arc>, /// Creation time #[serde(skip)] - #[serde(default = "Instant::now")] pub(crate) created_at: Instant, #[serde(skip)] diff --git a/apollo-router/src/plugins/authentication/mod.rs b/apollo-router/src/plugins/authentication/mod.rs index 2c8d81fefc..5874dd0284 100644 --- a/apollo-router/src/plugins/authentication/mod.rs +++ b/apollo-router/src/plugins/authentication/mod.rs @@ -110,7 +110,7 @@ struct AuthenticationPlugin { subgraph: Option, } -#[derive(Clone, Debug, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Deserialize, JsonSchema, serde_derive_default::Default)] #[serde(deny_unknown_fields)] struct JWTConf { /// List of JWKS used to verify tokens @@ -135,17 +135,6 @@ struct JwksConf { #[serde(default)] algorithms: Option>, } - -impl Default for JWTConf { - fn default() -> Self { - Self { - jwks: Default::default(), - header_name: default_header_name(), - header_value_prefix: default_header_value_prefix(), - } - } -} - /// Authentication #[derive(Clone, Debug, Default, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] diff --git a/apollo-router/src/plugins/coprocessor/mod.rs b/apollo-router/src/plugins/coprocessor/mod.rs index 50c768f9df..3b42ec383a 100644 --- a/apollo-router/src/plugins/coprocessor/mod.rs +++ b/apollo-router/src/plugins/coprocessor/mod.rs @@ -254,7 +254,7 @@ pub(super) struct SubgraphResponseConf { } /// Configures the externalization plugin -#[derive(Clone, Debug, Default, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Deserialize, JsonSchema)] #[serde(deny_unknown_fields)] struct Conf { /// The url you'd like to offload processing to diff --git a/apollo-router/src/plugins/subscription.rs b/apollo-router/src/plugins/subscription.rs index afd7e5a6d1..ee8023c368 100644 --- a/apollo-router/src/plugins/subscription.rs +++ b/apollo-router/src/plugins/subscription.rs @@ -64,7 +64,6 @@ pub(crate) struct SubscriptionConfig { pub(crate) mode: SubscriptionModeConfig, /// Enable the deduplication of subscription (for example if we detect the exact same request to subgraph we won't open a new websocket to the subgraph in passthrough mode) /// (default: true) - #[serde(default = "enable_deduplication_default")] pub(crate) enable_deduplication: bool, /// This is a limit to only have maximum X opened subscriptions at the same time. By default if it's not set there is no limit. pub(crate) max_opened_subscriptions: Option, @@ -72,16 +71,12 @@ pub(crate) struct SubscriptionConfig { pub(crate) queue_capacity: Option, } -fn enable_deduplication_default() -> bool { - true -} - impl Default for SubscriptionConfig { fn default() -> Self { Self { enabled: true, mode: Default::default(), - enable_deduplication: enable_deduplication_default(), + enable_deduplication: true, max_opened_subscriptions: None, queue_capacity: None, } diff --git a/apollo-router/src/plugins/telemetry/apollo.rs b/apollo-router/src/plugins/telemetry/apollo.rs index f1e047ad64..79e53f6a58 100644 --- a/apollo-router/src/plugins/telemetry/apollo.rs +++ b/apollo-router/src/plugins/telemetry/apollo.rs @@ -35,71 +35,54 @@ pub(crate) const ENDPOINT_DEFAULT: &str = pub(crate) const OTLP_ENDPOINT_DEFAULT: &str = "https://usage-reporting.api.apollographql.com"; #[derive(Clone, Deserialize, JsonSchema, Debug)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub(crate) struct Config { /// The Apollo Studio endpoint for exporting traces and metrics. #[schemars(with = "String", default = "endpoint_default")] - #[serde(default = "endpoint_default")] pub(crate) endpoint: Url, /// The Apollo Studio endpoint for exporting traces and metrics. #[schemars(with = "String", default = "otlp_endpoint_default")] - #[serde(default = "otlp_endpoint_default")] pub(crate) experimental_otlp_endpoint: Url, /// The Apollo Studio API key. #[schemars(skip)] - #[serde(default = "apollo_key")] pub(crate) apollo_key: Option, /// The Apollo Studio graph reference. #[schemars(skip)] - #[serde(default = "apollo_graph_reference")] pub(crate) apollo_graph_ref: Option, /// The name of the header to extract from requests when populating 'client nane' for traces and metrics in Apollo Studio. #[schemars(with = "Option", default = "client_name_header_default_str")] - #[serde( - deserialize_with = "deserialize_header_name", - default = "client_name_header_default" - )] + #[serde(deserialize_with = "deserialize_header_name")] pub(crate) client_name_header: HeaderName, /// The name of the header to extract from requests when populating 'client version' for traces and metrics in Apollo Studio. #[schemars(with = "Option", default = "client_version_header_default_str")] - #[serde( - deserialize_with = "deserialize_header_name", - default = "client_version_header_default" - )] + #[serde(deserialize_with = "deserialize_header_name")] pub(crate) client_version_header: HeaderName, /// The buffer size for sending traces to Apollo. Increase this if you are experiencing lost traces. - #[serde(default = "default_buffer_size")] pub(crate) buffer_size: NonZeroUsize, /// Field level instrumentation for subgraphs via ftv1. ftv1 tracing can cause performance issues as it is transmitted in band with subgraph responses. - #[serde(default = "default_field_level_instrumentation_sampler")] pub(crate) field_level_instrumentation_sampler: SamplerOption, /// To configure which request header names and values are included in trace data that's sent to Apollo Studio. - #[serde(default)] pub(crate) send_headers: ForwardHeaders, /// To configure which GraphQL variable values are included in trace data that's sent to Apollo Studio - #[serde(default)] pub(crate) send_variable_values: ForwardValues, // This'll get overridden if a user tries to set it. // The purpose is to allow is to pass this in to the plugin. #[schemars(skip)] - #[serde(default)] pub(crate) schema_id: String, /// Configuration for batch processing. - #[serde(default)] pub(crate) batch_processor: BatchProcessorConfig, /// Configure the way errors are transmitted to Apollo Studio - #[serde(default)] pub(crate) errors: ErrorsConfiguration, } @@ -120,21 +103,19 @@ pub(crate) struct SubgraphErrorConfig { } #[derive(Debug, Clone, Deserialize, JsonSchema)] -#[serde(deny_unknown_fields)] +#[serde(deny_unknown_fields, default)] pub(crate) struct ErrorConfiguration { /// Send subgraph errors to Apollo Studio - #[serde(default = "default_send_errors")] pub(crate) send: bool, /// Redact subgraph errors to Apollo Studio - #[serde(default = "default_redact_errors")] pub(crate) redact: bool, } impl Default for ErrorConfiguration { fn default() -> Self { Self { - send: default_send_errors(), - redact: default_redact_errors(), + send: true, + redact: true, } } } @@ -149,14 +130,6 @@ impl SubgraphErrorConfig { } } -pub(crate) const fn default_send_errors() -> bool { - true -} - -pub(crate) const fn default_redact_errors() -> bool { - true -} - const fn default_field_level_instrumentation_sampler() -> SamplerOption { SamplerOption::TraceIdRatioBased(0.01) } diff --git a/apollo-router/src/plugins/telemetry/config.rs b/apollo-router/src/plugins/telemetry/config.rs index 77e5af2414..20007ccf66 100644 --- a/apollo-router/src/plugins/telemetry/config.rs +++ b/apollo-router/src/plugins/telemetry/config.rs @@ -92,7 +92,6 @@ pub(crate) struct MetricsCommon { /// Resources pub(crate) resources: HashMap, /// Custom buckets for histograms - #[serde(default = "default_buckets")] pub(crate) buckets: Vec, /// Experimental metrics to know more about caching strategies pub(crate) experimental_cache_metrics: ExperimentalCacheMetricsConf, @@ -118,12 +117,6 @@ impl Default for ExperimentalCacheMetricsConf { } } -fn default_buckets() -> Vec { - vec![ - 0.001, 0.005, 0.015, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1.0, 5.0, 10.0, - ] -} - impl Default for MetricsCommon { fn default() -> Self { Self { @@ -131,7 +124,9 @@ impl Default for MetricsCommon { service_name: None, service_namespace: None, resources: HashMap::new(), - buckets: default_buckets(), + buckets: vec![ + 0.001, 0.005, 0.015, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 1.0, 5.0, 10.0, + ], experimental_cache_metrics: ExperimentalCacheMetricsConf::default(), } } diff --git a/apollo-router/src/plugins/telemetry/metrics/prometheus.rs b/apollo-router/src/plugins/telemetry/metrics/prometheus.rs index 289ba7baf8..4825934271 100644 --- a/apollo-router/src/plugins/telemetry/metrics/prometheus.rs +++ b/apollo-router/src/plugins/telemetry/metrics/prometheus.rs @@ -31,27 +31,17 @@ pub(crate) struct Config { /// Set to true to enable pub(crate) enabled: bool, /// The listen address - #[serde(default = "prometheus_default_listen_addr")] pub(crate) listen: ListenAddr, /// The path where prometheus will be exposed - #[serde(default = "prometheus_default_path")] pub(crate) path: String, } -fn prometheus_default_listen_addr() -> ListenAddr { - ListenAddr::SocketAddr("127.0.0.1:9090".parse().expect("valid listenAddr")) -} - -fn prometheus_default_path() -> String { - "/metrics".to_string() -} - impl Default for Config { fn default() -> Self { Self { enabled: false, - listen: prometheus_default_listen_addr(), - path: prometheus_default_path(), + listen: ListenAddr::SocketAddr("127.0.0.1:9090".parse().expect("valid listenAddr")), + path: "/metrics".to_string(), } } } diff --git a/apollo-router/src/plugins/telemetry/tracing/mod.rs b/apollo-router/src/plugins/telemetry/tracing/mod.rs index d760d30281..8300d15f73 100644 --- a/apollo-router/src/plugins/telemetry/tracing/mod.rs +++ b/apollo-router/src/plugins/telemetry/tracing/mod.rs @@ -97,11 +97,9 @@ where /// Batch processor configuration #[derive(Debug, Clone, Deserialize, JsonSchema)] +#[serde(default)] pub(crate) struct BatchProcessorConfig { - #[serde( - deserialize_with = "humantime_serde::deserialize", - default = "scheduled_delay_default" - )] + #[serde(deserialize_with = "humantime_serde::deserialize")] #[schemars(with = "String")] /// The delay interval in milliseconds between two consecutive processing /// of batches. The default value is 5 seconds. @@ -109,22 +107,17 @@ pub(crate) struct BatchProcessorConfig { /// The maximum queue size to buffer spans for delayed processing. If the /// queue gets full it drops the spans. The default value of is 2048. - #[serde(default = "max_queue_size_default")] pub(crate) max_queue_size: usize, /// The maximum number of spans to process in a single batch. If there are /// more than one batch worth of spans then it processes multiple batches /// of spans one batch after the other without any delay. The default value /// is 512. - #[serde(default = "max_export_batch_size_default")] pub(crate) max_export_batch_size: usize, /// The maximum duration to export a batch of data. /// The default value is 30 seconds. - #[serde( - deserialize_with = "humantime_serde::deserialize", - default = "max_export_timeout_default" - )] + #[serde(deserialize_with = "humantime_serde::deserialize")] #[schemars(with = "String")] pub(crate) max_export_timeout: Duration, @@ -134,7 +127,6 @@ pub(crate) struct BatchProcessorConfig { /// by an exporter. A value of 1 will cause exports to be performed /// synchronously on the BatchSpanProcessor task. /// The default is 1. - #[serde(default = "max_concurrent_exports_default")] pub(crate) max_concurrent_exports: usize, }