Skip to content

Commit c57eb9d

Browse files
authored
Merge branch 'dev' into timbotnik/PULSR-1484/graphos-error-docs
2 parents 72090a6 + dc9aecc commit c57eb9d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+1746
-626
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
### Add support for connector header propagation via YAML config ([PR #7152](https://github.com/apollographql/router/pull/7152))
2+
3+
Added support for connector header propagation via YAML config. All of the existing header propagation in the Router now works for connectors by using
4+
`headers.connector.all` to apply rules to all connectors or `headers.connector.sources.*` to apply rules to specific sources.
5+
6+
Note that if one of these rules conflicts with a header set in your schema, either in `@connect` or `@source`, the value in your Router config will
7+
take priority and be treated as an override.
8+
9+
```
10+
headers:
11+
connector:
12+
all: # configuration for all connectors across all subgraphs
13+
request:
14+
- insert:
15+
name: "x-inserted-header"
16+
value: "hello world!"
17+
- propagate:
18+
named: "x-client-header"
19+
sources:
20+
connector-graph.random_person_api:
21+
request:
22+
- insert:
23+
name: "x-inserted-header"
24+
value: "hello world!"
25+
- propagate:
26+
named: "x-client-header"
27+
```
28+
29+
By [@andrewmcgivery](https://github.com/andrewmcgivery) in https://github.com/apollographql/router/pull/7152
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
### Fix Apollo request metadata generation for errors ([PR #7021](https://github.com/apollographql/router/pull/7021))
2+
3+
* Fixes the Apollo operation ID and name generated for requests that fail due to parse, validation, or invalid operation name errors.
4+
* Updates the error code generated for operations with an invalid operation name from GRAPHQL_VALIDATION_FAILED to GRAPHQL_UNKNOWN_OPERATION_NAME
5+
6+
By [@bonnici](https://github.com/bonnici) in https://github.com/apollographql/router/pull/7021
+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Support @context/@fromContext when using Connectors ([PR #7132](https://github.com/apollographql/router/pull/7132))
2+
3+
This fixes a bug that dropped the `@context` and `@fromContext` directives when introducing a connector.
4+
5+
By [@lennyburdette](https://github.com/lennyburdette) in https://github.com/apollographql/router/pull/7132

apollo-federation/src/link/federation_spec_definition.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,10 @@ impl FederationSpecDefinition {
715715
composition_strategy: None,
716716
}],
717717
false,
718-
&[DirectiveLocation::FieldDefinition],
718+
&[
719+
DirectiveLocation::Object,
720+
DirectiveLocation::FieldDefinition,
721+
],
719722
false,
720723
None,
721724
None,
@@ -740,8 +743,8 @@ impl FederationSpecDefinition {
740743
&[],
741744
self.version().ge(&Version { major: 2, minor: 2 }),
742745
&[
743-
DirectiveLocation::FieldDefinition,
744746
DirectiveLocation::Object,
747+
DirectiveLocation::FieldDefinition,
745748
],
746749
false,
747750
None,

apollo-federation/src/schema/type_and_directive_specification.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -581,14 +581,14 @@ impl TypeAndDirectiveSpecification for DirectiveSpecification {
581581
}
582582

583583
let directive_pos = DirectiveDefinitionPosition {
584-
directive_name: actual_name,
584+
directive_name: actual_name.clone(),
585585
};
586586
directive_pos.pre_insert(schema)?;
587587
directive_pos.insert(
588588
schema,
589589
Node::new(DirectiveDefinition {
590590
description: None,
591-
name: self.name.clone(),
591+
name: actual_name,
592592
arguments: resolved_args
593593
.iter()
594594
.map(|arg| Node::new(arg.into()))

apollo-federation/src/sources/connect/expand/carryover.rs

+39
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use apollo_compiler::Node;
33
use apollo_compiler::ast::Argument;
44
use apollo_compiler::ast::Directive;
55
use apollo_compiler::ast::Value;
6+
use apollo_compiler::collections::HashSet;
67
use apollo_compiler::name;
78

89
use crate::error::FederationError;
@@ -349,12 +350,50 @@ pub(super) fn carryover_directives(
349350
.ok_or_else(|| {
350351
FederationError::internal("Cannot find matching directive in new supergraph")
351352
})?;
353+
354+
let argument_names = argument
355+
.value
356+
.as_list()
357+
.map(|list| list.iter().flat_map(|v| v.as_object()).flatten())
358+
.map(|pairs| {
359+
pairs
360+
.filter(|(name, _)| name == &name!("name"))
361+
.flat_map(|(_, value)| value.as_str())
362+
.flat_map(|s| Name::new(s).ok())
363+
.collect::<HashSet<_>>()
364+
})
365+
.ok_or_else(|| {
366+
FederationError::internal("Cannot find `name` argument in `contextArguments`")
367+
})?;
368+
352369
ObjectOrInterfaceFieldDirectivePosition {
353370
field: pos.clone(),
354371
directive_name: name!("join__field"),
355372
directive_index,
356373
}
357374
.add_argument(to, argument)?;
375+
376+
for argument_name in argument_names {
377+
// Remove the argument now that it's handled by `@join__field(contextArguments:)`
378+
match &pos {
379+
ObjectOrInterfaceFieldDefinitionPosition::Object(pos) => {
380+
ObjectFieldArgumentDefinitionPosition {
381+
type_name: pos.type_name.clone(),
382+
field_name: pos.field_name.clone(),
383+
argument_name,
384+
}
385+
.remove(to)?;
386+
}
387+
ObjectOrInterfaceFieldDefinitionPosition::Interface(pos) => {
388+
InterfaceFieldArgumentDefinitionPosition {
389+
type_name: pos.type_name.clone(),
390+
field_name: pos.field_name.clone(),
391+
argument_name,
392+
}
393+
.remove(to)?;
394+
}
395+
}
396+
}
358397
}
359398
};
360399

apollo-federation/src/sources/connect/expand/snapshots/apollo_federation__sources__connect__expand__carryover__tests__carryover.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ type T @join__type(graph: ONE) @custom2 {
9494

9595
type X @join__type(graph: TWO, key: "id") {
9696
id: ID! @join__field(graph: TWO, type: "ID!")
97-
w(z: String): String @join__field(graph: TWO, type: "String", contextArguments: [{context: "two__ctx", name: "z", type: "String", selection: " { y }"}])
97+
w: String @join__field(graph: TWO, type: "String", contextArguments: [{context: "two__ctx", name: "z", type: "String", selection: " { y }"}])
9898
}
9999

100100
type Z @join__type(graph: TWO, key: "id") @context(name: "two__ctx") {

apollo-federation/src/sources/connect/expand/tests/snapshots/supergraph@carryover.graphql.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ type R @join__type(graph: ONE_T_R_0) {
9393

9494
type X @join__type(graph: TWO, key: "id") {
9595
id: ID! @join__field(graph: TWO, type: "ID!")
96-
w(z: String): String @join__field(graph: TWO, type: "String", contextArguments: [{context: "two__ctx", name: "z", type: "String", selection: " { y }"}])
96+
w: String @join__field(graph: TWO, type: "String", contextArguments: [{context: "two__ctx", name: "z", type: "String", selection: " { y }"}])
9797
}
9898

9999
type Z @join__type(graph: TWO, key: "id") @context(name: "two__ctx") {

apollo-federation/src/sources/connect/json_selection/apply_to.rs

+63-41
Original file line numberDiff line numberDiff line change
@@ -540,42 +540,58 @@ impl ApplyToInternal for WithRange<PathList> {
540540
}
541541
}
542542
PathList::Key(key, tail) => {
543-
if let JSON::Array(array) = data {
544-
return self.apply_to_array(array, vars, input_path);
545-
}
546-
547543
let input_path_with_key = input_path.append(key.to_json());
548544

549-
if !matches!(data, JSON::Object(_)) {
550-
return (
551-
None,
552-
vec![ApplyToError::new(
553-
format!(
554-
"Property {} not found in {}",
555-
key.dotted(),
556-
json_type_name(data),
557-
),
558-
input_path_with_key.to_vec(),
559-
key.range(),
560-
)],
561-
);
562-
}
563-
564-
if let Some(child) = data.get(key.as_str()) {
565-
tail.apply_to_path(child, vars, &input_path_with_key)
545+
if let JSON::Array(array) = data {
546+
// If we recursively call self.apply_to_array, it will end
547+
// up invoking the tail of the key recursively, whereas we
548+
// want to apply the tail once to the entire output array of
549+
// shallow key lookups. To keep the recursion shallow, we
550+
// need a version of self that has the same key but no tail.
551+
let empty_tail = WithRange::new(PathList::Empty, tail.range());
552+
let self_with_empty_tail =
553+
WithRange::new(PathList::Key(key.clone(), empty_tail), key.range());
554+
555+
self_with_empty_tail
556+
.apply_to_array(array, vars, input_path)
557+
.and_then_collecting_errors(|shallow_mapped_array| {
558+
// This tail.apply_to_path call happens only once,
559+
// passing to the original/top-level tail the entire
560+
// array produced by key-related recursion/mapping.
561+
tail.apply_to_path(shallow_mapped_array, vars, &input_path_with_key)
562+
})
566563
} else {
567-
(
568-
None,
569-
vec![ApplyToError::new(
570-
format!(
571-
"Property {} not found in {}",
572-
key.dotted(),
573-
json_type_name(data),
574-
),
575-
input_path_with_key.to_vec(),
576-
key.range(),
577-
)],
578-
)
564+
if !matches!(data, JSON::Object(_)) {
565+
return (
566+
None,
567+
vec![ApplyToError::new(
568+
format!(
569+
"Property {} not found in {}",
570+
key.dotted(),
571+
json_type_name(data),
572+
),
573+
input_path_with_key.to_vec(),
574+
key.range(),
575+
)],
576+
);
577+
}
578+
579+
if let Some(child) = data.get(key.as_str()) {
580+
tail.apply_to_path(child, vars, &input_path_with_key)
581+
} else {
582+
(
583+
None,
584+
vec![ApplyToError::new(
585+
format!(
586+
"Property {} not found in {}",
587+
key.dotted(),
588+
json_type_name(data),
589+
),
590+
input_path_with_key.to_vec(),
591+
key.range(),
592+
)],
593+
)
594+
}
579595
}
580596
}
581597
PathList::Expr(expr, tail) => expr
@@ -586,14 +602,20 @@ impl ApplyToInternal for WithRange<PathList> {
586602
input_path.append(JSON::String(format!("->{}", method_name.as_ref()).into()));
587603

588604
if let Some(method) = ArrowMethod::lookup(method_name) {
589-
method.apply(
590-
method_name,
591-
method_args.as_ref(),
592-
data,
593-
vars,
594-
&method_path,
595-
tail,
596-
)
605+
let (result_opt, errors) =
606+
method.apply(method_name, method_args.as_ref(), data, vars, &method_path);
607+
608+
if let Some(result) = result_opt {
609+
tail.apply_to_path(&result, vars, &method_path)
610+
.prepend_errors(errors)
611+
} else {
612+
// If the method produced no output, assume the errors
613+
// explain the None. Methods can legitimately produce
614+
// None without errors (like ->first or ->last on an
615+
// empty array), so we do not report any blanket error
616+
// here when errors.is_empty().
617+
(None, errors)
618+
}
597619
} else {
598620
(
599621
None,

apollo-federation/src/sources/connect/json_selection/methods.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use shape::location::SourceId;
55

66
use super::ApplyToError;
77
use super::MethodArgs;
8-
use super::PathList;
98
use super::VarsWithPathsMap;
109
use super::immutable::InputPath;
1110
use super::location::WithRange;
@@ -68,9 +67,8 @@ macro_rules! impl_arrow_method {
6867
data: &JSON,
6968
vars: &VarsWithPathsMap,
7069
input_path: &InputPath<JSON>,
71-
tail: &WithRange<PathList>,
7270
) -> (Option<JSON>, Vec<ApplyToError>) {
73-
$impl_fn_name(method_name, method_args, data, vars, input_path, tail)
71+
$impl_fn_name(method_name, method_args, data, vars, input_path)
7472
}
7573

7674
fn shape(
@@ -104,7 +102,6 @@ pub(super) trait ArrowMethodImpl {
104102
data: &JSON,
105103
vars: &VarsWithPathsMap,
106104
input_path: &InputPath<JSON>,
107-
tail: &WithRange<PathList>,
108105
) -> (Option<JSON>, Vec<ApplyToError>);
109106

110107
fn shape(

apollo-federation/src/sources/connect/json_selection/methods/future/and.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ use crate::impl_arrow_method;
88
use crate::sources::connect::json_selection::ApplyToError;
99
use crate::sources::connect::json_selection::ApplyToInternal;
1010
use crate::sources::connect::json_selection::MethodArgs;
11-
use crate::sources::connect::json_selection::PathList;
1211
use crate::sources::connect::json_selection::VarsWithPathsMap;
13-
use crate::sources::connect::json_selection::apply_to::ApplyToResultMethods;
1412
use crate::sources::connect::json_selection::immutable::InputPath;
1513
use crate::sources::connect::json_selection::location::Ranged;
1614
use crate::sources::connect::json_selection::location::WithRange;
@@ -30,7 +28,6 @@ fn and_method(
3028
data: &JSON,
3129
vars: &VarsWithPathsMap,
3230
input_path: &InputPath<JSON>,
33-
tail: &WithRange<PathList>,
3431
) -> (Option<JSON>, Vec<ApplyToError>) {
3532
if let Some(MethodArgs { args, .. }) = method_args {
3633
let mut result = is_truthy(data);
@@ -45,8 +42,7 @@ fn and_method(
4542
result = value_opt.map(|value| is_truthy(&value)).unwrap_or(false);
4643
}
4744

48-
tail.apply_to_path(&JSON::Bool(result), vars, input_path)
49-
.prepend_errors(errors)
45+
(Some(JSON::Bool(result)), errors)
5046
} else {
5147
(
5248
None,

apollo-federation/src/sources/connect/json_selection/methods/future/arithmetic.rs

-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ use crate::impl_arrow_method;
88
use crate::sources::connect::json_selection::ApplyToError;
99
use crate::sources::connect::json_selection::ApplyToInternal;
1010
use crate::sources::connect::json_selection::MethodArgs;
11-
use crate::sources::connect::json_selection::PathList;
1211
use crate::sources::connect::json_selection::VarsWithPathsMap;
13-
use crate::sources::connect::json_selection::apply_to::ApplyToResultMethods;
1412
use crate::sources::connect::json_selection::helpers::vec_push;
1513
use crate::sources::connect::json_selection::immutable::InputPath;
1614
use crate::sources::connect::json_selection::location::Ranged;
@@ -159,10 +157,8 @@ macro_rules! infix_math_method {
159157
data: &JSON,
160158
vars: &VarsWithPathsMap,
161159
input_path: &InputPath<JSON>,
162-
tail: &WithRange<PathList>,
163160
) -> (Option<JSON>, Vec<ApplyToError>) {
164161
arithmetic_method(method_name, method_args, $op, data, vars, input_path)
165-
.and_then_collecting_errors(|result| tail.apply_to_path(&result, vars, input_path))
166162
}
167163
};
168164
}

apollo-federation/src/sources/connect/json_selection/methods/future/eq.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ use crate::impl_arrow_method;
77
use crate::sources::connect::json_selection::ApplyToError;
88
use crate::sources::connect::json_selection::ApplyToInternal;
99
use crate::sources::connect::json_selection::MethodArgs;
10-
use crate::sources::connect::json_selection::PathList;
1110
use crate::sources::connect::json_selection::VarsWithPathsMap;
12-
use crate::sources::connect::json_selection::apply_to::ApplyToResultMethods;
1311
use crate::sources::connect::json_selection::immutable::InputPath;
1412
use crate::sources::connect::json_selection::location::Ranged;
1513
use crate::sources::connect::json_selection::location::WithRange;
@@ -26,7 +24,6 @@ fn eq_method(
2624
data: &JSON,
2725
vars: &VarsWithPathsMap,
2826
input_path: &InputPath<JSON>,
29-
tail: &WithRange<PathList>,
3027
) -> (Option<JSON>, Vec<ApplyToError>) {
3128
if let Some(MethodArgs { args, .. }) = method_args {
3229
if args.len() == 1 {
@@ -36,9 +33,7 @@ fn eq_method(
3633
} else {
3734
false
3835
};
39-
return tail
40-
.apply_to_path(&JSON::Bool(matches), vars, input_path)
41-
.prepend_errors(arg_errors);
36+
return (Some(JSON::Bool(matches)), arg_errors);
4237
}
4338
}
4439
(

0 commit comments

Comments
 (0)