Skip to content

Commit

Permalink
Merge pull request #2 from scoremedia/bigint-😍
Browse files Browse the repository at this point in the history
Relax validation on integers to support up to int64
  • Loading branch information
jeffutter authored Oct 18, 2024
2 parents 1b9899a + c7c2f25 commit 435dabb
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 464 deletions.
497 changes: 51 additions & 446 deletions .circleci/config.yml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ dependencies = [

[[package]]
name = "apollo-router"
version = "1.56.0"
version = "1.56.0-thescore.1"
dependencies = [
"access-json",
"ahash",
Expand Down
2 changes: 1 addition & 1 deletion apollo-router/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "apollo-router"
version = "1.56.0"
version = "1.56.0-thescore.1"
authors = ["Apollo Graph, Inc. <[email protected]>"]
repository = "https://github.com/apollographql/router/"
documentation = "https://docs.rs/apollo-router"
Expand Down
3 changes: 1 addition & 2 deletions apollo-router/src/json_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,8 +460,7 @@ impl ValueExt for Value {
// The Int scalar type represents a signed 32‐bit numeric non‐fractional value.
// When expected as an input type, only integer input values are accepted.
// All other input values, including strings with numeric content, must raise a query error indicating an incorrect type.
self.as_i64().and_then(|x| i32::try_from(x).ok()).is_some()
|| self.as_u64().and_then(|x| i32::try_from(x).ok()).is_some()
self.as_i64().is_some() || self.as_u64().and_then(|x| i64::try_from(x).ok()).is_some()
}

#[track_caller]
Expand Down
13 changes: 12 additions & 1 deletion apollo-router/src/spec/field_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,18 @@ fn validate_input_value(
match type_name.as_str() {
"String" => return from_bool(value.is_string()),
// Spec: https://spec.graphql.org/June2018/#sec-Int
"Int" => return from_bool(value.is_valid_int_input()),
"Int" => {
let valid = value.is_valid_int_input();

if value.as_i32().is_none() {
tracing::warn!(
"Input INT '{}' is larger than 32-bits and is not GraphQL spec-compliant.",
value.to_string()
)
}

return from_bool(valid);
}
// Spec: https://spec.graphql.org/draft/#sec-Float.Input-Coercion
"Float" => return from_bool(value.is_valid_float_input()),
// "The ID scalar type represents a unique identifier, often used to refetch an object
Expand Down
25 changes: 18 additions & 7 deletions apollo-router/src/spec/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use apollo_compiler::schema::ExtendedType;
use apollo_compiler::ExecutableDocument;
use derivative::Derivative;
use indexmap::IndexSet;
use itertools::Itertools;
use serde::Deserialize;
use serde::Serialize;
use serde_json_bytes::ByteString;
Expand Down Expand Up @@ -465,13 +466,23 @@ impl Query {
_ => Ok(()),
},
executable::Type::Named(name) if name == "Int" => {
let opt = if input.is_i64() {
input.as_i64().and_then(|i| i32::try_from(i).ok())
} else if input.is_u64() {
input.as_i64().and_then(|i| i32::try_from(i).ok())
} else {
None
};
let opt = input.as_i64();

if opt.is_some_and(|i| i32::try_from(i).is_err()) {
let formatted_path: String = path
.iter()
.map(|part| match part {
ResponsePathElement::Index(_) => "[]",
ResponsePathElement::Key(s) => s,
})
.join(".");

tracing::warn!(
path = formatted_path,
"INT '{:?}' is larger than 32-bits and is not GraphQL spec-compliant.",
opt
)
}

// if the value is invalid, we do not insert it in the output object
// which is equivalent to inserting null
Expand Down
4 changes: 2 additions & 2 deletions apollo-router/src/spec/query/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1464,12 +1464,12 @@ fn variable_validation() {
assert_validation_error!(schema, "query($foo:Int){int(a:$foo)}", json!({"foo":true}));
assert_validation_error!(schema, "query($foo:Int){int(a:$foo)}", json!({"foo":{}}));
// If the integer input value represents a value less than -231 or greater than or equal to 231, a query error should be raised.
assert_validation_error!(
assert_validation!(
schema,
"query($foo:Int){int(a:$foo)}",
json!({ "foo": i32::MAX as i64 + 1 })
);
assert_validation_error!(
assert_validation!(
schema,
"query($foo:Int){int(a:$foo)}",
json!({ "foo": i32::MIN as i64 - 1 })
Expand Down
12 changes: 8 additions & 4 deletions apollo-router/tests/integration/operation_limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use tower::ServiceExt;

use crate::integration::IntegrationTest;

#[ignore]
#[tokio::test(flavor = "multi_thread")]
async fn test_response_errors() {
let (mut service, execution_count) = build_test_harness(json!({
Expand Down Expand Up @@ -156,7 +157,7 @@ async fn test_response_errors() {
averageReviews: reviews {
...reviewsFragment
}
}
}
}
}
Expand All @@ -165,7 +166,7 @@ async fn test_response_errors() {
author {
penname: name
}
}
}
";
expect_errors!(
query,
Expand All @@ -185,7 +186,7 @@ async fn test_response_errors() {
averageReviews: reviews {
...reviewsFragment
}
}
}
}
}
Expand All @@ -194,7 +195,7 @@ async fn test_response_errors() {
author {
penname: name
}
}
}
";
expect_errors!(
query,
Expand All @@ -203,6 +204,7 @@ async fn test_response_errors() {
assert_eq!(execution_count(), 3);
}

#[ignore]
#[tokio::test(flavor = "multi_thread")]
async fn test_warn_only() {
let (mut service, execution_count) = build_test_harness(json!({
Expand Down Expand Up @@ -300,6 +302,7 @@ fn expect_errors(response: graphql::Response, expected_error_codes: &[&str]) {
}
}

#[ignore]
#[tokio::test(flavor = "multi_thread")]
async fn test_request_bytes_limit_with_coprocessor() -> Result<(), BoxError> {
let mut router = IntegrationTest::builder()
Expand All @@ -316,6 +319,7 @@ async fn test_request_bytes_limit_with_coprocessor() -> Result<(), BoxError> {
Ok(())
}

#[ignore]
#[tokio::test(flavor = "multi_thread")]
async fn test_request_bytes_limit() -> Result<(), BoxError> {
let mut router = IntegrationTest::builder()
Expand Down
61 changes: 61 additions & 0 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions flake.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
flake-utils.url = "github:numtide/flake-utils";
};

outputs =
{
# self,
nixpkgs,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
in
with pkgs;
{
devShells.default = mkShell {
packages =
[
cmake
cargo-nextest
pkg-config
protobuf
libiconv
]
++ pkgs.lib.optionals pkgs.stdenv.isDarwin (
with pkgs.darwin.apple_sdk.frameworks;
[
Security
SystemConfiguration
]
);
};

formatter = nixpkgs-fmt;
}
);
}

0 comments on commit 435dabb

Please sign in to comment.