Skip to content

Commit 0ccfd93

Browse files
authored
Implement @cost and @listsize directives for demand control (#3074)
<!-- ROUTER-384 --> # Overview Implements two new directives for demand control, based on the [IBM Cost Specification](https://ibm.github.io/graphql-specs/cost-spec.html). ``` directive @cost(weight: Int!) on | ARGUMENT_DEFINITION | ENUM | FIELD_DEFINITION | INPUT_FIELD_DEFINITION | OBJECT | SCALAR directive @listsize( assumedSize: Int, slicingArguments: [String!], sizedFields: [String!], requireOneSlicingArgument: Boolean = true ) on FIELD_DEFINITION ``` The `@cost` directive allows users to specify a custom weight for fields, enums, input objects, and arguments. The weight is used in the demand control cost calculation, both for static estimates as well as actual cost calculations. The `@listSize` directive allows users to specify expected sizes of list fields in their schema. This can be a static value set through `assumedSize` or a dynamic value using `slicingArguments` to get the value from some paging parameters. ## Differences from the spec The main difference from the IBM spec is that we use an `Int!` for weight argument of `@cost`. This allows the parser to enforce this is parameterized with proper numeric values instead of finding out at runtime that an invalid `String!` weight was passed. ## Caveats for shared fields When `@cost` or `@listSize` are used on a `@shareable` field with different values, the composed directive will use a merged value that takes the maximum weight or assumed size, when applicable.
1 parent 6cf28f2 commit 0ccfd93

16 files changed

+841
-17
lines changed

.changeset/happy-bats-exist.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@apollo/composition": minor
3+
"@apollo/federation-internals": minor
4+
---
5+
6+
Implements two new directives for defining custom costs for demand control. The `@cost` directive allows setting a custom weight to a particular field in the graph, overriding the default cost calculation. The `@listSize` directive gives the cost calculator information about how to estimate the size of lists returned by subgraphs. This can either be a static size or a value derived from input arguments, such as paging parameters.

composition-js/src/__tests__/__snapshots__/compose.composeDirective.test.ts.snap

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ exports[`composing custom core directives custom tag directive works when federa
44
"schema
55
@link(url: \\"https://specs.apollo.dev/link/v1.0\\")
66
@link(url: \\"https://specs.apollo.dev/join/v0.3\\", for: EXECUTION)
7-
@link(url: \\"https://specs.apollo.dev/tag/v0.3\\", as: \\"mytag\\")
7+
@link(url: \\"https://specs.apollo.dev/tag/v0.3\\", import: [{name: \\"@tag\\", as: \\"@mytag\\"}])
88
@link(url: \\"https://custom.dev/tag/v1.0\\", import: [\\"@tag\\"])
99
{
1010
query: Query

composition-js/src/__tests__/compose.composeDirective.test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -796,7 +796,7 @@ describe('composing custom core directives', () => {
796796
expect(errors(result)).toStrictEqual([
797797
[
798798
'DIRECTIVE_COMPOSITION_ERROR',
799-
'Could not find matching directive definition for argument to @composeDirective "@fooz" in subgraph "subgraphA". Did you mean "@foo"?',
799+
'Could not find matching directive definition for argument to @composeDirective "@fooz" in subgraph "subgraphA". Did you mean "@foo" or "@cost"?',
800800
]
801801
]);
802802
});
@@ -926,8 +926,8 @@ describe('composing custom core directives', () => {
926926
expectCoreFeature(schema, 'https://custom.dev/tag', '1.0', [{ name: '@tag' }]);
927927
const feature = schema.coreFeatures?.getByIdentity('https://specs.apollo.dev/tag');
928928
expect(feature?.url.toString()).toBe('https://specs.apollo.dev/tag/v0.3');
929-
expect(feature?.imports).toEqual([]);
930-
expect(feature?.nameInSchema).toEqual('mytag');
929+
expect(feature?.imports).toEqual([{ name: '@tag', as: '@mytag' }]);
930+
expect(feature?.nameInSchema).toEqual('tag');
931931
expect(printSchema(schema)).toMatchSnapshot();
932932
});
933933

0 commit comments

Comments
 (0)