├── .circleci └── config.yml ├── .editorconfig ├── .github ├── CODEOWNERS ├── release-drafter.yml └── workflows │ ├── build.yaml │ ├── compatibility.yml │ ├── continuous-integration.yml │ ├── pr-check.yml │ └── release.yml ├── .gitignore ├── .gitleaks.toml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── buildSrc ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── com.apollographql.federation.java-conventions.gradle.kts ├── compatibility ├── Dockerfile ├── build.gradle.kts ├── docker-compose.yaml ├── gradle.properties ├── gradle │ └── wrapper ├── gradlew ├── settings.gradle.kts └── src │ └── main │ ├── java │ └── com │ │ └── apollographql │ │ └── federation │ │ └── compatibility │ │ ├── App.java │ │ ├── DeprecatedProductController.java │ │ ├── GraphQLConfiguration.java │ │ ├── InventoryController.java │ │ ├── ProductController.java │ │ ├── ProductResearchController.java │ │ ├── TracingInterceptor.java │ │ ├── UserController.java │ │ └── model │ │ ├── CaseStudy.java │ │ ├── DeprecatedProduct.java │ │ ├── Inventory.java │ │ ├── Product.java │ │ ├── ProductDimension.java │ │ ├── ProductResearch.java │ │ ├── ProductVariation.java │ │ └── User.java │ └── resources │ ├── application.yml │ └── graphql │ └── schema.graphqls ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── graphql-java-support ├── README.md ├── build.gradle.kts └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── apollographql │ │ │ └── federation │ │ │ └── graphqljava │ │ │ ├── Federation.java │ │ │ ├── FederationDirectives.java │ │ │ ├── FederationError.java │ │ │ ├── SchemaTransformer.java │ │ │ ├── _Any.java │ │ │ ├── _Entity.java │ │ │ ├── _FieldSet.java │ │ │ ├── _Service.java │ │ │ ├── caching │ │ │ └── CacheControlInstrumentation.java │ │ │ ├── directives │ │ │ ├── LinkDirectiveProcessor.java │ │ │ └── LinkImportsRenamingVisitor.java │ │ │ ├── exceptions │ │ │ ├── MissingKeyException.java │ │ │ ├── MultipleFederationLinksException.java │ │ │ ├── UnsupportedFederationVersionException.java │ │ │ ├── UnsupportedLinkImportException.java │ │ │ └── UnsupportedRenameException.java │ │ │ ├── link__Import.java │ │ │ ├── printer │ │ │ └── ServiceSDLPrinter.java │ │ │ └── tracing │ │ │ └── FederatedTracingInstrumentation.java │ ├── proto │ │ └── reports.proto │ └── resources │ │ ├── definitions_fed2_0.graphqls │ │ ├── definitions_fed2_1.graphqls │ │ ├── definitions_fed2_2.graphqls │ │ ├── definitions_fed2_3.graphqls │ │ ├── definitions_fed2_5.graphqls │ │ ├── definitions_fed2_6.graphqls │ │ ├── definitions_fed2_7.graphqls │ │ ├── definitions_fed2_8.graphqls │ │ └── definitions_fed2_9.graphqls │ └── test │ ├── java │ └── com │ │ └── apollographql │ │ └── federation │ │ └── graphqljava │ │ ├── AnyTest.java │ │ ├── FederatedSchemaVerifier.java │ │ ├── FederationTest.java │ │ ├── FileUtils.java │ │ ├── SchemaTransformerTest.java │ │ ├── caching │ │ └── CacheControlInstrumentationTest.java │ │ ├── data │ │ ├── Product.java │ │ ├── ProductDimension.java │ │ ├── ProductVariation.java │ │ └── User.java │ │ ├── printer │ │ └── ServiceSDLPrinterTest.java │ │ └── tracing │ │ └── FederatedTracingInstrumentationTest.java │ └── resources │ └── schemas │ ├── README.md │ ├── authorization │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── composeDirective │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── context │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── cost │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── customAuthenticated │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── entitiesOnlySubgraph │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── extendSchema │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── fedV1 │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── fedV2 │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── interfaceEntity │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── interfaceObject │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── invalidMultipleFederationLinks.graphql │ ├── invalidMultipleFederationSchemaLinks.graphql │ ├── invalidPolymorphicSubgraphMissingKeys.graphql │ ├── invalidRenameInaccessibleImport.graphql │ ├── invalidRenameTagImport.graphql │ ├── invalidSpecVersion.graphql │ ├── invalidSpecVersionAuthenticated.graphql │ ├── invalidSpecVersionComposeDirective.graphql │ ├── invalidSpecVersionContext.graphql │ ├── invalidSpecVersionCost.graphql │ ├── invalidSpecVersionInterfaceObject.graphql │ ├── invalidSpecVersionPolicy.graphql │ ├── invalidSpecVersionProgressiveOverride.graphql │ ├── invalidSpecVersionRepeatableShareable.graphql │ ├── invalidSpecVersionRequiresScopes.graphql │ ├── noEntities │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── nonResolvableKey │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── policy │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── progressiveOverride │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── renamedImports │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── repeatableShareable │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── scalars │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ ├── schemaImport │ ├── schema.graphql │ ├── schema_federated.graphql │ └── schema_full.graphql │ └── tracingSchema.graphql ├── renovate.json ├── settings.gradle.kts └── spring-subscription-callback ├── README.md ├── build.gradle.kts └── src ├── main └── java │ └── com │ └── apollographql │ └── subscription │ ├── CallbackWebGraphQLInterceptor.java │ ├── callback │ ├── SubscriptionCallback.java │ └── SubscriptionCallbackHandler.java │ ├── exception │ ├── CallbackExtensionNotSpecifiedException.java │ ├── CallbackInitializationFailedException.java │ ├── InactiveSubscriptionException.java │ └── InvalidCallbackExtensionException.java │ └── message │ ├── CallbackMessageAction.java │ ├── CallbackMessageCheck.java │ ├── CallbackMessageComplete.java │ ├── CallbackMessageNext.java │ └── SubscritionCallbackMessage.java └── test ├── java └── com │ └── apollographql │ └── subscription │ ├── CallbackGraphQLHttpHandlerAbstrIT.java │ ├── CallbackTestUtils.java │ ├── callback │ ├── SubscriptionCallbackHandlerTest.java │ └── SubscriptionCallbackTest.java │ ├── configuration │ ├── TestGraphQLConfiguration.java │ └── TestSubscriptionController.java │ ├── webflux │ └── CallbackGraphQLWebfluxHttpHandlerIT.java │ └── webmvc │ └── CallbackGraphQLWebmvcHttpHandlerIT.java └── resources └── graphql └── schema.graphqls /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | orbs: 4 | secops: apollo/circleci-secops-orb@2.0.7 5 | 6 | workflows: 7 | security-scans: 8 | jobs: 9 | - secops/gitleaks: 10 | context: 11 | - platform-docker-ro 12 | - github-orb 13 | - secops-oidc 14 | git-base-revision: <<#pipeline.git.base_revision>><><> 15 | git-revision: << pipeline.git.revision >> 16 | - secops/semgrep: 17 | context: 18 | - secops-oidc 19 | - github-orb 20 | git-base-revision: <<#pipeline.git.base_revision>><><> 21 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_style = space 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | # space indentation for JSON and YML 15 | [*.{json,yml}] 16 | indent_size = 2 17 | 18 | # space indentation for Java 19 | [*.java] 20 | indent_size = 2 21 | max_line_length = 200 22 | 23 | [*.kts] 24 | indent_size = 4 25 | max_line_length = 200 26 | 27 | [*.graphql] 28 | indent_size = 2 29 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @apollographql/fed-core 2 | -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name-template: v$NEXT_PATCH_VERSION 2 | tag-template: v$NEXT_PATCH_VERSION 3 | change-template: '- $TITLE (#$NUMBER) @$AUTHOR' 4 | categories: 5 | - title: Major Changes 6 | label: "change: major" 7 | 8 | - title: Minor Changes 9 | label: "change: minor" 10 | 11 | - title: Patch Changes 12 | label: "change: patch" 13 | 14 | - title: Other Changes 15 | 16 | template: | 17 | $CHANGES 18 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | workflow_call: 5 | 6 | jobs: 7 | build: 8 | timeout-minutes: 30 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Set up Java 17 15 | uses: actions/setup-java@v4 16 | with: 17 | java-version: 17 18 | distribution: 'temurin' 19 | 20 | - name: Set up Gradle 21 | uses: gradle/actions/setup-gradle@v4 22 | 23 | - name: Build libraries with Gradle 24 | run: ./gradlew clean build 25 | 26 | - name: Archive failure build reports 27 | uses: actions/upload-artifact@v4 28 | if: failure() 29 | with: 30 | name: build-reports 31 | path: | 32 | ./**/build/reports 33 | retention-days: 7 34 | -------------------------------------------------------------------------------- /.github/workflows/compatibility.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Federation Compatibility Check 2 | 3 | on: 4 | workflow_call: 5 | secrets: 6 | token: 7 | required: false 8 | 9 | jobs: 10 | compatibility: 11 | timeout-minutes: 30 12 | runs-on: ubuntu-latest 13 | defaults: 14 | run: 15 | working-directory: compatibility 16 | 17 | steps: 18 | - name: Checkout Repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Set up Java 17 22 | uses: actions/setup-java@v4 23 | with: 24 | java-version: 17 25 | distribution: 'temurin' 26 | 27 | - name: Set up Gradle 28 | uses: gradle/actions/setup-gradle@v4 29 | 30 | - name: Build app with Gradle 31 | run: ./gradlew bootJar 32 | 33 | - name: Compatibility Test 34 | uses: apollographql/federation-subgraph-compatibility@v2 35 | with: 36 | compose: 'docker-compose.yaml' 37 | schema: 'src/main/resources/graphql/schema.graphqls' 38 | failOnWarning: true 39 | failOnRequired: true 40 | workingDirectory: 'compatibility' 41 | token: ${{ secrets.token }} 42 | -------------------------------------------------------------------------------- /.github/workflows/continuous-integration.yml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 'v*.x' 8 | paths-ignore: 9 | - '*.md' 10 | 11 | jobs: 12 | build: 13 | uses: ./.github/workflows/build.yaml 14 | 15 | integration: 16 | needs: build 17 | uses: ./.github/workflows/compatibility.yml 18 | 19 | release-notes: 20 | timeout-minutes: 10 21 | runs-on: ubuntu-latest 22 | permissions: 23 | contents: write 24 | pull-requests: read 25 | steps: 26 | - name: Release Drafter 27 | uses: release-drafter/release-drafter@v6 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | -------------------------------------------------------------------------------- /.github/workflows/pr-check.yml: -------------------------------------------------------------------------------- 1 | name: Pull Request Check 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | - 'v*.x' 8 | paths-ignore: 9 | - '*.md' 10 | 11 | jobs: 12 | build: 13 | uses: ./.github/workflows/build.yaml 14 | 15 | integration: 16 | needs: build 17 | permissions: 18 | pull-requests: write 19 | uses: ./.github/workflows/compatibility.yml 20 | secrets: 21 | token: ${{ secrets.GITHUB_TOKEN }} 22 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | release-code: 9 | timeout-minutes: 60 10 | runs-on: ubuntu-latest 11 | if: github.repository == 'apollographql/federation-jvm' 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - uses: gradle/actions/wrapper-validation@v4 17 | 18 | - name: Set up Java 17 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: 17 22 | distribution: 'temurin' 23 | cache: 'gradle' 24 | 25 | - name: Build libraries with Gradle 26 | run: ./gradlew clean build 27 | 28 | - name: Publish libraries with Gradle 29 | run: | 30 | NEW_VERSION=$(echo "${GITHUB_REF}" | sed 's/.*\/v//') 31 | echo "New version: ${NEW_VERSION}" 32 | ./gradlew publishToSonatype closeAndReleaseStagingRepositories -Pversion=${NEW_VERSION} 33 | env: 34 | SONATYPE_NEXUS_USERNAME: ${{ secrets.SONATYPE_NEXUS_USERNAME }} 35 | SONATYPE_NEXUS_PASSWORD: ${{ secrets.SONATYPE_NEXUS_PASSWORD }} 36 | COM_APOLLOGRAPHQL_PROFILE_ID: ${{ secrets.COM_APOLLOGRAPHQL_PROFILE_ID }} 37 | GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} 38 | GPG_PRIVATE_KEY_PASSWORD: ${{ secrets.GPG_PRIVATE_KEY_PASSWORD }} 39 | 40 | - name: Archive failure build reports 41 | uses: actions/upload-artifact@v4 42 | if: failure() 43 | with: 44 | name: build-reports 45 | path: | 46 | ./**/build/reports 47 | retention-days: 7 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # idea 2 | *.iml 3 | .idea/ 4 | 5 | # mac 6 | .DS_Store 7 | 8 | # gradle ignore 9 | .gradle 10 | build/ 11 | out/ 12 | 13 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 14 | !gradle-wrapper.jar 15 | 16 | # compatibility tests ignore 17 | results.md 18 | supergraph* 19 | -------------------------------------------------------------------------------- /.gitleaks.toml: -------------------------------------------------------------------------------- 1 | # This file exists primarily to influence scheduled scans that Apollo runs of all repos in Apollo-managed orgs. 2 | # This is an Apollo-Internal link, but more information about these scans is available here: 3 | # https://apollographql.atlassian.net/wiki/spaces/SecOps/pages/81330213/Everything+Static+Application+Security+Testing#Scheduled-Scans.1 4 | # 5 | # Apollo is using Gitleaks (https://github.com/gitleaks/gitleaks) to run these scans. 6 | # However, this file is not something that Gitleaks natively consumes. This file is an 7 | # Apollo-convention. Prior to scanning a repo, Apollo merges 8 | # our standard Gitleaks configuration (which is largely just the Gitleaks-default config) with 9 | # this file if it exists in a repo. The combined config is then used to scan a repo. 10 | # 11 | # We did this because the natively-supported allowlisting functionality in Gitleaks didn't do everything we wanted 12 | # or wasn't as robust as we needed. For example, one of the allowlisting options offered by Gitleaks depends on the line number 13 | # on which a false positive secret exists to allowlist it. (https://github.com/gitleaks/gitleaks#gitleaksignore). 14 | # This creates a fairly fragile allowlisting mechanism. This file allows us to leverage the full capabilities of the Gitleaks rule syntax 15 | # to create allowlisting functionality. 16 | 17 | [[ rules ]] 18 | id = "private-key" 19 | [ rules.allowlist ] 20 | commits = [ 21 | # Allowlist https://github.com/apollographql/federation-jvm/blob/689e65bf569dcf1ad1872bf519b676ea2d2a0fb7/RELEASING.md?plain=1#L13 22 | "689e65bf569dcf1ad1872bf519b676ea2d2a0fb7", 23 | 24 | ] 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Meteor Development Group, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("io.github.gradle-nexus.publish-plugin") version "2.0.0" 3 | } 4 | 5 | tasks { 6 | nexusPublishing { 7 | repositories { 8 | sonatype { 9 | nexusUrl.set(uri("https://s01.oss.sonatype.org/service/local/")) 10 | username.set(System.getenv("SONATYPE_NEXUS_USERNAME")) 11 | password.set(System.getenv("SONATYPE_NEXUS_PASSWORD")) 12 | stagingProfileId.set(System.getenv("COM_APOLLOGRAPHQL_PROFILE_ID")) 13 | } 14 | } 15 | 16 | transitionCheckOptions { 17 | maxRetries.set(60) 18 | delayBetween.set(java.time.Duration.ofMillis(5000)) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /buildSrc/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | // Support convention plugins written in Kotlin. Convention plugins are build scripts in 'src/main' that automatically become available as plugins in the main build. 3 | `kotlin-dsl` 4 | } 5 | 6 | repositories { 7 | // Use the plugin portal to apply community plugins in convention plugins. 8 | gradlePluginPortal() 9 | } 10 | 11 | dependencies { 12 | implementation("com.diffplug.spotless:spotless-plugin-gradle:7.0.1") 13 | } 14 | -------------------------------------------------------------------------------- /compatibility/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:21 2 | 3 | EXPOSE 4001 4 | RUN mkdir /app 5 | 6 | COPY build/libs/federation-jvm-compatibility.jar /app/app.jar 7 | 8 | ENTRYPOINT ["java", "-jar","/app/app.jar"] 9 | -------------------------------------------------------------------------------- /compatibility/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Properties 2 | 3 | plugins { 4 | id("org.springframework.boot") version "3.3.6" 5 | id("io.spring.dependency-management") version "1.1.7" 6 | java 7 | } 8 | 9 | repositories { 10 | mavenCentral() 11 | } 12 | 13 | val properties = Properties() 14 | properties.load(File(rootDir.parent, "gradle.properties").inputStream()) 15 | for ((key, value) in properties) { 16 | project.ext[key.toString()] = value 17 | } 18 | 19 | val annotationsVersion: String by project 20 | dependencies { 21 | implementation("com.apollographql.federation", "federation-graphql-java-support") 22 | implementation("org.jetbrains", "annotations", annotationsVersion) 23 | implementation("org.springframework.boot", "spring-boot-starter-actuator") 24 | implementation("org.springframework.boot", "spring-boot-starter-graphql") 25 | implementation("org.springframework.boot", "spring-boot-starter-web") 26 | testImplementation("org.springframework.boot", "spring-boot-starter-test") 27 | testImplementation("org.springframework.boot", "spring-boot-starter-webflux") 28 | testImplementation("org.springframework.graphql", "spring-graphql-test") 29 | } 30 | 31 | java { 32 | sourceCompatibility = JavaVersion.VERSION_17 33 | targetCompatibility = JavaVersion.VERSION_17 34 | } 35 | 36 | tasks.withType { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /compatibility/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | products: 3 | # must match path from project root dir 4 | build: . 5 | ports: 6 | - 4001:4001 7 | -------------------------------------------------------------------------------- /compatibility/gradle.properties: -------------------------------------------------------------------------------- 1 | # graphql-java.version=22.3 2 | -------------------------------------------------------------------------------- /compatibility/gradle/wrapper: -------------------------------------------------------------------------------- 1 | ../../gradle/wrapper -------------------------------------------------------------------------------- /compatibility/gradlew: -------------------------------------------------------------------------------- 1 | ../gradlew -------------------------------------------------------------------------------- /compatibility/settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "federation-jvm-compatibility" 2 | 3 | // composite builds 4 | includeBuild("..") 5 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/App.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class App { 8 | public static void main(String[] args) { 9 | SpringApplication.run(App.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/DeprecatedProductController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.compatibility.model.DeprecatedProduct; 4 | import org.springframework.graphql.data.federation.EntityMapping; 5 | import org.springframework.graphql.data.method.annotation.Argument; 6 | import org.springframework.graphql.data.method.annotation.QueryMapping; 7 | import org.springframework.graphql.data.method.annotation.SchemaMapping; 8 | import org.springframework.stereotype.Controller; 9 | 10 | @Controller 11 | public class DeprecatedProductController { 12 | 13 | @QueryMapping 14 | @EntityMapping 15 | public DeprecatedProduct deprecatedProduct(@Argument String sku, @Argument("package") String pkg) { 16 | return DeprecatedProduct.resolveBySkuAndPackage(sku, pkg); 17 | } 18 | 19 | @SchemaMapping(typeName = "DeprecatedProduct", field = "package") 20 | public String getPackage(DeprecatedProduct product) { 21 | return product.pkg(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/GraphQLConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.graphqljava.tracing.FederatedTracingInstrumentation; 4 | import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.graphql.data.federation.FederationSchemaFactory; 8 | 9 | @Configuration 10 | public class GraphQLConfiguration { 11 | 12 | @Bean 13 | public FederatedTracingInstrumentation federatedTracingInstrumentation() { 14 | return new FederatedTracingInstrumentation(); 15 | } 16 | 17 | @Bean 18 | public GraphQlSourceBuilderCustomizer customizer(FederationSchemaFactory factory) { 19 | return builder -> builder.schemaFactory(factory::createGraphQLSchema); 20 | } 21 | 22 | @Bean 23 | FederationSchemaFactory federationSchemaFactory() { 24 | return new FederationSchemaFactory(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/InventoryController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.compatibility.model.Inventory; 4 | import org.springframework.graphql.data.federation.EntityMapping; 5 | import org.springframework.graphql.data.method.annotation.Argument; 6 | import org.springframework.stereotype.Controller; 7 | 8 | @Controller 9 | public class InventoryController { 10 | @EntityMapping 11 | public Inventory inventory(@Argument("id") String id) { 12 | return Inventory.resolveById(id); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/ProductController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.compatibility.model.Product; 4 | import org.springframework.graphql.data.federation.EntityMapping; 5 | import org.springframework.graphql.data.method.annotation.Argument; 6 | import org.springframework.graphql.data.method.annotation.QueryMapping; 7 | import org.springframework.graphql.data.method.annotation.SchemaMapping; 8 | import org.springframework.stereotype.Controller; 9 | 10 | import java.util.Map; 11 | 12 | @Controller 13 | public class ProductController { 14 | @EntityMapping 15 | public Product product( 16 | @Argument String id, 17 | @Argument String sku, 18 | @Argument("package") String pkg, 19 | @Argument("variation") Map variation 20 | ) { 21 | if (id != null) { 22 | return Product.resolveById(id); 23 | } else if (sku != null) { 24 | if (pkg != null) { 25 | return Product.resolveBySkuAndPackage(sku, pkg); 26 | } else if (variation != null) { 27 | return Product.resolveBySkuAndVariation(sku, variation.get("id")); 28 | } 29 | } 30 | return null; 31 | } 32 | 33 | @QueryMapping 34 | public Product product(@Argument String id) { 35 | return Product.resolveById(id); 36 | } 37 | 38 | @SchemaMapping(typeName = "Product", field = "package") 39 | public String getPackage(Product product) { 40 | return product.pkg(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/ProductResearchController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.compatibility.model.ProductResearch; 4 | import org.springframework.graphql.data.federation.EntityMapping; 5 | import org.springframework.graphql.data.method.annotation.Argument; 6 | import org.springframework.stereotype.Controller; 7 | 8 | import java.util.Map; 9 | 10 | @Controller 11 | public class ProductResearchController { 12 | @EntityMapping 13 | public ProductResearch productResearch(@Argument("study") Map study) { 14 | return ProductResearch.resolveByCaseNumber(study.get("caseNumber")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/TracingInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.springframework.graphql.server.WebGraphQlInterceptor; 5 | import org.springframework.graphql.server.WebGraphQlRequest; 6 | import org.springframework.graphql.server.WebGraphQlResponse; 7 | import org.springframework.stereotype.Component; 8 | import reactor.core.publisher.Mono; 9 | 10 | import java.util.Collections; 11 | 12 | import static com.apollographql.federation.graphqljava.tracing.FederatedTracingInstrumentation.FEDERATED_TRACING_HEADER_NAME; 13 | 14 | @Component 15 | public class TracingInterceptor implements WebGraphQlInterceptor { 16 | 17 | @Override 18 | public @NotNull Mono intercept(WebGraphQlRequest request, @NotNull Chain chain) { 19 | String headerValue = request.getHeaders().getFirst(FEDERATED_TRACING_HEADER_NAME); 20 | if (headerValue != null) { 21 | request.configureExecutionInput((executionInput, builder) -> 22 | builder.graphQLContext(Collections.singletonMap(FEDERATED_TRACING_HEADER_NAME, headerValue)).build()); 23 | } 24 | return chain.next(request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/UserController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility; 2 | 3 | import com.apollographql.federation.compatibility.model.User; 4 | import org.springframework.graphql.data.federation.EntityMapping; 5 | import org.springframework.graphql.data.method.annotation.Argument; 6 | import org.springframework.graphql.data.method.annotation.SchemaMapping; 7 | import org.springframework.stereotype.Controller; 8 | 9 | @Controller 10 | public class UserController { 11 | 12 | @EntityMapping 13 | public User user(@Argument String email, @Argument Integer totalProductsCreated, @Argument Integer yearsOfEmployment) { 14 | final User user = new User(email); 15 | if (totalProductsCreated != null) { 16 | user.setTotalProductsCreated(totalProductsCreated); 17 | } 18 | if (yearsOfEmployment != null) { 19 | user.setYearsOfEmployment(yearsOfEmployment); 20 | } 21 | return user; 22 | } 23 | 24 | @SchemaMapping(typeName = "User", field = "averageProductsCreatedPerYear") 25 | public Integer getAverageProductsCreatedPerYear(User user) { 26 | if (user.getTotalProductsCreated() != null && user.getYearsOfEmployment() > 0) { 27 | return Math.round(1.0f * user.getTotalProductsCreated() / user.getYearsOfEmployment()); 28 | } else { 29 | return null; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/CaseStudy.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | public record CaseStudy(String caseNumber, String description) { 4 | } 5 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/DeprecatedProduct.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | public record DeprecatedProduct(String sku, String pkg, String reason, User createdBy) { 4 | 5 | public static DeprecatedProduct DEPRECATED_PRODUCT = new DeprecatedProduct("apollo-federation-v1", "@apollo/federation-v1", "Migrate to Federation V2"); 6 | 7 | public DeprecatedProduct(String sku, String pkg, String reason) { 8 | this(sku, pkg, reason, User.DEFAULT_USER); 9 | } 10 | 11 | public static DeprecatedProduct resolveBySkuAndPackage(String sku, String pkg) { 12 | if (DEPRECATED_PRODUCT.sku.equals(sku) && DEPRECATED_PRODUCT.pkg.equals(pkg)) { 13 | return DEPRECATED_PRODUCT; 14 | } else { 15 | return null; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/Inventory.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | import java.util.List; 4 | 5 | import static com.apollographql.federation.compatibility.model.DeprecatedProduct.DEPRECATED_PRODUCT; 6 | 7 | public record Inventory(String id, List deprecatedProducts) { 8 | 9 | public Inventory(String id) { 10 | this(id, List.of(DEPRECATED_PRODUCT)); 11 | } 12 | 13 | public static Inventory resolveById(String id) { 14 | if ("apollo-oss".equals(id)) { 15 | return new Inventory(id); 16 | } 17 | return null; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/Product.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.Stream; 7 | 8 | public record Product(String id, String sku, String pkg, ProductVariation variation, ProductDimension dimensions, User createdBy, List research) { 9 | 10 | private static final Map PRODUCTS = Stream.of( 11 | new Product("apollo-federation", "federation", "@apollo/federation", "OSS", List.of(ProductResearch.FEDERATION_STUDY)), 12 | new Product("apollo-studio", "studio", "", "platform", List.of(ProductResearch.STUDIO_STUDY)) 13 | ).collect(Collectors.toMap(Product::id, product -> product)); 14 | 15 | public Product(String id, String sku, String pkg, String variationId, List research) { 16 | this( 17 | id, 18 | sku, 19 | pkg, 20 | new ProductVariation(variationId), 21 | new ProductDimension("small", 1, "kg"), 22 | User.DEFAULT_USER, research 23 | ); 24 | } 25 | 26 | public static Product resolveById(String id) { 27 | return PRODUCTS.get(id); 28 | } 29 | 30 | public static Product resolveBySkuAndPackage(String sku, String pkg) { 31 | for (Product product : PRODUCTS.values()) { 32 | if (product.sku().equals(sku) && product.pkg().equals(pkg)) { 33 | return product; 34 | } 35 | } 36 | return null; 37 | } 38 | 39 | public static Product resolveBySkuAndVariation(String sku, String variationId) { 40 | for (Product product : PRODUCTS.values()) { 41 | if (product.sku().equals(sku) && product.variation().id().equals(variationId)) { 42 | return product; 43 | } 44 | } 45 | return null; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/ProductDimension.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | public record ProductDimension(String size, float weight, String unit) { 4 | } 5 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/ProductResearch.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | import java.util.List; 4 | 5 | public record ProductResearch(CaseStudy study, String outcome) { 6 | public static final ProductResearch FEDERATION_STUDY = new ProductResearch(new CaseStudy("1234", "Federation Study")); 7 | public static final ProductResearch STUDIO_STUDY = new ProductResearch(new CaseStudy("1235", "Studio Study")); 8 | public static final List RESEARCH_LIST = List.of(FEDERATION_STUDY, STUDIO_STUDY); 9 | 10 | public ProductResearch(CaseStudy study) { 11 | this(study, null); 12 | } 13 | 14 | public static ProductResearch resolveByCaseNumber(String caseNumber) { 15 | return RESEARCH_LIST.stream() 16 | .filter(research -> research.study.caseNumber().equals(caseNumber)) 17 | .findAny() 18 | .orElse(null); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/ProductVariation.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | public record ProductVariation(String id) { 4 | } 5 | -------------------------------------------------------------------------------- /compatibility/src/main/java/com/apollographql/federation/compatibility/model/User.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.compatibility.model; 2 | 3 | public class User { 4 | 5 | public static User DEFAULT_USER = new User("support@apollographql.com"); 6 | 7 | private final String email; 8 | private final String name; 9 | private Integer totalProductsCreated; 10 | 11 | private int yearsOfEmployment; 12 | 13 | public User(String email) { 14 | this.email = email; 15 | this.totalProductsCreated = 1337; 16 | this.name = "Jane Smith"; 17 | } 18 | 19 | public String getEmail() { 20 | return email; 21 | } 22 | 23 | public String getName() { 24 | return name; 25 | } 26 | 27 | public Integer getTotalProductsCreated() { 28 | return totalProductsCreated; 29 | } 30 | 31 | public void setTotalProductsCreated(Integer totalProductsCreated) { 32 | this.totalProductsCreated = totalProductsCreated; 33 | } 34 | 35 | public int getYearsOfEmployment() { 36 | return yearsOfEmployment; 37 | } 38 | 39 | public void setYearsOfEmployment(int yearsOfEmployment) { 40 | this.yearsOfEmployment = yearsOfEmployment; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /compatibility/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: federation-jvm-compatibility 4 | graphql: 5 | path: / 6 | graphiql: 7 | enabled: true 8 | schema: 9 | printer: 10 | enabled: true 11 | server: 12 | port: 4001 13 | -------------------------------------------------------------------------------- /compatibility/src/main/resources/graphql/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.5", 4 | import: [ 5 | "@composeDirective", 6 | "@extends", 7 | "@external", 8 | "@inaccessible", 9 | "@interfaceObject", 10 | "@key", 11 | "@override", 12 | "@provides", 13 | "@requires", 14 | "@shareable", 15 | "@tag" 16 | ] 17 | ) 18 | @link(url: "https://myspecs.dev/myCustomDirective/v1.0", import: ["@custom"]) 19 | @composeDirective(name: "@custom") 20 | 21 | directive @custom on OBJECT 22 | 23 | type Product @custom @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") { 24 | id: ID! 25 | sku: String 26 | package: String 27 | variation: ProductVariation 28 | dimensions: ProductDimension 29 | createdBy: User @provides(fields: "totalProductsCreated") 30 | notes: String @tag(name: "internal") 31 | research: [ProductResearch!]! 32 | } 33 | 34 | type DeprecatedProduct @key(fields: "sku package") { 35 | sku: String! 36 | package: String! 37 | reason: String 38 | createdBy: User 39 | } 40 | 41 | type ProductVariation { 42 | id: ID! 43 | } 44 | 45 | type ProductResearch @key(fields: "study { caseNumber }") { 46 | study: CaseStudy! 47 | outcome: String 48 | } 49 | 50 | type CaseStudy { 51 | caseNumber: ID! 52 | description: String 53 | } 54 | 55 | type ProductDimension @shareable { 56 | size: String 57 | weight: Float 58 | unit: String @inaccessible 59 | } 60 | 61 | type Query { 62 | product(id: ID!): Product 63 | deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead") 64 | } 65 | 66 | type User @key(fields: "email") { 67 | averageProductsCreatedPerYear: Int @requires(fields: "totalProductsCreated yearsOfEmployment") 68 | email: ID! 69 | name: String @override(from: "users") 70 | totalProductsCreated: Int @external 71 | yearsOfEmployment: Int! @external 72 | } 73 | 74 | type Inventory @interfaceObject @key(fields: "id") { 75 | id: ID! 76 | deprecatedProducts: [DeprecatedProduct!]! 77 | } 78 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = com.apollographql.federation 2 | version = 3.0-SNAPSHOT 3 | 4 | # dependencies 5 | annotationsVersion = 24.1.0 6 | graphQLJavaVersion = 22.3 7 | # generated proto v3 messages can be used with v3 and v4 8 | protobufVersion = 3.25.5 9 | slf4jVersion = 2.0.16 10 | springBootVersion = 3.3.6 11 | 12 | # test dependencies 13 | junitVersion = 5.10.5 14 | mockWebServerVersion = 4.12.0 15 | springGraphQLVersion = 1.3.3 16 | reactorVersion = 3.6.12 17 | 18 | # plugin versions 19 | nexusPublishPluginVersion = 1.1.0 20 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/apollographql/federation-jvm/e598034983460abc35b6c87652c6c9c400465afa/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 1>&2 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 48 | echo. 1>&2 49 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 50 | echo location of your Java installation. 1>&2 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 1>&2 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 62 | echo. 1>&2 63 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 64 | echo location of your Java installation. 1>&2 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /graphql-java-support/build.gradle.kts: -------------------------------------------------------------------------------- 1 | description = "GraphQL Java server support for Apollo Federation" 2 | 3 | plugins { 4 | id("com.apollographql.federation.java-conventions") 5 | id("com.google.protobuf") version "0.9.4" 6 | } 7 | 8 | val annotationsVersion: String by project 9 | val graphQLJavaVersion: String by project 10 | val protobufVersion: String by project 11 | val slf4jVersion: String by project 12 | dependencies { 13 | compileOnly("org.jetbrains:annotations:$annotationsVersion") 14 | api("com.graphql-java:graphql-java:$graphQLJavaVersion") 15 | api("org.slf4j:slf4j-api:$slf4jVersion") 16 | api("com.google.protobuf:protobuf-java:$protobufVersion") 17 | testCompileOnly("org.jetbrains:annotations:$annotationsVersion") 18 | } 19 | 20 | protobuf { 21 | protoc { 22 | artifact = "com.google.protobuf:protoc:$protobufVersion" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/FederationError.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import graphql.ErrorClassification; 4 | import graphql.ErrorType; 5 | import graphql.GraphQLError; 6 | import graphql.GraphQLException; 7 | import graphql.language.SourceLocation; 8 | import java.util.Collections; 9 | import java.util.List; 10 | 11 | public class FederationError extends GraphQLException implements GraphQLError { 12 | private static final List NO_WHERE = 13 | Collections.singletonList(new SourceLocation(-1, -1)); 14 | 15 | FederationError(String message) { 16 | super(message); 17 | } 18 | 19 | @Override 20 | public List getLocations() { 21 | return NO_WHERE; 22 | } 23 | 24 | @Override 25 | public ErrorClassification getErrorType() { 26 | return ErrorType.ValidationError; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/_Any.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import graphql.GraphQLContext; 4 | import graphql.execution.CoercedVariables; 5 | import graphql.language.ArrayValue; 6 | import graphql.language.BooleanValue; 7 | import graphql.language.EnumValue; 8 | import graphql.language.FloatValue; 9 | import graphql.language.IntValue; 10 | import graphql.language.NullValue; 11 | import graphql.language.ObjectField; 12 | import graphql.language.ObjectValue; 13 | import graphql.language.StringValue; 14 | import graphql.language.Value; 15 | import graphql.schema.Coercing; 16 | import graphql.schema.CoercingParseLiteralException; 17 | import graphql.schema.CoercingParseValueException; 18 | import graphql.schema.CoercingSerializeException; 19 | import graphql.schema.GraphQLScalarType; 20 | import java.util.Locale; 21 | import java.util.stream.Collectors; 22 | import org.jetbrains.annotations.NotNull; 23 | import org.jetbrains.annotations.Nullable; 24 | 25 | public final class _Any { 26 | private _Any() { 27 | // hidden constructor 28 | } 29 | 30 | public static final String typeName = "_Any"; 31 | 32 | /** Coercing logic for serializing/deserializing of _Any scalar */ 33 | private static final Coercing coercing = 34 | new Coercing() { 35 | @Override 36 | public Object serialize( 37 | @NotNull Object dataFetcherResult, 38 | @NotNull GraphQLContext graphQLContext, 39 | @NotNull Locale locale) 40 | throws CoercingSerializeException { 41 | return dataFetcherResult; 42 | } 43 | 44 | @Override 45 | public Object parseValue( 46 | @NotNull Object input, @NotNull GraphQLContext graphQLContext, @NotNull Locale locale) 47 | throws CoercingParseValueException { 48 | return input; 49 | } 50 | 51 | @Nullable 52 | @Override 53 | public Object parseLiteral( 54 | @NotNull Value input, 55 | @NotNull CoercedVariables variables, 56 | @NotNull GraphQLContext graphQLContext, 57 | @NotNull Locale locale) 58 | throws CoercingParseLiteralException { 59 | if (input instanceof NullValue) { 60 | return null; 61 | } else if (input instanceof FloatValue) { 62 | return ((FloatValue) input).getValue(); 63 | } else if (input instanceof StringValue) { 64 | return ((StringValue) input).getValue(); 65 | } else if (input instanceof IntValue) { 66 | return ((IntValue) input).getValue(); 67 | } else if (input instanceof BooleanValue) { 68 | return ((BooleanValue) input).isValue(); 69 | } else if (input instanceof EnumValue) { 70 | return ((EnumValue) input).getName(); 71 | } else if (input instanceof ArrayValue) { 72 | return ((ArrayValue) input) 73 | .getValues().stream() 74 | .map((value) -> parseLiteral(value, variables, graphQLContext, locale)) 75 | .collect(Collectors.toList()); 76 | } else if (input instanceof ObjectValue) { 77 | return ((ObjectValue) input) 78 | .getObjectFields().stream() 79 | .collect( 80 | Collectors.toMap( 81 | ObjectField::getName, 82 | f -> parseLiteral(f.getValue(), variables, graphQLContext, locale))); 83 | } else { 84 | throw new CoercingParseLiteralException( 85 | "Cannot parse input(" + input + ") to Any scalar"); 86 | } 87 | } 88 | }; 89 | 90 | public static GraphQLScalarType type = 91 | GraphQLScalarType.newScalar().name(typeName).coercing(coercing).build(); 92 | } 93 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/_Entity.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import static graphql.schema.GraphQLArgument.newArgument; 4 | import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; 5 | 6 | import graphql.schema.GraphQLFieldDefinition; 7 | import graphql.schema.GraphQLList; 8 | import graphql.schema.GraphQLNonNull; 9 | import graphql.schema.GraphQLTypeReference; 10 | import graphql.schema.GraphQLUnionType; 11 | import java.util.Set; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public final class _Entity { 15 | public static final String argumentName = "representations"; 16 | public static final String typeName = "_Entity"; 17 | public static final String fieldName = "_entities"; 18 | 19 | private _Entity() {} 20 | 21 | // graphql-java will mutate GraphQLTypeReference in-place, 22 | // so we need to create a new instance every time. 23 | static GraphQLFieldDefinition field(@NotNull Set typeNames) { 24 | return newFieldDefinition() 25 | .name(fieldName) 26 | .argument( 27 | newArgument() 28 | .name(argumentName) 29 | .type( 30 | new GraphQLNonNull( 31 | new GraphQLList( 32 | new GraphQLNonNull(new GraphQLTypeReference(_Any.typeName))))) 33 | .build()) 34 | .type( 35 | new GraphQLNonNull( 36 | new GraphQLList( 37 | GraphQLUnionType.newUnionType() 38 | .name(typeName) 39 | .possibleTypes( 40 | typeNames.stream() 41 | .map(GraphQLTypeReference::new) 42 | .toArray(GraphQLTypeReference[]::new)) 43 | .build()))) 44 | .build(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/_FieldSet.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import graphql.Scalars; 4 | import graphql.language.ScalarTypeDefinition; 5 | import graphql.schema.GraphQLScalarType; 6 | 7 | public final class _FieldSet { 8 | public static final String typeName = "_FieldSet"; 9 | 10 | public static GraphQLScalarType type = 11 | GraphQLScalarType.newScalar(Scalars.GraphQLString) 12 | .name(typeName) 13 | .description(null) 14 | .coercing(Scalars.GraphQLString.getCoercing()) 15 | .build(); 16 | 17 | public static final ScalarTypeDefinition definition = 18 | ScalarTypeDefinition.newScalarTypeDefinition().name(typeName).build(); 19 | 20 | private _FieldSet() { 21 | // hidden constructor 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/_Service.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition; 4 | import static graphql.schema.GraphQLObjectType.newObject; 5 | 6 | import graphql.Scalars; 7 | import graphql.schema.GraphQLFieldDefinition; 8 | import graphql.schema.GraphQLNonNull; 9 | import graphql.schema.GraphQLObjectType; 10 | 11 | public final class _Service { 12 | public static final String typeName = "_Service"; 13 | public static final String fieldName = "_service"; 14 | static final String sdlFieldName = "sdl"; 15 | 16 | static final GraphQLObjectType type = 17 | newObject() 18 | .name(typeName) 19 | .field( 20 | newFieldDefinition() 21 | .name(sdlFieldName) 22 | .type(new GraphQLNonNull(Scalars.GraphQLString)) 23 | .build()) 24 | .build(); 25 | 26 | static final GraphQLFieldDefinition field = 27 | newFieldDefinition().name(fieldName).type(GraphQLNonNull.nonNull(type)).build(); 28 | 29 | private _Service() {} 30 | } 31 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/directives/LinkImportsRenamingVisitor.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.directives; 2 | 3 | import static graphql.util.TreeTransformerUtil.changeNode; 4 | 5 | import com.apollographql.federation.graphqljava.exceptions.UnsupportedRenameException; 6 | import graphql.language.DirectiveDefinition; 7 | import graphql.language.EnumTypeDefinition; 8 | import graphql.language.NamedNode; 9 | import graphql.language.Node; 10 | import graphql.language.NodeVisitorStub; 11 | import graphql.language.ScalarTypeDefinition; 12 | import graphql.language.TypeName; 13 | import graphql.util.TraversalControl; 14 | import graphql.util.TraverserContext; 15 | import java.util.Arrays; 16 | import java.util.HashSet; 17 | import java.util.Map; 18 | import java.util.Set; 19 | 20 | /** 21 | * GraphQL schema node visitor that supports renaming imported elements specified in the @link 22 | * directive. 23 | */ 24 | class LinkImportsRenamingVisitor extends NodeVisitorStub { 25 | private static final Set BUILT_IN_SCALARS = 26 | new HashSet<>(Arrays.asList("String", "Boolean", "Int", "Float", "ID")); 27 | 28 | private final Map fed2Imports; 29 | 30 | public LinkImportsRenamingVisitor(Map fed2Imports) { 31 | this.fed2Imports = fed2Imports; 32 | } 33 | 34 | @Override 35 | protected TraversalControl visitNode(Node node, TraverserContext context) { 36 | if (node instanceof NamedNode) { 37 | Node newNode = null; 38 | if (node instanceof TypeName) { 39 | String newName = newName(((NamedNode) node).getName(), fed2Imports, false); 40 | newNode = ((TypeName) node).transform(builder -> builder.name(newName)); 41 | } else if (node instanceof ScalarTypeDefinition) { 42 | String newName = newName(((NamedNode) node).getName(), fed2Imports, false); 43 | newNode = ((ScalarTypeDefinition) node).transform(builder -> builder.name(newName)); 44 | } else if (node instanceof DirectiveDefinition) { 45 | String newName = newName(((NamedNode) node).getName(), fed2Imports, true); 46 | newNode = ((DirectiveDefinition) node).transform(builder -> builder.name(newName)); 47 | } else if (node instanceof EnumTypeDefinition) { 48 | String newName = newName(((NamedNode) node).getName(), fed2Imports, true); 49 | newNode = ((EnumTypeDefinition) node).transform(builder -> builder.name(newName)); 50 | } 51 | if (newNode != null) { 52 | return changeNode(context, newNode); 53 | } 54 | } 55 | return super.visitNode(node, context); 56 | } 57 | 58 | private String newName(String name, Map fed2Imports, boolean isDirective) { 59 | String key; 60 | if (isDirective) { 61 | key = "@" + name; 62 | } else { 63 | key = name; 64 | } 65 | 66 | if (BUILT_IN_SCALARS.contains(key)) { 67 | // Do not rename builtin types 68 | return name; 69 | } 70 | 71 | if (fed2Imports.containsKey(key)) { 72 | String newName = fed2Imports.get(key); 73 | if (("@tag".equals(key) || "@inaccessible".equals(key)) && !newName.equals(key)) { 74 | throw new UnsupportedRenameException(key); 75 | } 76 | 77 | if (isDirective) { 78 | return newName.substring(1); 79 | } else { 80 | return newName; 81 | } 82 | } else { 83 | if (name.equals("inaccessible") || name.equals("tag")) { 84 | return name; 85 | } else if (name.equals("Import") || name.equals("Purpose")) { 86 | return "link__" + name; 87 | } else { 88 | // apply default namespace 89 | return "federation__" + name; 90 | } 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/exceptions/MissingKeyException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.exceptions; 2 | 3 | /** 4 | * Exception thrown when GraphQL object type does not specify all @keys specified on its interface. 5 | */ 6 | public class MissingKeyException extends RuntimeException { 7 | 8 | public MissingKeyException(String objectType, String interfaceType) { 9 | super( 10 | String.format( 11 | "Object %s does not specify @key fields specified by its interface %s", 12 | objectType, interfaceType)); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/exceptions/MultipleFederationLinksException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.exceptions; 2 | 3 | import graphql.language.Directive; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | /** Exception thrown when schema defines multiple `@link` directives importing federation spec. */ 8 | public class MultipleFederationLinksException extends RuntimeException { 9 | 10 | public MultipleFederationLinksException(List directives) { 11 | super( 12 | "Schema imports multiple federation specs: " 13 | + directives.stream().map(Directive::toString).collect(Collectors.joining())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/exceptions/UnsupportedFederationVersionException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.exceptions; 2 | 3 | /** Exception thrown while processing link that specifies currently not supported version. */ 4 | public class UnsupportedFederationVersionException extends RuntimeException { 5 | public UnsupportedFederationVersionException(String federationSpec) { 6 | super("Specified federation spec = " + federationSpec + " is currently not supported"); 7 | } 8 | 9 | public UnsupportedFederationVersionException(String federationSpec, Exception e) { 10 | super("Specified federation spec = " + federationSpec + " is currently not supported", e); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/exceptions/UnsupportedLinkImportException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.exceptions; 2 | 3 | import graphql.language.Value; 4 | 5 | /** 6 | * Exception thrown when processing invalid `@link` import definitions. 7 | * 8 | *

Unsupported imports:
9 | * - specifying object import without specifying String name
10 | * - specifying object rename that is not a String
11 | * - attempting to import definition that is not a String nor an object definition
12 | * - attempting to import 13 | */ 14 | public class UnsupportedLinkImportException extends RuntimeException { 15 | 16 | public UnsupportedLinkImportException(Value importedDefinition) { 17 | super("Unsupported import: " + importedDefinition); 18 | } 19 | 20 | public UnsupportedLinkImportException(String importedDefinition, int minVersion, int version) { 21 | super( 22 | String.format( 23 | "Federation v%.1f feature %s imported using old Federation v%.1f version", 24 | minVersion / 10.0, importedDefinition, version / 10.0)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/exceptions/UnsupportedRenameException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.exceptions; 2 | 3 | /** Exception thrown when attempting to rename directive imports that cannot be renamed. */ 4 | public class UnsupportedRenameException extends RuntimeException { 5 | 6 | public UnsupportedRenameException(String name) { 7 | super("Current version of Apollo Federation does not allow renaming " + name + " directive."); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/java/com/apollographql/federation/graphqljava/link__Import.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import graphql.Scalars; 4 | import graphql.language.ScalarTypeDefinition; 5 | import graphql.schema.GraphQLScalarType; 6 | 7 | public class link__Import { 8 | static final String typeName = "link__Import"; 9 | 10 | public static GraphQLScalarType type = 11 | GraphQLScalarType.newScalar() 12 | .name(typeName) 13 | .description(null) 14 | .coercing(Scalars.GraphQLString.getCoercing()) 15 | .build(); 16 | 17 | public static final ScalarTypeDefinition definition = 18 | ScalarTypeDefinition.newScalarTypeDefinition().name(typeName).build(); 19 | } 20 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_0.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @shareable on FIELD_DEFINITION | OBJECT 10 | directive @extends on OBJECT | INTERFACE 11 | directive @override(from: String!) on FIELD_DEFINITION 12 | directive @inaccessible on 13 | | FIELD_DEFINITION 14 | | OBJECT 15 | | INTERFACE 16 | | UNION 17 | | ENUM 18 | | ENUM_VALUE 19 | | SCALAR 20 | | INPUT_OBJECT 21 | | INPUT_FIELD_DEFINITION 22 | | ARGUMENT_DEFINITION 23 | directive @tag(name: String!) repeatable on 24 | | FIELD_DEFINITION 25 | | INTERFACE 26 | | OBJECT 27 | | UNION 28 | | ARGUMENT_DEFINITION 29 | | SCALAR 30 | | ENUM 31 | | ENUM_VALUE 32 | | INPUT_OBJECT 33 | | INPUT_FIELD_DEFINITION 34 | scalar FieldSet 35 | 36 | # 37 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 38 | # 39 | 40 | directive @link( 41 | url: String!, 42 | as: String, 43 | import: [Import], 44 | for: Purpose) 45 | repeatable on SCHEMA 46 | 47 | scalar Import 48 | 49 | enum Purpose { 50 | SECURITY 51 | EXECUTION 52 | } 53 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_1.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @shareable on FIELD_DEFINITION | OBJECT 10 | directive @extends on OBJECT | INTERFACE 11 | directive @override(from: String!) on FIELD_DEFINITION 12 | directive @inaccessible on 13 | | FIELD_DEFINITION 14 | | OBJECT 15 | | INTERFACE 16 | | UNION 17 | | ENUM 18 | | ENUM_VALUE 19 | | SCALAR 20 | | INPUT_OBJECT 21 | | INPUT_FIELD_DEFINITION 22 | | ARGUMENT_DEFINITION 23 | directive @tag(name: String!) repeatable on 24 | | FIELD_DEFINITION 25 | | INTERFACE 26 | | OBJECT 27 | | UNION 28 | | ARGUMENT_DEFINITION 29 | | SCALAR 30 | | ENUM 31 | | ENUM_VALUE 32 | | INPUT_OBJECT 33 | | INPUT_FIELD_DEFINITION 34 | scalar FieldSet 35 | 36 | # 37 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 38 | # 39 | 40 | directive @link( 41 | url: String!, 42 | as: String, 43 | import: [Import], 44 | for: Purpose) 45 | repeatable on SCHEMA 46 | 47 | scalar Import 48 | 49 | enum Purpose { 50 | SECURITY 51 | EXECUTION 52 | } 53 | 54 | # 55 | # federation-v2.1 56 | # 57 | 58 | directive @composeDirective(name: String!) repeatable on SCHEMA 59 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_2.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @override(from: String!) on FIELD_DEFINITION 11 | directive @inaccessible on 12 | | FIELD_DEFINITION 13 | | OBJECT 14 | | INTERFACE 15 | | UNION 16 | | ENUM 17 | | ENUM_VALUE 18 | | SCALAR 19 | | INPUT_OBJECT 20 | | INPUT_FIELD_DEFINITION 21 | | ARGUMENT_DEFINITION 22 | directive @tag(name: String!) repeatable on 23 | | FIELD_DEFINITION 24 | | INTERFACE 25 | | OBJECT 26 | | UNION 27 | | ARGUMENT_DEFINITION 28 | | SCALAR 29 | | ENUM 30 | | ENUM_VALUE 31 | | INPUT_OBJECT 32 | | INPUT_FIELD_DEFINITION 33 | scalar FieldSet 34 | 35 | # 36 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 37 | # 38 | 39 | directive @link( 40 | url: String!, 41 | as: String, 42 | import: [Import], 43 | for: Purpose) 44 | repeatable on SCHEMA 45 | 46 | scalar Import 47 | 48 | enum Purpose { 49 | SECURITY 50 | EXECUTION 51 | } 52 | 53 | # 54 | # federation-v2.1 55 | # 56 | 57 | directive @composeDirective(name: String!) repeatable on SCHEMA 58 | 59 | # 60 | # federation-v2.2 61 | # 62 | 63 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 64 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_3.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @override(from: String!) on FIELD_DEFINITION 11 | directive @inaccessible on 12 | | FIELD_DEFINITION 13 | | OBJECT 14 | | INTERFACE 15 | | UNION 16 | | ENUM 17 | | ENUM_VALUE 18 | | SCALAR 19 | | INPUT_OBJECT 20 | | INPUT_FIELD_DEFINITION 21 | | ARGUMENT_DEFINITION 22 | scalar FieldSet 23 | 24 | # 25 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 26 | # 27 | 28 | directive @link( 29 | url: String!, 30 | as: String, 31 | import: [Import], 32 | for: Purpose) 33 | repeatable on SCHEMA 34 | 35 | scalar Import 36 | 37 | enum Purpose { 38 | SECURITY 39 | EXECUTION 40 | } 41 | 42 | # 43 | # federation-v2.1 44 | # 45 | 46 | directive @composeDirective(name: String!) repeatable on SCHEMA 47 | 48 | # 49 | # federation-v2.2 50 | # 51 | 52 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 53 | 54 | # 55 | # federation-v2.3 56 | # 57 | 58 | directive @interfaceObject on OBJECT 59 | 60 | directive @tag(name: String!) repeatable on 61 | | FIELD_DEFINITION 62 | | INTERFACE 63 | | OBJECT 64 | | UNION 65 | | ARGUMENT_DEFINITION 66 | | SCALAR 67 | | ENUM 68 | | ENUM_VALUE 69 | | INPUT_OBJECT 70 | | INPUT_FIELD_DEFINITION 71 | | SCHEMA 72 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_5.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @override(from: String!) on FIELD_DEFINITION 11 | directive @inaccessible on 12 | | FIELD_DEFINITION 13 | | OBJECT 14 | | INTERFACE 15 | | UNION 16 | | ENUM 17 | | ENUM_VALUE 18 | | SCALAR 19 | | INPUT_OBJECT 20 | | INPUT_FIELD_DEFINITION 21 | | ARGUMENT_DEFINITION 22 | scalar FieldSet 23 | 24 | # 25 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 26 | # 27 | 28 | directive @link( 29 | url: String!, 30 | as: String, 31 | import: [Import], 32 | for: Purpose) 33 | repeatable on SCHEMA 34 | 35 | scalar Import 36 | 37 | enum Purpose { 38 | SECURITY 39 | EXECUTION 40 | } 41 | 42 | # 43 | # federation-v2.1 44 | # 45 | 46 | directive @composeDirective(name: String!) repeatable on SCHEMA 47 | 48 | # 49 | # federation-v2.2 50 | # 51 | 52 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 53 | 54 | # 55 | # federation-v2.3 56 | # 57 | 58 | directive @interfaceObject on OBJECT 59 | 60 | directive @tag(name: String!) repeatable on 61 | | FIELD_DEFINITION 62 | | INTERFACE 63 | | OBJECT 64 | | UNION 65 | | ARGUMENT_DEFINITION 66 | | SCALAR 67 | | ENUM 68 | | ENUM_VALUE 69 | | INPUT_OBJECT 70 | | INPUT_FIELD_DEFINITION 71 | | SCHEMA 72 | 73 | # 74 | # federation-v2.5 75 | # 76 | 77 | directive @authenticated on 78 | ENUM 79 | | FIELD_DEFINITION 80 | | INTERFACE 81 | | OBJECT 82 | | SCALAR 83 | 84 | directive @requiresScopes(scopes: [[Scope!]!]!) on 85 | ENUM 86 | | FIELD_DEFINITION 87 | | INTERFACE 88 | | OBJECT 89 | | SCALAR 90 | 91 | scalar Scope 92 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_6.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @override(from: String!) on FIELD_DEFINITION 11 | directive @inaccessible on 12 | | FIELD_DEFINITION 13 | | OBJECT 14 | | INTERFACE 15 | | UNION 16 | | ENUM 17 | | ENUM_VALUE 18 | | SCALAR 19 | | INPUT_OBJECT 20 | | INPUT_FIELD_DEFINITION 21 | | ARGUMENT_DEFINITION 22 | directive @tag(name: String!) repeatable on 23 | | FIELD_DEFINITION 24 | | INTERFACE 25 | | OBJECT 26 | | UNION 27 | | ARGUMENT_DEFINITION 28 | | SCALAR 29 | | ENUM 30 | | ENUM_VALUE 31 | | INPUT_OBJECT 32 | | INPUT_FIELD_DEFINITION 33 | scalar FieldSet 34 | 35 | # 36 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 37 | # 38 | 39 | directive @link( 40 | url: String!, 41 | as: String, 42 | import: [Import], 43 | for: Purpose) 44 | repeatable on SCHEMA 45 | 46 | scalar Import 47 | 48 | enum Purpose { 49 | SECURITY 50 | EXECUTION 51 | } 52 | 53 | # 54 | # federation-v2.1 55 | # 56 | 57 | directive @composeDirective(name: String!) repeatable on SCHEMA 58 | 59 | # 60 | # federation-v2.2 61 | # 62 | 63 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 64 | 65 | # 66 | # federation-v2.3 67 | # 68 | 69 | directive @interfaceObject on OBJECT 70 | 71 | directive @tag(name: String!) repeatable on 72 | | FIELD_DEFINITION 73 | | INTERFACE 74 | | OBJECT 75 | | UNION 76 | | ARGUMENT_DEFINITION 77 | | SCALAR 78 | | ENUM 79 | | ENUM_VALUE 80 | | INPUT_OBJECT 81 | | INPUT_FIELD_DEFINITION 82 | | SCHEMA 83 | 84 | # 85 | # federation-v2.5 86 | # 87 | 88 | directive @authenticated on 89 | ENUM 90 | | FIELD_DEFINITION 91 | | INTERFACE 92 | | OBJECT 93 | | SCALAR 94 | 95 | directive @requiresScopes(scopes: [[Scope!]!]!) on 96 | ENUM 97 | | FIELD_DEFINITION 98 | | INTERFACE 99 | | OBJECT 100 | | SCALAR 101 | 102 | scalar Scope 103 | 104 | # 105 | # federation-v2.6 106 | # 107 | 108 | directive @policy(policies: [[Policy!]!]!) on 109 | ENUM 110 | | FIELD_DEFINITION 111 | | INTERFACE 112 | | OBJECT 113 | | SCALAR 114 | 115 | scalar Policy 116 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_7.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @inaccessible on 11 | | FIELD_DEFINITION 12 | | OBJECT 13 | | INTERFACE 14 | | UNION 15 | | ENUM 16 | | ENUM_VALUE 17 | | SCALAR 18 | | INPUT_OBJECT 19 | | INPUT_FIELD_DEFINITION 20 | | ARGUMENT_DEFINITION 21 | directive @tag(name: String!) repeatable on 22 | | FIELD_DEFINITION 23 | | INTERFACE 24 | | OBJECT 25 | | UNION 26 | | ARGUMENT_DEFINITION 27 | | SCALAR 28 | | ENUM 29 | | ENUM_VALUE 30 | | INPUT_OBJECT 31 | | INPUT_FIELD_DEFINITION 32 | scalar FieldSet 33 | 34 | # 35 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 36 | # 37 | 38 | directive @link( 39 | url: String!, 40 | as: String, 41 | import: [Import], 42 | for: Purpose) 43 | repeatable on SCHEMA 44 | 45 | scalar Import 46 | 47 | enum Purpose { 48 | SECURITY 49 | EXECUTION 50 | } 51 | 52 | # 53 | # federation-v2.1 54 | # 55 | 56 | directive @composeDirective(name: String!) repeatable on SCHEMA 57 | 58 | # 59 | # federation-v2.2 60 | # 61 | 62 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 63 | 64 | # 65 | # federation-v2.3 66 | # 67 | 68 | directive @interfaceObject on OBJECT 69 | 70 | directive @tag(name: String!) repeatable on 71 | | FIELD_DEFINITION 72 | | INTERFACE 73 | | OBJECT 74 | | UNION 75 | | ARGUMENT_DEFINITION 76 | | SCALAR 77 | | ENUM 78 | | ENUM_VALUE 79 | | INPUT_OBJECT 80 | | INPUT_FIELD_DEFINITION 81 | | SCHEMA 82 | 83 | # 84 | # federation-v2.5 85 | # 86 | 87 | directive @authenticated on 88 | ENUM 89 | | FIELD_DEFINITION 90 | | INTERFACE 91 | | OBJECT 92 | | SCALAR 93 | 94 | directive @requiresScopes(scopes: [[Scope!]!]!) on 95 | ENUM 96 | | FIELD_DEFINITION 97 | | INTERFACE 98 | | OBJECT 99 | | SCALAR 100 | 101 | scalar Scope 102 | 103 | # 104 | # federation-v2.6 105 | # 106 | 107 | directive @policy(policies: [[Policy!]!]!) on 108 | ENUM 109 | | FIELD_DEFINITION 110 | | INTERFACE 111 | | OBJECT 112 | | SCALAR 113 | 114 | scalar Policy 115 | 116 | # 117 | # federation-v2.7 118 | # 119 | 120 | directive @override(from: String!, label: String) on FIELD_DEFINITION 121 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_8.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @inaccessible on 11 | | FIELD_DEFINITION 12 | | OBJECT 13 | | INTERFACE 14 | | UNION 15 | | ENUM 16 | | ENUM_VALUE 17 | | SCALAR 18 | | INPUT_OBJECT 19 | | INPUT_FIELD_DEFINITION 20 | | ARGUMENT_DEFINITION 21 | directive @tag(name: String!) repeatable on 22 | | FIELD_DEFINITION 23 | | INTERFACE 24 | | OBJECT 25 | | UNION 26 | | ARGUMENT_DEFINITION 27 | | SCALAR 28 | | ENUM 29 | | ENUM_VALUE 30 | | INPUT_OBJECT 31 | | INPUT_FIELD_DEFINITION 32 | scalar FieldSet 33 | 34 | # 35 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 36 | # 37 | 38 | directive @link( 39 | url: String!, 40 | as: String, 41 | import: [Import], 42 | for: Purpose) 43 | repeatable on SCHEMA 44 | 45 | scalar Import 46 | 47 | enum Purpose { 48 | SECURITY 49 | EXECUTION 50 | } 51 | 52 | # 53 | # federation-v2.1 54 | # 55 | 56 | directive @composeDirective(name: String!) repeatable on SCHEMA 57 | 58 | # 59 | # federation-v2.2 60 | # 61 | 62 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 63 | 64 | # 65 | # federation-v2.3 66 | # 67 | 68 | directive @interfaceObject on OBJECT 69 | 70 | # 71 | # federation-v2.5 72 | # 73 | 74 | directive @authenticated on 75 | ENUM 76 | | FIELD_DEFINITION 77 | | INTERFACE 78 | | OBJECT 79 | | SCALAR 80 | 81 | directive @requiresScopes(scopes: [[Scope!]!]!) on 82 | ENUM 83 | | FIELD_DEFINITION 84 | | INTERFACE 85 | | OBJECT 86 | | SCALAR 87 | 88 | scalar Scope 89 | 90 | # 91 | # federation-v2.6 92 | # 93 | 94 | directive @policy(policies: [[Policy!]!]!) on 95 | ENUM 96 | | FIELD_DEFINITION 97 | | INTERFACE 98 | | OBJECT 99 | | SCALAR 100 | 101 | scalar Policy 102 | 103 | # 104 | # federation-v2.7 105 | # 106 | 107 | directive @override(from: String!, label: String) on FIELD_DEFINITION 108 | 109 | # 110 | # federation-v2.8 111 | # 112 | 113 | scalar ContextFieldValue 114 | 115 | directive @context(name: String!) repeatable on INTERFACE | OBJECT | UNION 116 | 117 | directive @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITION 118 | -------------------------------------------------------------------------------- /graphql-java-support/src/main/resources/definitions_fed2_9.graphqls: -------------------------------------------------------------------------------- 1 | # 2 | # https://specs.apollo.dev/federation/v2.0/federation-v2.0.graphql 3 | # 4 | 5 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 6 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 7 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 8 | directive @external on OBJECT | FIELD_DEFINITION 9 | directive @extends on OBJECT | INTERFACE 10 | directive @inaccessible on 11 | | FIELD_DEFINITION 12 | | OBJECT 13 | | INTERFACE 14 | | UNION 15 | | ENUM 16 | | ENUM_VALUE 17 | | SCALAR 18 | | INPUT_OBJECT 19 | | INPUT_FIELD_DEFINITION 20 | | ARGUMENT_DEFINITION 21 | directive @tag(name: String!) repeatable on 22 | | FIELD_DEFINITION 23 | | INTERFACE 24 | | OBJECT 25 | | UNION 26 | | ARGUMENT_DEFINITION 27 | | SCALAR 28 | | ENUM 29 | | ENUM_VALUE 30 | | INPUT_OBJECT 31 | | INPUT_FIELD_DEFINITION 32 | scalar FieldSet 33 | 34 | # 35 | # https://specs.apollo.dev/link/v1.0/link-v1.0.graphql 36 | # 37 | 38 | directive @link( 39 | url: String!, 40 | as: String, 41 | import: [Import], 42 | for: Purpose) 43 | repeatable on SCHEMA 44 | 45 | scalar Import 46 | 47 | enum Purpose { 48 | SECURITY 49 | EXECUTION 50 | } 51 | 52 | # 53 | # federation-v2.1 54 | # 55 | 56 | directive @composeDirective(name: String!) repeatable on SCHEMA 57 | 58 | # 59 | # federation-v2.2 60 | # 61 | 62 | directive @shareable repeatable on FIELD_DEFINITION | OBJECT 63 | 64 | # 65 | # federation-v2.3 66 | # 67 | 68 | directive @interfaceObject on OBJECT 69 | 70 | # 71 | # federation-v2.5 72 | # 73 | 74 | directive @authenticated on 75 | ENUM 76 | | FIELD_DEFINITION 77 | | INTERFACE 78 | | OBJECT 79 | | SCALAR 80 | 81 | directive @requiresScopes(scopes: [[Scope!]!]!) on 82 | ENUM 83 | | FIELD_DEFINITION 84 | | INTERFACE 85 | | OBJECT 86 | | SCALAR 87 | 88 | scalar Scope 89 | 90 | # 91 | # federation-v2.6 92 | # 93 | 94 | directive @policy(policies: [[Policy!]!]!) on 95 | ENUM 96 | | FIELD_DEFINITION 97 | | INTERFACE 98 | | OBJECT 99 | | SCALAR 100 | 101 | scalar Policy 102 | 103 | # 104 | # federation-v2.7 105 | # 106 | 107 | directive @override(from: String!, label: String) on FIELD_DEFINITION 108 | 109 | # 110 | # federation-v2.8 111 | # 112 | 113 | scalar ContextFieldValue 114 | 115 | directive @context(name: String!) repeatable on INTERFACE | OBJECT | UNION 116 | 117 | directive @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITION 118 | 119 | # 120 | # federation-v2.9 121 | # 122 | 123 | directive @cost(weight: Int!) on 124 | ARGUMENT_DEFINITION 125 | | ENUM 126 | | FIELD_DEFINITION 127 | | INPUT_FIELD_DEFINITION 128 | | OBJECT 129 | | SCALAR 130 | 131 | directive @listSize( 132 | assumedSize: Int, 133 | slicingArguments: [String!], 134 | sizedFields: [String!], 135 | requireOneSlicingArgument: Boolean = true 136 | ) on FIELD_DEFINITION -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FederatedSchemaVerifier.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import static graphql.ExecutionInput.newExecutionInput; 4 | import static graphql.GraphQL.newGraphQL; 5 | import static org.junit.jupiter.api.Assertions.assertEquals; 6 | import static org.junit.jupiter.api.Assertions.assertInstanceOf; 7 | import static org.junit.jupiter.api.Assertions.assertNotNull; 8 | import static org.junit.jupiter.api.Assertions.assertTrue; 9 | 10 | import graphql.ExecutionResult; 11 | import graphql.Scalars; 12 | import graphql.schema.GraphQLFieldDefinition; 13 | import graphql.schema.GraphQLNonNull; 14 | import graphql.schema.GraphQLObjectType; 15 | import graphql.schema.GraphQLSchema; 16 | import graphql.schema.GraphQLType; 17 | import graphql.schema.idl.SchemaPrinter; 18 | import java.util.Map; 19 | import org.junit.jupiter.api.Assertions; 20 | 21 | final class FederatedSchemaVerifier { 22 | 23 | private FederatedSchemaVerifier() {} 24 | 25 | static ExecutionResult execute(GraphQLSchema schema, String query) { 26 | return newGraphQL(schema).build().execute(newExecutionInput().query(query).build()); 27 | } 28 | 29 | /** 30 | * Verifies passed in schema generates expected SDL. 31 | * 32 | * @param schema test schema 33 | * @param expectedSchemaSDL expected SDL 34 | */ 35 | public static void verifyFullSchema(GraphQLSchema schema, String expectedSchemaSDL) { 36 | Assertions.assertEquals( 37 | expectedSchemaSDL.trim(), 38 | new SchemaPrinter(SchemaPrinter.Options.defaultOptions().includeSchemaDefinition(true)) 39 | .print(schema) 40 | .trim(), 41 | "Generated schema SDL should match expected one"); 42 | } 43 | 44 | /** 45 | * Verifies that passed in schema: - contains `_Service { sdl: String! }` type - contains 46 | * `_service: _Service` query 47 | * 48 | * @param schema schema to be verified 49 | */ 50 | public static void verifySchemaContainsServiceFederationType(GraphQLSchema schema) { 51 | final GraphQLFieldDefinition serviceField = 52 | schema.getQueryType().getFieldDefinition("_service"); 53 | assertNotNull(serviceField, "_service field present"); 54 | final GraphQLType serviceType = schema.getType("_Service"); 55 | assertNotNull(serviceType, "_Service type present"); 56 | assertInstanceOf(GraphQLObjectType.class, serviceType, "_Service type is object type"); 57 | assertInstanceOf( 58 | GraphQLNonNull.class, serviceField.getType(), "_service returns non-nullable object"); 59 | final GraphQLNonNull nonNullableServiceType = (GraphQLNonNull) serviceField.getType(); 60 | assertEquals( 61 | serviceType, 62 | nonNullableServiceType.getWrappedType(), 63 | "_service returns non-nullable _Service"); 64 | final GraphQLFieldDefinition sdlField = 65 | ((GraphQLObjectType) serviceType).getFieldDefinition("sdl"); 66 | assertNotNull(sdlField, "sdl field present"); 67 | assertTrue( 68 | GraphQLNonNull.nonNull(Scalars.GraphQLString).isEqualTo(sdlField.getType()), 69 | "sdl returns String!"); 70 | } 71 | 72 | /** 73 | * Verifies `_service { sdl }` query returns expected SDL 74 | * 75 | * @param schema test schema 76 | * @param expectedServiceSDL expected SDL 77 | */ 78 | public static void verifyServiceSDL(GraphQLSchema schema, String expectedServiceSDL) { 79 | final ExecutionResult inspect = execute(schema, "{_service{sdl}}"); 80 | assertEquals(0, inspect.getErrors().size(), "No errors"); 81 | final Map data = inspect.getData(); 82 | assertNotNull(data); 83 | @SuppressWarnings("unchecked") 84 | final Map _service = (Map) data.get("_service"); 85 | assertNotNull(_service); 86 | final String sdl = (String) _service.get("sdl"); 87 | assertEquals(expectedServiceSDL.trim(), sdl.trim()); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.InputStreamReader; 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.stream.Collectors; 9 | 10 | public final class FileUtils { 11 | 12 | private static final String NEW_LINE_SEPARATOR = "\n"; 13 | 14 | public static String readResource(String name) { 15 | try (InputStream is = 16 | FederatedSchemaVerifier.class.getClassLoader().getResourceAsStream(name)) { 17 | if (is == null) { 18 | throw new RuntimeException("Unable to locate the target file " + name); 19 | } 20 | try (BufferedReader reader = 21 | new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) { 22 | String contents = reader.lines().collect(Collectors.joining(NEW_LINE_SEPARATOR)).trim(); 23 | assert !contents.isEmpty(); 24 | return contents; 25 | } 26 | } catch (IOException e) { 27 | throw new RuntimeException("Unable to read the contents of " + name + " file."); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/SchemaTransformerTest.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava; 2 | 3 | import graphql.Scalars; 4 | import graphql.schema.GraphQLAppliedDirectiveArgument; 5 | import graphql.schema.GraphQLFieldDefinition; 6 | import graphql.schema.GraphQLNonNull; 7 | import graphql.schema.GraphQLObjectType; 8 | import graphql.schema.GraphQLSchema; 9 | import java.util.Set; 10 | import org.junit.jupiter.api.Assertions; 11 | import org.junit.jupiter.api.Test; 12 | 13 | public class SchemaTransformerTest { 14 | 15 | private final GraphQLSchema TEST_SCHEMA = 16 | GraphQLSchema.newSchema() 17 | .query( 18 | GraphQLObjectType.newObject() 19 | .name("Query") 20 | .field( 21 | GraphQLFieldDefinition.newFieldDefinition() 22 | .name("helloWorld") 23 | .type(Scalars.GraphQLString) 24 | .build())) 25 | .build(); 26 | 27 | private final GraphQLObjectType FOO_TYPE = 28 | GraphQLObjectType.newObject() 29 | .name("Foo") 30 | .field( 31 | GraphQLFieldDefinition.newFieldDefinition() 32 | .name("id") 33 | .type(Scalars.GraphQLID) 34 | .build()) 35 | .build(); 36 | 37 | @Test 38 | public void getFederatedEntities_entityHasAppliedDirective_found() { 39 | final GraphQLSchema schema = 40 | TEST_SCHEMA.transform( 41 | schemaBuilder -> 42 | schemaBuilder.additionalType( 43 | FOO_TYPE.transform( 44 | objectBuilder -> 45 | objectBuilder.withAppliedDirective( 46 | FederationDirectives.key 47 | .toAppliedDirective() 48 | .transform( 49 | directive -> 50 | directive.argument( 51 | GraphQLAppliedDirectiveArgument.newArgument() 52 | .name("fields") 53 | .type(GraphQLNonNull.nonNull(_FieldSet.type)) 54 | .valueProgrammatic("id") 55 | .build())))))); 56 | 57 | final SchemaTransformer transformer = new SchemaTransformer(schema, false); 58 | Set entities = transformer.getFederatedEntities(); 59 | 60 | Assertions.assertFalse(entities.isEmpty()); 61 | Assertions.assertEquals(1, entities.size()); 62 | Assertions.assertTrue(entities.contains("Foo")); 63 | } 64 | 65 | @Test 66 | public void getFederatedEntities_entityHasDirective_found() { 67 | final GraphQLSchema schema = 68 | TEST_SCHEMA.transform( 69 | schemaBuilder -> 70 | schemaBuilder 71 | .additionalDirective(FederationDirectives.key) 72 | .additionalType( 73 | FOO_TYPE.transform( 74 | objectBuilder -> 75 | objectBuilder.withDirective(FederationDirectives.key("id"))))); 76 | 77 | final SchemaTransformer transformer = new SchemaTransformer(schema, false); 78 | Set entities = transformer.getFederatedEntities(); 79 | 80 | Assertions.assertFalse(entities.isEmpty()); 81 | Assertions.assertEquals(1, entities.size()); 82 | Assertions.assertTrue(entities.contains("Foo")); 83 | } 84 | 85 | @Test 86 | public void getFederatedEntities_noEntities_notFound() { 87 | final GraphQLSchema schema = 88 | TEST_SCHEMA.transform(schemaBuilder -> schemaBuilder.additionalType(FOO_TYPE)); 89 | 90 | final SchemaTransformer transformer = new SchemaTransformer(schema, false); 91 | Set entities = transformer.getFederatedEntities(); 92 | 93 | Assertions.assertTrue(entities.isEmpty()); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/data/ProductDimension.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.data; 2 | 3 | public class ProductDimension { 4 | private final String size; 5 | private final float weight; 6 | 7 | public ProductDimension(String size, float weight) { 8 | this.size = size; 9 | this.weight = weight; 10 | } 11 | 12 | public String getSize() { 13 | return size; 14 | } 15 | 16 | public float getWeight() { 17 | return weight; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/data/ProductVariation.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.data; 2 | 3 | public class ProductVariation { 4 | private final String id; 5 | 6 | public ProductVariation(String id) { 7 | this.id = id; 8 | } 9 | 10 | public String getId() { 11 | return id; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/java/com/apollographql/federation/graphqljava/data/User.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.federation.graphqljava.data; 2 | 3 | public class User { 4 | private final String email; 5 | private final Integer totalProductsCreated; 6 | private final String name; 7 | 8 | public User(String email) { 9 | this.email = email; 10 | this.totalProductsCreated = 1337; 11 | this.name = "Jane Smith"; 12 | } 13 | 14 | public String getEmail() { 15 | return email; 16 | } 17 | 18 | public Integer getTotalProductsCreated() { 19 | return totalProductsCreated; 20 | } 21 | 22 | public String getName() { 23 | return name; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/README.md: -------------------------------------------------------------------------------- 1 | This directory contains various federation schemas that verify the transformations. 2 | When creating a new valid (happy path) test case please create a new directory that 3 | contains 4 | 5 | * `schema.graphql` - schema file that will be transformed 6 | * `schema_full.graphql` - transformed complete GraphQL schema (includes all directive definitions) 7 | * `schema_federated.graphql` - transformed GraphQL schema returned from `_service { sdl }` query 8 | 9 | When creating test cases that verify validations on broken schemas please name your test schema 10 | with `invalid` prefix. 11 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/authorization/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@authenticated", "@key", "@requiresScopes", "Scope", "FieldSet"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | supplier: String @requiresScopes(scopes: [["scopeA"]]) 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product @authenticated 11 | } 12 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/authorization/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@authenticated", "@key", "@requiresScopes", "Scope", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.5"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 6 | 7 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 8 | 9 | directive @federation__extends on OBJECT | INTERFACE 10 | 11 | directive @federation__external on OBJECT | FIELD_DEFINITION 12 | 13 | directive @federation__interfaceObject on OBJECT 14 | 15 | directive @federation__override(from: String!) on FIELD_DEFINITION 16 | 17 | directive @federation__provides(fields: FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__requires(fields: FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 22 | 23 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 26 | 27 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 28 | 29 | directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 30 | 31 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 32 | 33 | union _Entity = Product 34 | 35 | type Product @key(fields : "id", resolvable : true) { 36 | id: ID! 37 | name: String! 38 | supplier: String @requiresScopes(scopes : [["scopeA"]]) 39 | } 40 | 41 | type Query { 42 | _entities(representations: [_Any!]!): [_Entity]! 43 | _service: _Service! 44 | product(id: ID!): Product @authenticated 45 | } 46 | 47 | type _Service { 48 | sdl: String! 49 | } 50 | 51 | enum link__Purpose { 52 | EXECUTION 53 | SECURITY 54 | } 55 | 56 | scalar FieldSet 57 | 58 | scalar Scope 59 | 60 | scalar _Any 61 | 62 | scalar link__Import 63 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/authorization/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@authenticated", "@key", "@requiresScopes", "Scope", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.5"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 6 | 7 | "Marks the field, argument, input field or enum value as deprecated" 8 | directive @deprecated( 9 | "The reason for the deprecation" 10 | reason: String = "No longer supported" 11 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 12 | 13 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 14 | 15 | directive @federation__extends on OBJECT | INTERFACE 16 | 17 | directive @federation__external on OBJECT | FIELD_DEFINITION 18 | 19 | directive @federation__interfaceObject on OBJECT 20 | 21 | directive @federation__override(from: String!) on FIELD_DEFINITION 22 | 23 | directive @federation__provides(fields: FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @federation__requires(fields: FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 28 | 29 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 30 | 31 | "Directs the executor to include this field or fragment only when the `if` argument is true" 32 | directive @include( 33 | "Included when true." 34 | if: Boolean! 35 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 36 | 37 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 38 | 39 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 40 | 41 | "Indicates an Input Object is a OneOf Input Object." 42 | directive @oneOf on INPUT_OBJECT 43 | 44 | directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 45 | 46 | "Directs the executor to skip this field or fragment when the `if` argument is true." 47 | directive @skip( 48 | "Skipped when true." 49 | if: Boolean! 50 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 51 | 52 | "Exposes a URL that specifies the behaviour of this scalar." 53 | directive @specifiedBy( 54 | "The URL that specifies the behaviour of this scalar." 55 | url: String! 56 | ) on SCALAR 57 | 58 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 59 | 60 | union _Entity = Product 61 | 62 | type Product @key(fields : "id", resolvable : true) { 63 | id: ID! 64 | name: String! 65 | supplier: String @requiresScopes(scopes : [["scopeA"]]) 66 | } 67 | 68 | type Query { 69 | _entities(representations: [_Any!]!): [_Entity]! 70 | _service: _Service! 71 | product(id: ID!): Product @authenticated 72 | } 73 | 74 | type _Service { 75 | sdl: String! 76 | } 77 | 78 | enum link__Purpose { 79 | EXECUTION 80 | SECURITY 81 | } 82 | 83 | scalar FieldSet 84 | 85 | scalar Scope 86 | 87 | scalar _Any 88 | 89 | scalar link__Import 90 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/composeDirective/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.1", 3 | import: ["@key", "@composeDirective"]) 4 | @link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }]) 5 | @composeDirective(name: "@myDirective") 6 | @composeDirective(name: "@hello") 7 | 8 | directive @myDirective(foo: String!) on FIELD_DEFINITION 9 | directive @hello on FIELD_DEFINITION 10 | 11 | type Product @key(fields: "id") { 12 | id: ID! 13 | name: String! @hello 14 | custom: String @myDirective(foo: "bar") 15 | } 16 | 17 | type Query { 18 | product(id: ID!): Product 19 | } 20 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/composeDirective/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @composeDirective(name : "@myDirective") @composeDirective(name : "@hello") @link(import : ["@key", "@composeDirective"], url : "https://specs.apollo.dev/federation/v2.1") @link(import : ["@myDirective", {name : "@anotherDirective", as : "@hello"}], url : "https://myspecs.dev/myDirective/v1.0"){ 2 | query: Query 3 | } 4 | 5 | directive @composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @federation__extends on OBJECT | INTERFACE 8 | 9 | directive @federation__external on OBJECT | FIELD_DEFINITION 10 | 11 | directive @federation__override(from: String!) on FIELD_DEFINITION 12 | 13 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 14 | 15 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 18 | 19 | directive @hello on FIELD_DEFINITION 20 | 21 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 22 | 23 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 24 | 25 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 26 | 27 | directive @myDirective(foo: String!) on FIELD_DEFINITION 28 | 29 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 30 | 31 | union _Entity = Product 32 | 33 | type Product @key(fields : "id", resolvable : true) { 34 | custom: String @myDirective(foo : "bar") 35 | id: ID! 36 | name: String! @hello 37 | } 38 | 39 | type Query { 40 | _entities(representations: [_Any!]!): [_Entity]! 41 | _service: _Service! 42 | product(id: ID!): Product 43 | } 44 | 45 | type _Service { 46 | sdl: String! 47 | } 48 | 49 | enum link__Purpose { 50 | EXECUTION 51 | SECURITY 52 | } 53 | 54 | scalar _Any 55 | 56 | scalar federation__FieldSet 57 | 58 | scalar link__Import 59 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/composeDirective/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @composeDirective(name : "@myDirective") @composeDirective(name : "@hello") @link(import : ["@key", "@composeDirective"], url : "https://specs.apollo.dev/federation/v2.1") @link(import : ["@myDirective", {name : "@anotherDirective", as : "@hello"}], url : "https://myspecs.dev/myDirective/v1.0"){ 2 | query: Query 3 | } 4 | 5 | directive @composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | "Marks the field, argument, input field or enum value as deprecated" 8 | directive @deprecated( 9 | "The reason for the deprecation" 10 | reason: String = "No longer supported" 11 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__override(from: String!) on FIELD_DEFINITION 18 | 19 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 24 | 25 | directive @hello on FIELD_DEFINITION 26 | 27 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | "Directs the executor to include this field or fragment only when the `if` argument is true" 30 | directive @include( 31 | "Included when true." 32 | if: Boolean! 33 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 34 | 35 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 36 | 37 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 38 | 39 | directive @myDirective(foo: String!) on FIELD_DEFINITION 40 | 41 | "Indicates an Input Object is a OneOf Input Object." 42 | directive @oneOf on INPUT_OBJECT 43 | 44 | "Directs the executor to skip this field or fragment when the `if` argument is true." 45 | directive @skip( 46 | "Skipped when true." 47 | if: Boolean! 48 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 49 | 50 | "Exposes a URL that specifies the behaviour of this scalar." 51 | directive @specifiedBy( 52 | "The URL that specifies the behaviour of this scalar." 53 | url: String! 54 | ) on SCALAR 55 | 56 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 57 | 58 | union _Entity = Product 59 | 60 | type Product @key(fields : "id", resolvable : true) { 61 | custom: String @myDirective(foo : "bar") 62 | id: ID! 63 | name: String! @hello 64 | } 65 | 66 | type Query { 67 | _entities(representations: [_Any!]!): [_Entity]! 68 | _service: _Service! 69 | product(id: ID!): Product 70 | } 71 | 72 | type _Service { 73 | sdl: String! 74 | } 75 | 76 | enum link__Purpose { 77 | EXECUTION 78 | SECURITY 79 | } 80 | 81 | scalar _Any 82 | 83 | scalar federation__FieldSet 84 | 85 | scalar link__Import 86 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/context/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.8", import: ["@key", "@context", "@fromContext"]) 2 | 3 | type Product @key(fields: "id") @context(name: "product") { 4 | id: ID! 5 | name: String! 6 | child: Child! 7 | } 8 | 9 | type Child @key(fields: "id") { 10 | id: ID! 11 | details(productName: String @fromContext(field: "$product { name }")): String! 12 | } 13 | 14 | type Query { 15 | product(id: ID!): Product 16 | } 17 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/context/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@context", "@fromContext"], url : "https://specs.apollo.dev/federation/v2.8"){ 2 | query: Query 3 | } 4 | 5 | directive @context(name: String!) repeatable on OBJECT | INTERFACE | UNION 6 | 7 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 8 | 9 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 10 | 11 | directive @federation__extends on OBJECT | INTERFACE 12 | 13 | directive @federation__external on OBJECT | FIELD_DEFINITION 14 | 15 | directive @federation__interfaceObject on OBJECT 16 | 17 | directive @federation__override(from: String!, label: String) on FIELD_DEFINITION 18 | 19 | directive @federation__policy(policies: [[federation__Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 20 | 21 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 26 | 27 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 28 | 29 | directive @fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION 30 | 31 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 32 | 33 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 34 | 35 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 36 | 37 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 38 | 39 | union _Entity = Child | Product 40 | 41 | type Child @key(fields : "id", resolvable : true) { 42 | details(productName: String @fromContext(field : "$product { name }")): String! 43 | id: ID! 44 | } 45 | 46 | type Product @context(name : "product") @key(fields : "id", resolvable : true) { 47 | child: Child! 48 | id: ID! 49 | name: String! 50 | } 51 | 52 | type Query { 53 | _entities(representations: [_Any!]!): [_Entity]! 54 | _service: _Service! 55 | product(id: ID!): Product 56 | } 57 | 58 | type _Service { 59 | sdl: String! 60 | } 61 | 62 | enum link__Purpose { 63 | EXECUTION 64 | SECURITY 65 | } 66 | 67 | scalar _Any 68 | 69 | scalar federation__ContextFieldValue 70 | 71 | scalar federation__FieldSet 72 | 73 | scalar federation__Policy 74 | 75 | scalar federation__Scope 76 | 77 | scalar link__Import -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/context/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@context", "@fromContext"], url : "https://specs.apollo.dev/federation/v2.8"){ 2 | query: Query 3 | } 4 | 5 | directive @context(name: String!) repeatable on OBJECT | INTERFACE | UNION 6 | 7 | "Marks the field, argument, input field or enum value as deprecated" 8 | directive @deprecated( 9 | "The reason for the deprecation" 10 | reason: String = "No longer supported" 11 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 12 | 13 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 14 | 15 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 16 | 17 | directive @federation__extends on OBJECT | INTERFACE 18 | 19 | directive @federation__external on OBJECT | FIELD_DEFINITION 20 | 21 | directive @federation__interfaceObject on OBJECT 22 | 23 | directive @federation__override(from: String!, label: String) on FIELD_DEFINITION 24 | 25 | directive @federation__policy(policies: [[federation__Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 26 | 27 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 28 | 29 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 30 | 31 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 32 | 33 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 34 | 35 | directive @fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION 36 | 37 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 38 | 39 | "Directs the executor to include this field or fragment only when the `if` argument is true" 40 | directive @include( 41 | "Included when true." 42 | if: Boolean! 43 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 44 | 45 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 46 | 47 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 48 | 49 | "Indicates an Input Object is a OneOf Input Object." 50 | directive @oneOf on INPUT_OBJECT 51 | 52 | "Directs the executor to skip this field or fragment when the `if` argument is true." 53 | directive @skip( 54 | "Skipped when true." 55 | if: Boolean! 56 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 57 | 58 | "Exposes a URL that specifies the behaviour of this scalar." 59 | directive @specifiedBy( 60 | "The URL that specifies the behaviour of this scalar." 61 | url: String! 62 | ) on SCALAR 63 | 64 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 65 | 66 | union _Entity = Child | Product 67 | 68 | type Child @key(fields : "id", resolvable : true) { 69 | details(productName: String @fromContext(field : "$product { name }")): String! 70 | id: ID! 71 | } 72 | 73 | type Product @context(name : "product") @key(fields : "id", resolvable : true) { 74 | child: Child! 75 | id: ID! 76 | name: String! 77 | } 78 | 79 | type Query { 80 | _entities(representations: [_Any!]!): [_Entity]! 81 | _service: _Service! 82 | product(id: ID!): Product 83 | } 84 | 85 | type _Service { 86 | sdl: String! 87 | } 88 | 89 | enum link__Purpose { 90 | EXECUTION 91 | SECURITY 92 | } 93 | 94 | scalar _Any 95 | 96 | scalar federation__ContextFieldValue 97 | 98 | scalar federation__FieldSet 99 | 100 | scalar federation__Policy 101 | 102 | scalar federation__Scope 103 | 104 | scalar link__Import -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/cost/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.9" 4 | import: ["@cost", "@key", "@listSize"] 5 | ) 6 | 7 | type Product @key(fields: "id") { 8 | id: ID! 9 | name: String! 10 | child: Child! @cost(weight: 5) 11 | } 12 | 13 | type Child @key(fields: "id") { 14 | id: ID! 15 | details(productName: String): [String!] @listSize(assumedSize: 10) 16 | } 17 | 18 | type Query { 19 | product(id: ID!): Product 20 | } 21 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/cost/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@cost", "@key", "@listSize"], url : "https://specs.apollo.dev/federation/v2.9"){ 2 | query: Query 3 | } 4 | 5 | directive @cost(weight: Int!) on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM | INPUT_FIELD_DEFINITION 6 | 7 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 8 | 9 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 10 | 11 | directive @federation__context(name: String!) repeatable on OBJECT | INTERFACE | UNION 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__fromContext(field: federation__ContextFieldValue) on ARGUMENT_DEFINITION 18 | 19 | directive @federation__interfaceObject on OBJECT 20 | 21 | directive @federation__override(from: String!, label: String) on FIELD_DEFINITION 22 | 23 | directive @federation__policy(policies: [[federation__Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 24 | 25 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 28 | 29 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 30 | 31 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 32 | 33 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 34 | 35 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 36 | 37 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 38 | 39 | directive @listSize(assumedSize: Int, requireOneSlicingArgument: Boolean = true, sizedFields: [String!], slicingArguments: [String!]) on FIELD_DEFINITION 40 | 41 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 42 | 43 | union _Entity = Child | Product 44 | 45 | type Child @key(fields : "id", resolvable : true) { 46 | details(productName: String): [String!] @listSize(assumedSize : 10, requireOneSlicingArgument : true) 47 | id: ID! 48 | } 49 | 50 | type Product @key(fields : "id", resolvable : true) { 51 | child: Child! @cost(weight : 5) 52 | id: ID! 53 | name: String! 54 | } 55 | 56 | type Query { 57 | _entities(representations: [_Any!]!): [_Entity]! 58 | _service: _Service! 59 | product(id: ID!): Product 60 | } 61 | 62 | type _Service { 63 | sdl: String! 64 | } 65 | 66 | enum link__Purpose { 67 | EXECUTION 68 | SECURITY 69 | } 70 | 71 | scalar _Any 72 | 73 | scalar federation__ContextFieldValue 74 | 75 | scalar federation__FieldSet 76 | 77 | scalar federation__Policy 78 | 79 | scalar federation__Scope 80 | 81 | scalar link__Import -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/customAuthenticated/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.5", import: ["@key"]) 2 | 3 | directive @authenticated(role: [String!]!) on FIELD_DEFINITION 4 | 5 | type Product @key(fields: "id") { 6 | id: ID! 7 | name: String! 8 | supplier: String @authenticated(role: ["manager"]) 9 | } 10 | 11 | type Query { 12 | product(id: ID!): Product 13 | } 14 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/customAuthenticated/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.5"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated(role: [String!]!) on FIELD_DEFINITION 6 | 7 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 8 | 9 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 10 | 11 | directive @federation__extends on OBJECT | INTERFACE 12 | 13 | directive @federation__external on OBJECT | FIELD_DEFINITION 14 | 15 | directive @federation__interfaceObject on OBJECT 16 | 17 | directive @federation__override(from: String!) on FIELD_DEFINITION 18 | 19 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 24 | 25 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 26 | 27 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 30 | 31 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 32 | 33 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 34 | 35 | union _Entity = Product 36 | 37 | type Product @key(fields : "id", resolvable : true) { 38 | id: ID! 39 | name: String! 40 | supplier: String @authenticated(role : ["manager"]) 41 | } 42 | 43 | type Query { 44 | _entities(representations: [_Any!]!): [_Entity]! 45 | _service: _Service! 46 | product(id: ID!): Product 47 | } 48 | 49 | type _Service { 50 | sdl: String! 51 | } 52 | 53 | enum link__Purpose { 54 | EXECUTION 55 | SECURITY 56 | } 57 | 58 | scalar _Any 59 | 60 | scalar federation__FieldSet 61 | 62 | scalar federation__Scope 63 | 64 | scalar link__Import 65 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/customAuthenticated/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.5"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated(role: [String!]!) on FIELD_DEFINITION 6 | 7 | "Marks the field, argument, input field or enum value as deprecated" 8 | directive @deprecated( 9 | "The reason for the deprecation" 10 | reason: String = "No longer supported" 11 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 12 | 13 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 14 | 15 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 16 | 17 | directive @federation__extends on OBJECT | INTERFACE 18 | 19 | directive @federation__external on OBJECT | FIELD_DEFINITION 20 | 21 | directive @federation__interfaceObject on OBJECT 22 | 23 | directive @federation__override(from: String!) on FIELD_DEFINITION 24 | 25 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 28 | 29 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 30 | 31 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 32 | 33 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 34 | 35 | "Directs the executor to include this field or fragment only when the `if` argument is true" 36 | directive @include( 37 | "Included when true." 38 | if: Boolean! 39 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 40 | 41 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 42 | 43 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 44 | 45 | "Indicates an Input Object is a OneOf Input Object." 46 | directive @oneOf on INPUT_OBJECT 47 | 48 | "Directs the executor to skip this field or fragment when the `if` argument is true." 49 | directive @skip( 50 | "Skipped when true." 51 | if: Boolean! 52 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 53 | 54 | "Exposes a URL that specifies the behaviour of this scalar." 55 | directive @specifiedBy( 56 | "The URL that specifies the behaviour of this scalar." 57 | url: String! 58 | ) on SCALAR 59 | 60 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 61 | 62 | union _Entity = Product 63 | 64 | type Product @key(fields : "id", resolvable : true) { 65 | id: ID! 66 | name: String! 67 | supplier: String @authenticated(role : ["manager"]) 68 | } 69 | 70 | type Query { 71 | _entities(representations: [_Any!]!): [_Entity]! 72 | _service: _Service! 73 | product(id: ID!): Product 74 | } 75 | 76 | type _Service { 77 | sdl: String! 78 | } 79 | 80 | enum link__Purpose { 81 | EXECUTION 82 | SECURITY 83 | } 84 | 85 | scalar _Any 86 | 87 | scalar federation__FieldSet 88 | 89 | scalar federation__Scope 90 | 91 | scalar link__Import 92 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/entitiesOnlySubgraph/schema.graphql: -------------------------------------------------------------------------------- 1 | type Product @key(fields: "id") @extends { 2 | id: ID! 3 | reviews: [Review!]! 4 | } 5 | 6 | type Review { 7 | id: ID! 8 | text: String! 9 | } 10 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/entitiesOnlySubgraph/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Product @extends @key(fields : "id") { 6 | id: ID! 7 | reviews: [Review!]! 8 | } 9 | 10 | type Query 11 | 12 | type Review { 13 | id: ID! 14 | text: String! 15 | } 16 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/entitiesOnlySubgraph/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @extends on OBJECT | INTERFACE 12 | 13 | directive @external on FIELD_DEFINITION 14 | 15 | "Directs the executor to include this field or fragment only when the `if` argument is true" 16 | directive @include( 17 | "Included when true." 18 | if: Boolean! 19 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 20 | 21 | directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE 22 | 23 | "Indicates an Input Object is a OneOf Input Object." 24 | directive @oneOf on INPUT_OBJECT 25 | 26 | directive @provides(fields: _FieldSet!) on FIELD_DEFINITION 27 | 28 | directive @requires(fields: _FieldSet!) on FIELD_DEFINITION 29 | 30 | "Directs the executor to skip this field or fragment when the `if` argument is true." 31 | directive @skip( 32 | "Skipped when true." 33 | if: Boolean! 34 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 35 | 36 | "Exposes a URL that specifies the behaviour of this scalar." 37 | directive @specifiedBy( 38 | "The URL that specifies the behaviour of this scalar." 39 | url: String! 40 | ) on SCALAR 41 | 42 | union _Entity = Product 43 | 44 | type Product @extends @key(fields : "id") { 45 | id: ID! 46 | reviews: [Review!]! 47 | } 48 | 49 | type Query { 50 | _entities(representations: [_Any!]!): [_Entity]! 51 | _service: _Service! 52 | } 53 | 54 | type Review { 55 | id: ID! 56 | text: String! 57 | } 58 | 59 | type _Service { 60 | sdl: String! 61 | } 62 | 63 | scalar _Any 64 | 65 | scalar _FieldSet 66 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/extendSchema/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) 2 | 3 | schema { 4 | query: Query 5 | } 6 | 7 | type Product @key(fields: "id") { 8 | id: ID! 9 | } 10 | 11 | type Query { 12 | product(id: ID!): Product 13 | } 14 | 15 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/extendSchema/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__extends on OBJECT | INTERFACE 6 | 7 | directive @federation__external on OBJECT | FIELD_DEFINITION 8 | 9 | directive @federation__override(from: String!) on FIELD_DEFINITION 10 | 11 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 12 | 13 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 14 | 15 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 16 | 17 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 18 | 19 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 20 | 21 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 22 | 23 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | union _Entity = Product 26 | 27 | type Product @key(fields : "id", resolvable : true) { 28 | id: ID! 29 | } 30 | 31 | type Query { 32 | _entities(representations: [_Any!]!): [_Entity]! 33 | _service: _Service! 34 | product(id: ID!): Product 35 | } 36 | 37 | type _Service { 38 | sdl: String! 39 | } 40 | 41 | enum link__Purpose { 42 | EXECUTION 43 | SECURITY 44 | } 45 | 46 | scalar _Any 47 | 48 | scalar federation__FieldSet 49 | 50 | scalar link__Import 51 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/extendSchema/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__extends on OBJECT | INTERFACE 12 | 13 | directive @federation__external on OBJECT | FIELD_DEFINITION 14 | 15 | directive @federation__override(from: String!) on FIELD_DEFINITION 16 | 17 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 22 | 23 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | "Directs the executor to include this field or fragment only when the `if` argument is true" 26 | directive @include( 27 | "Included when true." 28 | if: Boolean! 29 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 30 | 31 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 32 | 33 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 34 | 35 | "Indicates an Input Object is a OneOf Input Object." 36 | directive @oneOf on INPUT_OBJECT 37 | 38 | "Directs the executor to skip this field or fragment when the `if` argument is true." 39 | directive @skip( 40 | "Skipped when true." 41 | if: Boolean! 42 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 43 | 44 | "Exposes a URL that specifies the behaviour of this scalar." 45 | directive @specifiedBy( 46 | "The URL that specifies the behaviour of this scalar." 47 | url: String! 48 | ) on SCALAR 49 | 50 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 51 | 52 | union _Entity = Product 53 | 54 | type Product @key(fields : "id", resolvable : true) { 55 | id: ID! 56 | } 57 | 58 | type Query { 59 | _entities(representations: [_Any!]!): [_Entity]! 60 | _service: _Service! 61 | product(id: ID!): Product 62 | } 63 | 64 | type _Service { 65 | sdl: String! 66 | } 67 | 68 | enum link__Purpose { 69 | EXECUTION 70 | SECURITY 71 | } 72 | 73 | scalar _Any 74 | 75 | scalar federation__FieldSet 76 | 77 | scalar link__Import 78 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/fedV1/schema.graphql: -------------------------------------------------------------------------------- 1 | type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") { 2 | id: ID! 3 | sku: String 4 | package: String 5 | variation: ProductVariation 6 | dimensions: ProductDimension 7 | createdBy: User @provides(fields: "totalProductsCreated") 8 | notes: String 9 | } 10 | 11 | type ProductVariation { 12 | id: ID! 13 | } 14 | 15 | type ProductDimension { 16 | size: String 17 | weight: Float 18 | unit: String 19 | } 20 | 21 | extend type Query { 22 | product(id: ID!): Product 23 | } 24 | 25 | type User @key(fields: "email") @extends { 26 | email: ID! @external 27 | name: String 28 | totalProductsCreated: Int @external 29 | } 30 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/fedV1/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Product @key(fields : "id") @key(fields : "sku package") @key(fields : "sku variation { id }") { 6 | createdBy: User @provides(fields : "totalProductsCreated") 7 | dimensions: ProductDimension 8 | id: ID! 9 | notes: String 10 | package: String 11 | sku: String 12 | variation: ProductVariation 13 | } 14 | 15 | type ProductDimension { 16 | size: String 17 | unit: String 18 | weight: Float 19 | } 20 | 21 | type ProductVariation { 22 | id: ID! 23 | } 24 | 25 | type Query { 26 | product(id: ID!): Product 27 | } 28 | 29 | type User @extends @key(fields : "email") { 30 | email: ID! @external 31 | name: String 32 | totalProductsCreated: Int @external 33 | } 34 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/fedV1/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @extends on OBJECT | INTERFACE 12 | 13 | directive @external on FIELD_DEFINITION 14 | 15 | "Directs the executor to include this field or fragment only when the `if` argument is true" 16 | directive @include( 17 | "Included when true." 18 | if: Boolean! 19 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 20 | 21 | directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE 22 | 23 | "Indicates an Input Object is a OneOf Input Object." 24 | directive @oneOf on INPUT_OBJECT 25 | 26 | directive @provides(fields: _FieldSet!) on FIELD_DEFINITION 27 | 28 | directive @requires(fields: _FieldSet!) on FIELD_DEFINITION 29 | 30 | "Directs the executor to skip this field or fragment when the `if` argument is true." 31 | directive @skip( 32 | "Skipped when true." 33 | if: Boolean! 34 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 35 | 36 | "Exposes a URL that specifies the behaviour of this scalar." 37 | directive @specifiedBy( 38 | "The URL that specifies the behaviour of this scalar." 39 | url: String! 40 | ) on SCALAR 41 | 42 | union _Entity = Product | User 43 | 44 | type Product @key(fields : "id") @key(fields : "sku package") @key(fields : "sku variation { id }") { 45 | createdBy: User @provides(fields : "totalProductsCreated") 46 | dimensions: ProductDimension 47 | id: ID! 48 | notes: String 49 | package: String 50 | sku: String 51 | variation: ProductVariation 52 | } 53 | 54 | type ProductDimension { 55 | size: String 56 | unit: String 57 | weight: Float 58 | } 59 | 60 | type ProductVariation { 61 | id: ID! 62 | } 63 | 64 | type Query { 65 | _entities(representations: [_Any!]!): [_Entity]! 66 | _service: _Service! 67 | product(id: ID!): Product 68 | } 69 | 70 | type User @extends @key(fields : "email") { 71 | email: ID! @external 72 | name: String 73 | totalProductsCreated: Int @external 74 | } 75 | 76 | type _Service { 77 | sdl: String! 78 | } 79 | 80 | scalar _Any 81 | 82 | scalar _FieldSet 83 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/fedV2/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.3" 4 | import: [ 5 | "@composeDirective" 6 | "@extends" 7 | "@external" 8 | "@key" 9 | "@inaccessible" 10 | "@interfaceObject" 11 | "@override" 12 | "@provides" 13 | "@requires" 14 | "@shareable" 15 | "@tag" 16 | ] 17 | ) 18 | @link(url: "https://myspecs.dev/myCustomDirective/v1.0", import: ["@custom"]) 19 | @composeDirective(name: "@custom") 20 | 21 | directive @custom on OBJECT 22 | 23 | type Product 24 | @custom 25 | @key(fields: "id") 26 | @key(fields: "sku package") 27 | @key(fields: "sku variation { id }") { 28 | id: ID! 29 | sku: String 30 | package: String 31 | variation: ProductVariation 32 | dimensions: ProductDimension 33 | createdBy: User @provides(fields: "totalProductsCreated") 34 | notes: String @tag(name: "internal") 35 | research: [ProductResearch!]! 36 | } 37 | 38 | type DeprecatedProduct @key(fields: "sku package") { 39 | sku: String! 40 | package: String! 41 | reason: String 42 | createdBy: User 43 | } 44 | 45 | type ProductVariation { 46 | id: ID! 47 | } 48 | 49 | type ProductResearch @key(fields: "study { caseNumber }") { 50 | study: CaseStudy! 51 | outcome: String 52 | } 53 | 54 | type CaseStudy { 55 | caseNumber: ID! 56 | description: String 57 | } 58 | 59 | type ProductDimension @shareable { 60 | size: String 61 | weight: Float 62 | unit: String @inaccessible 63 | } 64 | 65 | type Query { 66 | product(id: ID!): Product 67 | deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead") 68 | } 69 | 70 | type User @key(fields: "email") { 71 | averageProductsCreatedPerYear: Int @requires(fields: "totalProductsCreated yearsOfEmployment") 72 | email: ID! @external 73 | name: String @override(from: "users") 74 | totalProductsCreated: Int @external 75 | yearsOfEmployment: Int! @external 76 | } 77 | 78 | type Inventory @interfaceObject @key(fields: "id") { 79 | id: ID! 80 | deprecatedProducts: [DeprecatedProduct!]! 81 | } 82 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/fedV2/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @composeDirective(name : "@custom") @link(import : ["@composeDirective", "@extends", "@external", "@key", "@inaccessible", "@interfaceObject", "@override", "@provides", "@requires", "@shareable", "@tag"], url : "https://specs.apollo.dev/federation/v2.3") @link(import : ["@custom"], url : "https://myspecs.dev/myCustomDirective/v1.0"){ 2 | query: Query 3 | } 4 | 5 | directive @composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @custom on OBJECT 8 | 9 | directive @extends on OBJECT | INTERFACE 10 | 11 | directive @external on OBJECT | FIELD_DEFINITION 12 | 13 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 14 | 15 | directive @interfaceObject on OBJECT 16 | 17 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 18 | 19 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 20 | 21 | directive @override(from: String!) on FIELD_DEFINITION 22 | 23 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 28 | 29 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 30 | 31 | union _Entity = DeprecatedProduct | Inventory | Product | ProductResearch | User 32 | 33 | type CaseStudy { 34 | caseNumber: ID! 35 | description: String 36 | } 37 | 38 | type DeprecatedProduct @key(fields : "sku package", resolvable : true) { 39 | createdBy: User 40 | package: String! 41 | reason: String 42 | sku: String! 43 | } 44 | 45 | type Inventory @interfaceObject @key(fields : "id", resolvable : true) { 46 | deprecatedProducts: [DeprecatedProduct!]! 47 | id: ID! 48 | } 49 | 50 | type Product @custom @key(fields : "id", resolvable : true) @key(fields : "sku package", resolvable : true) @key(fields : "sku variation { id }", resolvable : true) { 51 | createdBy: User @provides(fields : "totalProductsCreated") 52 | dimensions: ProductDimension 53 | id: ID! 54 | notes: String @tag(name : "internal") 55 | package: String 56 | research: [ProductResearch!]! 57 | sku: String 58 | variation: ProductVariation 59 | } 60 | 61 | type ProductDimension @shareable { 62 | size: String 63 | unit: String @inaccessible 64 | weight: Float 65 | } 66 | 67 | type ProductResearch @key(fields : "study { caseNumber }", resolvable : true) { 68 | outcome: String 69 | study: CaseStudy! 70 | } 71 | 72 | type ProductVariation { 73 | id: ID! 74 | } 75 | 76 | type Query { 77 | _entities(representations: [_Any!]!): [_Entity]! 78 | _service: _Service! 79 | deprecatedProduct(package: String!, sku: String!): DeprecatedProduct @deprecated(reason : "Use product query instead") 80 | product(id: ID!): Product 81 | } 82 | 83 | type User @key(fields : "email", resolvable : true) { 84 | averageProductsCreatedPerYear: Int @requires(fields : "totalProductsCreated yearsOfEmployment") 85 | email: ID! @external 86 | name: String @override(from : "users") 87 | totalProductsCreated: Int @external 88 | yearsOfEmployment: Int! @external 89 | } 90 | 91 | type _Service { 92 | sdl: String! 93 | } 94 | 95 | enum link__Purpose { 96 | EXECUTION 97 | SECURITY 98 | } 99 | 100 | scalar _Any 101 | 102 | scalar federation__FieldSet 103 | 104 | scalar link__Import 105 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceEntity/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"]) 2 | 3 | type Query { 4 | products: [Product!]! 5 | } 6 | 7 | interface Product @key(fields: "id") { 8 | id: ID! 9 | description: String 10 | price: Float 11 | } 12 | 13 | type Book implements Product @key(fields: "id") { 14 | id: ID! 15 | description: String 16 | price: Float 17 | pages: Int 18 | } 19 | 20 | type Movie implements Product @key(fields: "id") { 21 | id: ID! 22 | description: String 23 | price: Float 24 | duration: Int 25 | } 26 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceEntity/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @federation__extends on OBJECT | INTERFACE 8 | 9 | directive @federation__external on OBJECT | FIELD_DEFINITION 10 | 11 | directive @federation__interfaceObject on OBJECT 12 | 13 | directive @federation__override(from: String!) on FIELD_DEFINITION 14 | 15 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 20 | 21 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 22 | 23 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 24 | 25 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 26 | 27 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | interface Product @key(fields : "id", resolvable : true) { 30 | description: String 31 | id: ID! 32 | price: Float 33 | } 34 | 35 | union _Entity = Book | Movie 36 | 37 | type Book implements Product @key(fields : "id", resolvable : true) { 38 | description: String 39 | id: ID! 40 | pages: Int 41 | price: Float 42 | } 43 | 44 | type Movie implements Product @key(fields : "id", resolvable : true) { 45 | description: String 46 | duration: Int 47 | id: ID! 48 | price: Float 49 | } 50 | 51 | type Query { 52 | _entities(representations: [_Any!]!): [_Entity]! 53 | _service: _Service! 54 | products: [Product!]! 55 | } 56 | 57 | type _Service { 58 | sdl: String! 59 | } 60 | 61 | enum link__Purpose { 62 | EXECUTION 63 | SECURITY 64 | } 65 | 66 | scalar _Any 67 | 68 | scalar federation__FieldSet 69 | 70 | scalar link__Import 71 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceEntity/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__interfaceObject on OBJECT 18 | 19 | directive @federation__override(from: String!) on FIELD_DEFINITION 20 | 21 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 26 | 27 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | "Directs the executor to include this field or fragment only when the `if` argument is true" 30 | directive @include( 31 | "Included when true." 32 | if: Boolean! 33 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 34 | 35 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 36 | 37 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 38 | 39 | "Indicates an Input Object is a OneOf Input Object." 40 | directive @oneOf on INPUT_OBJECT 41 | 42 | "Directs the executor to skip this field or fragment when the `if` argument is true." 43 | directive @skip( 44 | "Skipped when true." 45 | if: Boolean! 46 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 47 | 48 | "Exposes a URL that specifies the behaviour of this scalar." 49 | directive @specifiedBy( 50 | "The URL that specifies the behaviour of this scalar." 51 | url: String! 52 | ) on SCALAR 53 | 54 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 55 | 56 | interface Product @key(fields : "id", resolvable : true) { 57 | description: String 58 | id: ID! 59 | price: Float 60 | } 61 | 62 | union _Entity = Book | Movie 63 | 64 | type Book implements Product @key(fields : "id", resolvable : true) { 65 | description: String 66 | id: ID! 67 | pages: Int 68 | price: Float 69 | } 70 | 71 | type Movie implements Product @key(fields : "id", resolvable : true) { 72 | description: String 73 | duration: Int 74 | id: ID! 75 | price: Float 76 | } 77 | 78 | type Query { 79 | _entities(representations: [_Any!]!): [_Entity]! 80 | _service: _Service! 81 | products: [Product!]! 82 | } 83 | 84 | type _Service { 85 | sdl: String! 86 | } 87 | 88 | enum link__Purpose { 89 | EXECUTION 90 | SECURITY 91 | } 92 | 93 | scalar _Any 94 | 95 | scalar federation__FieldSet 96 | 97 | scalar link__Import 98 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceObject/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key", "@interfaceObject"]) 2 | 3 | type Product @key(fields: "id") @interfaceObject { 4 | id: ID! 5 | name: String! 6 | } 7 | 8 | type Query { 9 | product(id: ID!): Product 10 | } 11 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceObject/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@interfaceObject"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @federation__extends on OBJECT | INTERFACE 8 | 9 | directive @federation__external on OBJECT | FIELD_DEFINITION 10 | 11 | directive @federation__override(from: String!) on FIELD_DEFINITION 12 | 13 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 14 | 15 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 18 | 19 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 20 | 21 | directive @interfaceObject on OBJECT 22 | 23 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 24 | 25 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 26 | 27 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | union _Entity = Product 30 | 31 | type Product @interfaceObject @key(fields : "id", resolvable : true) { 32 | id: ID! 33 | name: String! 34 | } 35 | 36 | type Query { 37 | _entities(representations: [_Any!]!): [_Entity]! 38 | _service: _Service! 39 | product(id: ID!): Product 40 | } 41 | 42 | type _Service { 43 | sdl: String! 44 | } 45 | 46 | enum link__Purpose { 47 | EXECUTION 48 | SECURITY 49 | } 50 | 51 | scalar _Any 52 | 53 | scalar federation__FieldSet 54 | 55 | scalar link__Import 56 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/interfaceObject/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@interfaceObject"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__override(from: String!) on FIELD_DEFINITION 18 | 19 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 24 | 25 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 26 | 27 | "Directs the executor to include this field or fragment only when the `if` argument is true" 28 | directive @include( 29 | "Included when true." 30 | if: Boolean! 31 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 32 | 33 | directive @interfaceObject on OBJECT 34 | 35 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 36 | 37 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 38 | 39 | "Indicates an Input Object is a OneOf Input Object." 40 | directive @oneOf on INPUT_OBJECT 41 | 42 | "Directs the executor to skip this field or fragment when the `if` argument is true." 43 | directive @skip( 44 | "Skipped when true." 45 | if: Boolean! 46 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 47 | 48 | "Exposes a URL that specifies the behaviour of this scalar." 49 | directive @specifiedBy( 50 | "The URL that specifies the behaviour of this scalar." 51 | url: String! 52 | ) on SCALAR 53 | 54 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 55 | 56 | union _Entity = Product 57 | 58 | type Product @interfaceObject @key(fields : "id", resolvable : true) { 59 | id: ID! 60 | name: String! 61 | } 62 | 63 | type Query { 64 | _entities(representations: [_Any!]!): [_Entity]! 65 | _service: _Service! 66 | product(id: ID!): Product 67 | } 68 | 69 | type _Service { 70 | sdl: String! 71 | } 72 | 73 | enum link__Purpose { 74 | EXECUTION 75 | SECURITY 76 | } 77 | 78 | scalar _Any 79 | 80 | scalar federation__FieldSet 81 | 82 | scalar link__Import 83 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidMultipleFederationLinks.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.0", 3 | import: ["@key"]) 4 | @link(url: "https://specs.apollo.dev/federation/v2.1", 5 | import: ["@composeDirective"]) 6 | @link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }]) 7 | @composeDirective(name: "@myDirective") 8 | @composeDirective(name: "@hello") 9 | 10 | directive @myDirective(foo: String!) on FIELD_DEFINITION 11 | directive @hello on FIELD_DEFINITION 12 | 13 | type Product @key(fields: "id") { 14 | id: ID! 15 | name: String! @hello 16 | custom: String @myDirective(foo: "bar") 17 | } 18 | 19 | type Query { 20 | product(id: ID!): Product 21 | } 22 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidMultipleFederationSchemaLinks.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) 2 | 3 | schema @link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@tag"]) { 4 | query: Query 5 | } 6 | 7 | type Product @key(fields: "id") { 8 | id: ID! 9 | name: String! @tag(name: "example") 10 | } 11 | 12 | type Query { 13 | product(id: ID!): Product 14 | } 15 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidPolymorphicSubgraphMissingKeys.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) 2 | 3 | interface Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | } 7 | 8 | type Book implements Product { 9 | id: ID! 10 | name: String! 11 | author: String! 12 | } 13 | 14 | type Movie implements Product { 15 | id: ID! 16 | name: String! 17 | director: String! 18 | } 19 | 20 | type Query { 21 | movie(id: ID!): Movie 22 | } 23 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidRenameInaccessibleImport.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.0", 3 | import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", { name: "@inaccessible", as: "@unreachable" }]) 4 | 5 | type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") { 6 | id: ID! 7 | sku: String 8 | package: String 9 | variation: ProductVariation 10 | dimensions: ProductDimension 11 | createdBy: User @provides(fields: "totalProductsCreated") 12 | notes: String @mytag(name: "internal") 13 | } 14 | 15 | type ProductVariation { 16 | id: ID! 17 | } 18 | 19 | type ProductDimension @shareable { 20 | size: String 21 | weight: Float 22 | unit: String @unreachable 23 | } 24 | 25 | type Query { 26 | product(id: ID!): Product 27 | } 28 | 29 | type User @key(fields: "email") { 30 | email: ID! 31 | name: String @shareable @override(from: "users") 32 | totalProductsCreated: Int @external 33 | } 34 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidRenameTagImport.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.0", 3 | import: ["@key", "@shareable", "@provides", "@external", { name: "@tag", as: "@mytag" }, "@extends", "@override", "@inaccessible"]) 4 | 5 | type Product @key(fields: "id") @key(fields: "sku package") @key(fields: "sku variation { id }") { 6 | id: ID! 7 | sku: String 8 | package: String 9 | variation: ProductVariation 10 | dimensions: ProductDimension 11 | createdBy: User @provides(fields: "totalProductsCreated") 12 | notes: String @mytag(name: "internal") 13 | } 14 | 15 | type ProductVariation { 16 | id: ID! 17 | } 18 | 19 | type ProductDimension @shareable { 20 | size: String 21 | weight: Float 22 | unit: String @inaccessible 23 | } 24 | 25 | type Query { 26 | product(id: ID!): Product 27 | } 28 | 29 | type User @key(fields: "email") { 30 | email: ID! 31 | name: String @shareable @override(from: "users") 32 | totalProductsCreated: Int @external 33 | } 34 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersion.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v99.99", 3 | import: ["@key"]) 4 | 5 | type Product @key(fields: "id") { 6 | id: ID! 7 | package: String 8 | notes: String @tag(name: "internal") 9 | } 10 | 11 | type Query { 12 | product(id: ID!): Product 13 | } 14 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionAuthenticated.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@authenticated", "@key", "FieldSet"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | supplier: String 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product @authenticated 11 | } 12 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionComposeDirective.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.0", 3 | import: ["@key", "@shareable", "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible", "@composeDirective"]) 4 | @link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }]) 5 | @composeDirective(name: "@myDirective") 6 | @composeDirective(name: "@hello") 7 | 8 | directive @myDirective(foo: String!) on FIELD_DEFINITION 9 | directive @hello on FIELD_DEFINITION 10 | 11 | type Product @key(fields: "id") { 12 | id: ID! 13 | name: String! @hello 14 | custom: String @myDirective(foo: "bar") 15 | } 16 | 17 | type Query { 18 | product(id: ID!): Product 19 | } 20 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionContext.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.7" 4 | import: ["@key", "@context", "@fromContext"] 5 | ) 6 | 7 | type Product @key(fields: "id") @context(name: "product") { 8 | id: ID! 9 | name: String! 10 | child: Child! 11 | } 12 | 13 | type Child @key(fields: "id") { 14 | id: ID! 15 | details(productName: String @fromContext(field: "$product { name }")): String! 16 | } 17 | 18 | type Query { 19 | product(id: ID!): Product 20 | } 21 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionCost.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.8" 4 | import: ["@cost", "@key", "@listSize"] 5 | ) 6 | 7 | type Product @key(fields: "id") { 8 | id: ID! 9 | name: String! 10 | child: Child! @cost(weight: 5) 11 | } 12 | 13 | type Child @key(fields: "id") { 14 | id: ID! 15 | details(productName: String): [String!] @listSize(assumedSize: 10) 16 | } 17 | 18 | type Query { 19 | product(id: ID!): Product 20 | } 21 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionInterfaceObject.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@key", "@interfaceObject"]) 2 | 3 | type Product @key(fields: "id") @interfaceObject { 4 | id: ID! 5 | name: String! 6 | } 7 | 8 | type Query { 9 | product(id: ID!): Product 10 | } 11 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionPolicy.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@policy", "Policy", "FieldSet"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | supplier: String @policy(policies: [["policy"]]) 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product 11 | } 12 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionProgressiveOverride.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.6", import: [ 2 | "@key", 3 | "@override" 4 | ]) 5 | 6 | type Product @key(fields: "id") { 7 | id: ID! 8 | name: String! @override(from: "old-product-service", label: "percent(5)") 9 | } 10 | 11 | type Query { 12 | product(id: ID!): Product 13 | } 14 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionRepeatableShareable.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@key", "@shareable"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | position: Position 7 | } 8 | 9 | type Position @shareable { 10 | x: Float! 11 | y: Float! 12 | } 13 | 14 | extend type Position @shareable { 15 | z: Float! 16 | } 17 | 18 | type Query { 19 | product(id: ID!): Product 20 | } 21 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/invalidSpecVersionRequiresScopes.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@requiresScopes", "Scope", "FieldSet"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | supplier: String @requiresScopes(scopes: [["scopeA"]]) 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product 11 | } 12 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/noEntities/schema.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | product(id: ID!): Product 3 | } 4 | 5 | type Product { 6 | id: ID! 7 | name: String 8 | } 9 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/noEntities/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | type Product { 6 | id: ID! 7 | name: String 8 | } 9 | 10 | type Query { 11 | product(id: ID!): Product 12 | } 13 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/noEntities/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema { 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @extends on OBJECT | INTERFACE 12 | 13 | directive @external on FIELD_DEFINITION 14 | 15 | "Directs the executor to include this field or fragment only when the `if` argument is true" 16 | directive @include( 17 | "Included when true." 18 | if: Boolean! 19 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 20 | 21 | directive @key(fields: _FieldSet!) repeatable on OBJECT | INTERFACE 22 | 23 | "Indicates an Input Object is a OneOf Input Object." 24 | directive @oneOf on INPUT_OBJECT 25 | 26 | directive @provides(fields: _FieldSet!) on FIELD_DEFINITION 27 | 28 | directive @requires(fields: _FieldSet!) on FIELD_DEFINITION 29 | 30 | "Directs the executor to skip this field or fragment when the `if` argument is true." 31 | directive @skip( 32 | "Skipped when true." 33 | if: Boolean! 34 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 35 | 36 | "Exposes a URL that specifies the behaviour of this scalar." 37 | directive @specifiedBy( 38 | "The URL that specifies the behaviour of this scalar." 39 | url: String! 40 | ) on SCALAR 41 | 42 | type Product { 43 | id: ID! 44 | name: String 45 | } 46 | 47 | type Query { 48 | _service: _Service! 49 | product(id: ID!): Product 50 | } 51 | 52 | type _Service { 53 | sdl: String! 54 | } 55 | 56 | scalar _FieldSet 57 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/nonResolvableKey/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@key"]) 2 | 3 | type Product { 4 | id: ID! 5 | description: String! 6 | createdBy: User 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product 11 | } 12 | 13 | type User @key(fields: "email", resolvable: false) { 14 | email: ID! 15 | } 16 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/nonResolvableKey/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @federation__extends on OBJECT | INTERFACE 8 | 9 | directive @federation__external on OBJECT | FIELD_DEFINITION 10 | 11 | directive @federation__interfaceObject on OBJECT 12 | 13 | directive @federation__override(from: String!) on FIELD_DEFINITION 14 | 15 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 20 | 21 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 22 | 23 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 24 | 25 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 26 | 27 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | union _Entity = User 30 | 31 | type Product { 32 | createdBy: User 33 | description: String! 34 | id: ID! 35 | } 36 | 37 | type Query { 38 | _entities(representations: [_Any!]!): [_Entity]! 39 | _service: _Service! 40 | product(id: ID!): Product 41 | } 42 | 43 | type User @key(fields : "email", resolvable : false) { 44 | email: ID! 45 | } 46 | 47 | type _Service { 48 | sdl: String! 49 | } 50 | 51 | enum link__Purpose { 52 | EXECUTION 53 | SECURITY 54 | } 55 | 56 | scalar _Any 57 | 58 | scalar federation__FieldSet 59 | 60 | scalar link__Import 61 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/nonResolvableKey/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.3"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__interfaceObject on OBJECT 18 | 19 | directive @federation__override(from: String!) on FIELD_DEFINITION 20 | 21 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 26 | 27 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 28 | 29 | "Directs the executor to include this field or fragment only when the `if` argument is true" 30 | directive @include( 31 | "Included when true." 32 | if: Boolean! 33 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 34 | 35 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 36 | 37 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 38 | 39 | "Indicates an Input Object is a OneOf Input Object." 40 | directive @oneOf on INPUT_OBJECT 41 | 42 | "Directs the executor to skip this field or fragment when the `if` argument is true." 43 | directive @skip( 44 | "Skipped when true." 45 | if: Boolean! 46 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 47 | 48 | "Exposes a URL that specifies the behaviour of this scalar." 49 | directive @specifiedBy( 50 | "The URL that specifies the behaviour of this scalar." 51 | url: String! 52 | ) on SCALAR 53 | 54 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 55 | 56 | union _Entity = User 57 | 58 | type Product { 59 | createdBy: User 60 | description: String! 61 | id: ID! 62 | } 63 | 64 | type Query { 65 | _entities(representations: [_Any!]!): [_Entity]! 66 | _service: _Service! 67 | product(id: ID!): Product 68 | } 69 | 70 | type User @key(fields : "email", resolvable : false) { 71 | email: ID! 72 | } 73 | 74 | type _Service { 75 | sdl: String! 76 | } 77 | 78 | enum link__Purpose { 79 | EXECUTION 80 | SECURITY 81 | } 82 | 83 | scalar _Any 84 | 85 | scalar federation__FieldSet 86 | 87 | scalar link__Import 88 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/policy/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.6", import: ["@key", "@policy", "Policy", "FieldSet"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | supplier: String @policy(policies: [["policyA"]]) 7 | } 8 | 9 | type Query { 10 | product(id: ID!): Product 11 | } 12 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/policy/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@policy", "Policy", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.6"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 6 | 7 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 8 | 9 | directive @federation__extends on OBJECT | INTERFACE 10 | 11 | directive @federation__external on OBJECT | FIELD_DEFINITION 12 | 13 | directive @federation__interfaceObject on OBJECT 14 | 15 | directive @federation__override(from: String!) on FIELD_DEFINITION 16 | 17 | directive @federation__provides(fields: FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__requires(fields: FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 22 | 23 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 24 | 25 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 26 | 27 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 28 | 29 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 30 | 31 | directive @policy(policies: [[Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 32 | 33 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 34 | 35 | union _Entity = Product 36 | 37 | type Product @key(fields : "id", resolvable : true) { 38 | id: ID! 39 | name: String! 40 | supplier: String @policy(policies : [["policyA"]]) 41 | } 42 | 43 | type Query { 44 | _entities(representations: [_Any!]!): [_Entity]! 45 | _service: _Service! 46 | product(id: ID!): Product 47 | } 48 | 49 | type _Service { 50 | sdl: String! 51 | } 52 | 53 | enum link__Purpose { 54 | EXECUTION 55 | SECURITY 56 | } 57 | 58 | scalar FieldSet 59 | 60 | scalar Policy 61 | 62 | scalar _Any 63 | 64 | scalar federation__Scope 65 | 66 | scalar link__Import 67 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/policy/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@policy", "Policy", "FieldSet"], url : "https://specs.apollo.dev/federation/v2.6"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 12 | 13 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 14 | 15 | directive @federation__extends on OBJECT | INTERFACE 16 | 17 | directive @federation__external on OBJECT | FIELD_DEFINITION 18 | 19 | directive @federation__interfaceObject on OBJECT 20 | 21 | directive @federation__override(from: String!) on FIELD_DEFINITION 22 | 23 | directive @federation__provides(fields: FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @federation__requires(fields: FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @federation__requiresScopes(scopes: [[federation__Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 28 | 29 | directive @federation__shareable repeatable on OBJECT | FIELD_DEFINITION 30 | 31 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 32 | 33 | "Directs the executor to include this field or fragment only when the `if` argument is true" 34 | directive @include( 35 | "Included when true." 36 | if: Boolean! 37 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 38 | 39 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 40 | 41 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 42 | 43 | "Indicates an Input Object is a OneOf Input Object." 44 | directive @oneOf on INPUT_OBJECT 45 | 46 | directive @policy(policies: [[Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 47 | 48 | "Directs the executor to skip this field or fragment when the `if` argument is true." 49 | directive @skip( 50 | "Skipped when true." 51 | if: Boolean! 52 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 53 | 54 | "Exposes a URL that specifies the behaviour of this scalar." 55 | directive @specifiedBy( 56 | "The URL that specifies the behaviour of this scalar." 57 | url: String! 58 | ) on SCALAR 59 | 60 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 61 | 62 | union _Entity = Product 63 | 64 | type Product @key(fields : "id", resolvable : true) { 65 | id: ID! 66 | name: String! 67 | supplier: String @policy(policies : [["policyA"]]) 68 | } 69 | 70 | type Query { 71 | _entities(representations: [_Any!]!): [_Entity]! 72 | _service: _Service! 73 | product(id: ID!): Product 74 | } 75 | 76 | type _Service { 77 | sdl: String! 78 | } 79 | 80 | enum link__Purpose { 81 | EXECUTION 82 | SECURITY 83 | } 84 | 85 | scalar FieldSet 86 | 87 | scalar Policy 88 | 89 | scalar _Any 90 | 91 | scalar federation__Scope 92 | 93 | scalar link__Import 94 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/progressiveOverride/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.7", import: [ 2 | "@authenticated", 3 | "@composeDirective", 4 | "@extends", 5 | "@external", 6 | "@inaccessible", 7 | "@interfaceObject", 8 | "@key", 9 | "@override", 10 | "@policy", 11 | "@provides", 12 | "@requires", 13 | "@requiresScopes", 14 | "@shareable", 15 | "@tag", 16 | "FieldSet", 17 | "Import", 18 | "Policy", 19 | "Scope" 20 | ]) 21 | 22 | type Product @key(fields: "id") { 23 | id: ID! 24 | name: String! @override(from: "old-product-service", label: "percent(5)") 25 | } 26 | 27 | type Query { 28 | product(id: ID!): Product 29 | } 30 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/progressiveOverride/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@authenticated", "@composeDirective", "@extends", "@external", "@inaccessible", "@interfaceObject", "@key", "@override", "@policy", "@provides", "@requires", "@requiresScopes", "@shareable", "@tag", "FieldSet", "Import", "Policy", "Scope"], url : "https://specs.apollo.dev/federation/v2.7"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 6 | 7 | directive @composeDirective(name: String!) repeatable on SCHEMA 8 | 9 | directive @extends on OBJECT | INTERFACE 10 | 11 | directive @external on OBJECT | FIELD_DEFINITION 12 | 13 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 14 | 15 | directive @interfaceObject on OBJECT 16 | 17 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 18 | 19 | directive @link(as: String, for: link__Purpose, import: [Import], url: String!) repeatable on SCHEMA 20 | 21 | directive @override(from: String!, label: String) on FIELD_DEFINITION 22 | 23 | directive @policy(policies: [[Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 24 | 25 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 28 | 29 | directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 30 | 31 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 32 | 33 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 34 | 35 | union _Entity = Product 36 | 37 | type Product @key(fields : "id", resolvable : true) { 38 | id: ID! 39 | name: String! @override(from : "old-product-service", label : "percent(5)") 40 | } 41 | 42 | type Query { 43 | _entities(representations: [_Any!]!): [_Entity]! 44 | _service: _Service! 45 | product(id: ID!): Product 46 | } 47 | 48 | type _Service { 49 | sdl: String! 50 | } 51 | 52 | enum link__Purpose { 53 | EXECUTION 54 | SECURITY 55 | } 56 | 57 | scalar FieldSet 58 | 59 | scalar Import 60 | 61 | scalar Policy 62 | 63 | scalar Scope 64 | 65 | scalar _Any 66 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/progressiveOverride/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@authenticated", "@composeDirective", "@extends", "@external", "@inaccessible", "@interfaceObject", "@key", "@override", "@policy", "@provides", "@requires", "@requiresScopes", "@shareable", "@tag", "FieldSet", "Import", "Policy", "Scope"], url : "https://specs.apollo.dev/federation/v2.7"){ 2 | query: Query 3 | } 4 | 5 | directive @authenticated on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 6 | 7 | directive @composeDirective(name: String!) repeatable on SCHEMA 8 | 9 | "Marks the field, argument, input field or enum value as deprecated" 10 | directive @deprecated( 11 | "The reason for the deprecation" 12 | reason: String = "No longer supported" 13 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 14 | 15 | directive @extends on OBJECT | INTERFACE 16 | 17 | directive @external on OBJECT | FIELD_DEFINITION 18 | 19 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 20 | 21 | "Directs the executor to include this field or fragment only when the `if` argument is true" 22 | directive @include( 23 | "Included when true." 24 | if: Boolean! 25 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 26 | 27 | directive @interfaceObject on OBJECT 28 | 29 | directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 30 | 31 | directive @link(as: String, for: link__Purpose, import: [Import], url: String!) repeatable on SCHEMA 32 | 33 | "Indicates an Input Object is a OneOf Input Object." 34 | directive @oneOf on INPUT_OBJECT 35 | 36 | directive @override(from: String!, label: String) on FIELD_DEFINITION 37 | 38 | directive @policy(policies: [[Policy!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 39 | 40 | directive @provides(fields: FieldSet!) on FIELD_DEFINITION 41 | 42 | directive @requires(fields: FieldSet!) on FIELD_DEFINITION 43 | 44 | directive @requiresScopes(scopes: [[Scope!]!]!) on SCALAR | OBJECT | FIELD_DEFINITION | INTERFACE | ENUM 45 | 46 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 47 | 48 | "Directs the executor to skip this field or fragment when the `if` argument is true." 49 | directive @skip( 50 | "Skipped when true." 51 | if: Boolean! 52 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 53 | 54 | "Exposes a URL that specifies the behaviour of this scalar." 55 | directive @specifiedBy( 56 | "The URL that specifies the behaviour of this scalar." 57 | url: String! 58 | ) on SCALAR 59 | 60 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 61 | 62 | union _Entity = Product 63 | 64 | type Product @key(fields : "id", resolvable : true) { 65 | id: ID! 66 | name: String! @override(from : "old-product-service", label : "percent(5)") 67 | } 68 | 69 | type Query { 70 | _entities(representations: [_Any!]!): [_Entity]! 71 | _service: _Service! 72 | product(id: ID!): Product 73 | } 74 | 75 | type _Service { 76 | sdl: String! 77 | } 78 | 79 | enum link__Purpose { 80 | EXECUTION 81 | SECURITY 82 | } 83 | 84 | scalar FieldSet 85 | 86 | scalar Import 87 | 88 | scalar Policy 89 | 90 | scalar Scope 91 | 92 | scalar _Any 93 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/renamedImports/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link(url: "https://specs.apollo.dev/federation/v2.0", 3 | import: [{ name: "@key", as: "@myKey" }, { name: "@shareable" }, "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"]) 4 | 5 | type Product @myKey(fields: "id") @myKey(fields: "sku package") @myKey(fields: "sku variation { id }") { 6 | id: ID! 7 | sku: String 8 | package: String 9 | variation: ProductVariation 10 | dimensions: ProductDimension 11 | createdBy: User @provides(fields: "totalProductsCreated") 12 | notes: String @tag(name: "internal") 13 | } 14 | 15 | type ProductVariation { 16 | id: ID! 17 | } 18 | 19 | type ProductDimension @shareable { 20 | size: String 21 | weight: Float 22 | unit: String @inaccessible 23 | } 24 | 25 | type Query { 26 | product(id: ID!): Product 27 | } 28 | 29 | type User @myKey(fields: "email") { 30 | email: ID! 31 | name: String @shareable @override(from: "users") 32 | totalProductsCreated: Int @external 33 | } 34 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/renamedImports/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : [{name : "@key", as : "@myKey"}, {name : "@shareable"}, "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | directive @extends on OBJECT | INTERFACE 6 | 7 | directive @external on OBJECT | FIELD_DEFINITION 8 | 9 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 10 | 11 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 12 | 13 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 14 | 15 | directive @myKey(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 16 | 17 | directive @override(from: String!) on FIELD_DEFINITION 18 | 19 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @shareable on OBJECT | FIELD_DEFINITION 22 | 23 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | type Product @myKey(fields : "id", resolvable : true) @myKey(fields : "sku package", resolvable : true) @myKey(fields : "sku variation { id }", resolvable : true) { 26 | createdBy: User @provides(fields : "totalProductsCreated") 27 | dimensions: ProductDimension 28 | id: ID! 29 | notes: String @tag(name : "internal") 30 | package: String 31 | sku: String 32 | variation: ProductVariation 33 | } 34 | 35 | type ProductDimension @shareable { 36 | size: String 37 | unit: String @inaccessible 38 | weight: Float 39 | } 40 | 41 | type ProductVariation { 42 | id: ID! 43 | } 44 | 45 | type Query { 46 | _service: _Service! 47 | product(id: ID!): Product 48 | } 49 | 50 | type User @myKey(fields : "email", resolvable : true) { 51 | email: ID! 52 | name: String @override(from : "users") @shareable 53 | totalProductsCreated: Int @external 54 | } 55 | 56 | type _Service { 57 | sdl: String! 58 | } 59 | 60 | enum link__Purpose { 61 | EXECUTION 62 | SECURITY 63 | } 64 | 65 | scalar federation__FieldSet 66 | 67 | scalar link__Import 68 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/renamedImports/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : [{name : "@key", as : "@myKey"}, {name : "@shareable"}, "@provides", "@external", "@tag", "@extends", "@override", "@inaccessible"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @extends on OBJECT | INTERFACE 12 | 13 | directive @external on OBJECT | FIELD_DEFINITION 14 | 15 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 18 | 19 | "Directs the executor to include this field or fragment only when the `if` argument is true" 20 | directive @include( 21 | "Included when true." 22 | if: Boolean! 23 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 24 | 25 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 26 | 27 | directive @myKey(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 28 | 29 | "Indicates an Input Object is a OneOf Input Object." 30 | directive @oneOf on INPUT_OBJECT 31 | 32 | directive @override(from: String!) on FIELD_DEFINITION 33 | 34 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 35 | 36 | directive @shareable on OBJECT | FIELD_DEFINITION 37 | 38 | "Directs the executor to skip this field or fragment when the `if` argument is true." 39 | directive @skip( 40 | "Skipped when true." 41 | if: Boolean! 42 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 43 | 44 | "Exposes a URL that specifies the behaviour of this scalar." 45 | directive @specifiedBy( 46 | "The URL that specifies the behaviour of this scalar." 47 | url: String! 48 | ) on SCALAR 49 | 50 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 51 | 52 | type Product @myKey(fields : "id", resolvable : true) @myKey(fields : "sku package", resolvable : true) @myKey(fields : "sku variation { id }", resolvable : true) { 53 | createdBy: User @provides(fields : "totalProductsCreated") 54 | dimensions: ProductDimension 55 | id: ID! 56 | notes: String @tag(name : "internal") 57 | package: String 58 | sku: String 59 | variation: ProductVariation 60 | } 61 | 62 | type ProductDimension @shareable { 63 | size: String 64 | unit: String @inaccessible 65 | weight: Float 66 | } 67 | 68 | type ProductVariation { 69 | id: ID! 70 | } 71 | 72 | type Query { 73 | _service: _Service! 74 | product(id: ID!): Product 75 | } 76 | 77 | type User @myKey(fields : "email", resolvable : true) { 78 | email: ID! 79 | name: String @override(from : "users") @shareable 80 | totalProductsCreated: Int @external 81 | } 82 | 83 | type _Service { 84 | sdl: String! 85 | } 86 | 87 | enum link__Purpose { 88 | EXECUTION 89 | SECURITY 90 | } 91 | 92 | scalar federation__FieldSet 93 | 94 | scalar link__Import 95 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/repeatableShareable/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.2", import: ["@key", "@shareable"]) 2 | 3 | type Product @key(fields: "id") { 4 | id: ID! 5 | name: String! 6 | position: Position 7 | } 8 | 9 | type Position @shareable { 10 | x: Float! 11 | y: Float! 12 | } 13 | 14 | extend type Position @shareable { 15 | z: Float! 16 | } 17 | 18 | type Query { 19 | product(id: ID!): Product 20 | } 21 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/repeatableShareable/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@shareable"], url : "https://specs.apollo.dev/federation/v2.2"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @federation__extends on OBJECT | INTERFACE 8 | 9 | directive @federation__external on OBJECT | FIELD_DEFINITION 10 | 11 | directive @federation__override(from: String!) on FIELD_DEFINITION 12 | 13 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 14 | 15 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 16 | 17 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 18 | 19 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 20 | 21 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 22 | 23 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 24 | 25 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 26 | 27 | union _Entity = Product 28 | 29 | type Position @shareable @shareable { 30 | x: Float! 31 | y: Float! 32 | z: Float! 33 | } 34 | 35 | type Product @key(fields : "id", resolvable : true) { 36 | id: ID! 37 | name: String! 38 | position: Position 39 | } 40 | 41 | type Query { 42 | _entities(representations: [_Any!]!): [_Entity]! 43 | _service: _Service! 44 | product(id: ID!): Product 45 | } 46 | 47 | type _Service { 48 | sdl: String! 49 | } 50 | 51 | enum link__Purpose { 52 | EXECUTION 53 | SECURITY 54 | } 55 | 56 | scalar _Any 57 | 58 | scalar federation__FieldSet 59 | 60 | scalar link__Import 61 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/repeatableShareable/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key", "@shareable"], url : "https://specs.apollo.dev/federation/v2.2"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__composeDirective(name: String!) repeatable on SCHEMA 12 | 13 | directive @federation__extends on OBJECT | INTERFACE 14 | 15 | directive @federation__external on OBJECT | FIELD_DEFINITION 16 | 17 | directive @federation__override(from: String!) on FIELD_DEFINITION 18 | 19 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 22 | 23 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | "Directs the executor to include this field or fragment only when the `if` argument is true" 26 | directive @include( 27 | "Included when true." 28 | if: Boolean! 29 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 30 | 31 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 32 | 33 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 34 | 35 | "Indicates an Input Object is a OneOf Input Object." 36 | directive @oneOf on INPUT_OBJECT 37 | 38 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 39 | 40 | "Directs the executor to skip this field or fragment when the `if` argument is true." 41 | directive @skip( 42 | "Skipped when true." 43 | if: Boolean! 44 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 45 | 46 | "Exposes a URL that specifies the behaviour of this scalar." 47 | directive @specifiedBy( 48 | "The URL that specifies the behaviour of this scalar." 49 | url: String! 50 | ) on SCALAR 51 | 52 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 53 | 54 | union _Entity = Product 55 | 56 | type Position @shareable @shareable { 57 | x: Float! 58 | y: Float! 59 | z: Float! 60 | } 61 | 62 | type Product @key(fields : "id", resolvable : true) { 63 | id: ID! 64 | name: String! 65 | position: Position 66 | } 67 | 68 | type Query { 69 | _entities(representations: [_Any!]!): [_Entity]! 70 | _service: _Service! 71 | product(id: ID!): Product 72 | } 73 | 74 | type _Service { 75 | sdl: String! 76 | } 77 | 78 | enum link__Purpose { 79 | EXECUTION 80 | SECURITY 81 | } 82 | 83 | scalar _Any 84 | 85 | scalar federation__FieldSet 86 | 87 | scalar link__Import 88 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/scalars/schema.graphql: -------------------------------------------------------------------------------- 1 | extend schema 2 | @link( 3 | url: "https://specs.apollo.dev/federation/v2.3" 4 | import: [ 5 | "@composeDirective" 6 | "@extends" 7 | "@external" 8 | "@key" 9 | "@inaccessible" 10 | "@interfaceObject" 11 | "@override" 12 | "@provides" 13 | "@requires" 14 | "@shareable" 15 | "@tag" 16 | ] 17 | ) 18 | @link(url: "https://myspecs.dev/myCustomDirective/v1.0", import: ["@custom"]) 19 | @composeDirective(name: "@custom") 20 | 21 | scalar federation__FieldSet 22 | 23 | directive @custom on OBJECT 24 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 25 | 26 | type Product 27 | @custom 28 | @key(fields: "id") 29 | @key(fields: "sku package") 30 | @key(fields: "sku variation { id }") { 31 | id: ID! 32 | sku: String 33 | package: String 34 | variation: ProductVariation 35 | dimensions: ProductDimension 36 | createdBy: User @provides(fields: "totalProductsCreated") 37 | notes: String @tag(name: "internal") 38 | research: [ProductResearch!]! 39 | } 40 | 41 | type DeprecatedProduct @key(fields: "sku package") { 42 | sku: String! 43 | package: String! 44 | reason: String 45 | createdBy: User 46 | } 47 | 48 | type ProductVariation { 49 | id: ID! 50 | } 51 | 52 | type ProductResearch @key(fields: "study { caseNumber }") { 53 | study: CaseStudy! 54 | outcome: String 55 | } 56 | 57 | type CaseStudy { 58 | caseNumber: ID! 59 | description: String 60 | } 61 | 62 | type ProductDimension @shareable { 63 | size: String 64 | weight: Float 65 | unit: String @inaccessible 66 | } 67 | 68 | type Query { 69 | product(id: ID!): Product 70 | deprecatedProduct(sku: String!, package: String!): DeprecatedProduct @deprecated(reason: "Use product query instead") 71 | } 72 | 73 | type User @key(fields: "email") { 74 | averageProductsCreatedPerYear: Int @requires(fields: "totalProductsCreated yearsOfEmployment") 75 | email: ID! @external 76 | name: String @override(from: "users") 77 | totalProductsCreated: Int @external 78 | yearsOfEmployment: Int! @external 79 | } 80 | 81 | type Inventory @interfaceObject @key(fields: "id") { 82 | id: ID! 83 | deprecatedProducts: [DeprecatedProduct!]! 84 | } 85 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/scalars/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @composeDirective(name : "@custom") @link(import : ["@composeDirective", "@extends", "@external", "@key", "@inaccessible", "@interfaceObject", "@override", "@provides", "@requires", "@shareable", "@tag"], url : "https://specs.apollo.dev/federation/v2.3") @link(import : ["@custom"], url : "https://myspecs.dev/myCustomDirective/v1.0"){ 2 | query: Query 3 | } 4 | 5 | directive @composeDirective(name: String!) repeatable on SCHEMA 6 | 7 | directive @custom on OBJECT 8 | 9 | directive @extends on OBJECT | INTERFACE 10 | 11 | directive @external on OBJECT | FIELD_DEFINITION 12 | 13 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 14 | 15 | directive @interfaceObject on OBJECT 16 | 17 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 18 | 19 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 20 | 21 | directive @override(from: String!) on FIELD_DEFINITION 22 | 23 | directive @provides(fields: federation__FieldSet!) on FIELD_DEFINITION 24 | 25 | directive @requires(fields: federation__FieldSet!) on FIELD_DEFINITION 26 | 27 | directive @shareable repeatable on OBJECT | FIELD_DEFINITION 28 | 29 | directive @tag(name: String!) repeatable on SCHEMA | SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 30 | 31 | union _Entity = DeprecatedProduct | Inventory | Product | ProductResearch | User 32 | 33 | type CaseStudy { 34 | caseNumber: ID! 35 | description: String 36 | } 37 | 38 | type DeprecatedProduct @key(fields : "sku package", resolvable : true) { 39 | createdBy: User 40 | package: String! 41 | reason: String 42 | sku: String! 43 | } 44 | 45 | type Inventory @interfaceObject @key(fields : "id", resolvable : true) { 46 | deprecatedProducts: [DeprecatedProduct!]! 47 | id: ID! 48 | } 49 | 50 | type Product @custom @key(fields : "id", resolvable : true) @key(fields : "sku package", resolvable : true) @key(fields : "sku variation { id }", resolvable : true) { 51 | createdBy: User @provides(fields : "totalProductsCreated") 52 | dimensions: ProductDimension 53 | id: ID! 54 | notes: String @tag(name : "internal") 55 | package: String 56 | research: [ProductResearch!]! 57 | sku: String 58 | variation: ProductVariation 59 | } 60 | 61 | type ProductDimension @shareable { 62 | size: String 63 | unit: String @inaccessible 64 | weight: Float 65 | } 66 | 67 | type ProductResearch @key(fields : "study { caseNumber }", resolvable : true) { 68 | outcome: String 69 | study: CaseStudy! 70 | } 71 | 72 | type ProductVariation { 73 | id: ID! 74 | } 75 | 76 | type Query { 77 | _entities(representations: [_Any!]!): [_Entity]! 78 | _service: _Service! 79 | deprecatedProduct(package: String!, sku: String!): DeprecatedProduct @deprecated(reason : "Use product query instead") 80 | product(id: ID!): Product 81 | } 82 | 83 | type User @key(fields : "email", resolvable : true) { 84 | averageProductsCreatedPerYear: Int @requires(fields : "totalProductsCreated yearsOfEmployment") 85 | email: ID! @external 86 | name: String @override(from : "users") 87 | totalProductsCreated: Int @external 88 | yearsOfEmployment: Int! @external 89 | } 90 | 91 | type _Service { 92 | sdl: String! 93 | } 94 | 95 | enum link__Purpose { 96 | EXECUTION 97 | SECURITY 98 | } 99 | 100 | scalar _Any 101 | 102 | scalar federation__FieldSet 103 | 104 | scalar link__Import 105 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/schemaImport/schema.graphql: -------------------------------------------------------------------------------- 1 | schema @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key"]) { 2 | query: Query 3 | } 4 | 5 | type Query { 6 | foo(id: ID!): Foo 7 | } 8 | 9 | type Foo @key(fields: "id") { 10 | id: ID! 11 | name: String! 12 | } 13 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/schemaImport/schema_federated.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | directive @federation__extends on OBJECT | INTERFACE 6 | 7 | directive @federation__external on OBJECT | FIELD_DEFINITION 8 | 9 | directive @federation__override(from: String!) on FIELD_DEFINITION 10 | 11 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 12 | 13 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 14 | 15 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 16 | 17 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 18 | 19 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 20 | 21 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 22 | 23 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | union _Entity = Foo 26 | 27 | type Foo @key(fields : "id", resolvable : true) { 28 | id: ID! 29 | name: String! 30 | } 31 | 32 | type Query { 33 | _entities(representations: [_Any!]!): [_Entity]! 34 | _service: _Service! 35 | foo(id: ID!): Foo 36 | } 37 | 38 | type _Service { 39 | sdl: String! 40 | } 41 | 42 | enum link__Purpose { 43 | EXECUTION 44 | SECURITY 45 | } 46 | 47 | scalar _Any 48 | 49 | scalar federation__FieldSet 50 | 51 | scalar link__Import 52 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/schemaImport/schema_full.graphql: -------------------------------------------------------------------------------- 1 | schema @link(import : ["@key"], url : "https://specs.apollo.dev/federation/v2.0"){ 2 | query: Query 3 | } 4 | 5 | "Marks the field, argument, input field or enum value as deprecated" 6 | directive @deprecated( 7 | "The reason for the deprecation" 8 | reason: String = "No longer supported" 9 | ) on FIELD_DEFINITION | ARGUMENT_DEFINITION | ENUM_VALUE | INPUT_FIELD_DEFINITION 10 | 11 | directive @federation__extends on OBJECT | INTERFACE 12 | 13 | directive @federation__external on OBJECT | FIELD_DEFINITION 14 | 15 | directive @federation__override(from: String!) on FIELD_DEFINITION 16 | 17 | directive @federation__provides(fields: federation__FieldSet!) on FIELD_DEFINITION 18 | 19 | directive @federation__requires(fields: federation__FieldSet!) on FIELD_DEFINITION 20 | 21 | directive @federation__shareable on OBJECT | FIELD_DEFINITION 22 | 23 | directive @inaccessible on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 24 | 25 | "Directs the executor to include this field or fragment only when the `if` argument is true" 26 | directive @include( 27 | "Included when true." 28 | if: Boolean! 29 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 30 | 31 | directive @key(fields: federation__FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE 32 | 33 | directive @link(as: String, for: link__Purpose, import: [link__Import], url: String!) repeatable on SCHEMA 34 | 35 | "Indicates an Input Object is a OneOf Input Object." 36 | directive @oneOf on INPUT_OBJECT 37 | 38 | "Directs the executor to skip this field or fragment when the `if` argument is true." 39 | directive @skip( 40 | "Skipped when true." 41 | if: Boolean! 42 | ) on FIELD | FRAGMENT_SPREAD | INLINE_FRAGMENT 43 | 44 | "Exposes a URL that specifies the behaviour of this scalar." 45 | directive @specifiedBy( 46 | "The URL that specifies the behaviour of this scalar." 47 | url: String! 48 | ) on SCALAR 49 | 50 | directive @tag(name: String!) repeatable on SCALAR | OBJECT | FIELD_DEFINITION | ARGUMENT_DEFINITION | INTERFACE | UNION | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION 51 | 52 | union _Entity = Foo 53 | 54 | type Foo @key(fields : "id", resolvable : true) { 55 | id: ID! 56 | name: String! 57 | } 58 | 59 | type Query { 60 | _entities(representations: [_Any!]!): [_Entity]! 61 | _service: _Service! 62 | foo(id: ID!): Foo 63 | } 64 | 65 | type _Service { 66 | sdl: String! 67 | } 68 | 69 | enum link__Purpose { 70 | EXECUTION 71 | SECURITY 72 | } 73 | 74 | scalar _Any 75 | 76 | scalar federation__FieldSet 77 | 78 | scalar link__Import 79 | -------------------------------------------------------------------------------- /graphql-java-support/src/test/resources/schemas/tracingSchema.graphql: -------------------------------------------------------------------------------- 1 | type Query { 2 | widgets: [Widget!] 3 | listOfLists: [[Widget!]!] 4 | listOfScalars: [String!]! 5 | } 6 | 7 | type Widget { 8 | foo: String 9 | bar: String 10 | } 11 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "labels": ["type: dependencies"], 6 | "packageRules": [ 7 | { 8 | "groupName": "all non-major dependencies", 9 | "matchUpdateTypes": ["patch", "minor"], 10 | "groupSlug": "all-minor-patch", 11 | }, 12 | { 13 | "groupName": "GraphQL Java (ignoring snapshot builds)", 14 | "matchPackagePrefixes": ["com.graphql-java:"], 15 | "allowedVersions": "/^[0-9]+\\.[0-9]+(\\.[0-9]+)?$/" 16 | }, 17 | { 18 | "groupName": "Gradle version updates", 19 | "matchDatasources": ["docker", "gradle-version"], 20 | "matchPackageNames": ["gradle"], 21 | "labels": ["type: build"] 22 | }, 23 | { 24 | "groupName": "Protobuf version updates", 25 | "matchPackagePrefixes": ["com.google.protobuf:"] 26 | } 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "federation-jvm" 2 | 3 | include(":federation-graphql-java-support") 4 | include(":federation-spring-subscription-callback") 5 | 6 | project(":federation-graphql-java-support").projectDir = file("graphql-java-support") 7 | project(":federation-spring-subscription-callback").projectDir = file("spring-subscription-callback") 8 | -------------------------------------------------------------------------------- /spring-subscription-callback/build.gradle.kts: -------------------------------------------------------------------------------- 1 | description = "GraphQL Java server support for Apollo Federation" 2 | 3 | plugins { 4 | id("com.apollographql.federation.java-conventions") 5 | } 6 | 7 | val annotationsVersion: String by project 8 | val graphQLJavaVersion: String by project 9 | val mockWebServerVersion: String by project 10 | val slf4jVersion: String by project 11 | val springBootVersion: String by project 12 | val springGraphQLVersion: String by project 13 | val reactorVersion: String by project 14 | dependencies { 15 | compileOnly("org.jetbrains", "annotations", annotationsVersion) 16 | implementation("com.graphql-java", "graphql-java", graphQLJavaVersion) 17 | implementation("org.slf4j", "slf4j-api", slf4jVersion) 18 | implementation("org.springframework.boot", "spring-boot-starter-graphql", springBootVersion) { 19 | exclude(group = "com.graphql-java", module = "graphql-java") 20 | } 21 | implementation("org.springframework.boot", "spring-boot-starter-web", springBootVersion) 22 | implementation("org.springframework.boot", "spring-boot-starter-webflux", springBootVersion) 23 | testCompileOnly("org.jetbrains", "annotations", annotationsVersion) 24 | testImplementation(project(":federation-graphql-java-support")) 25 | testImplementation("com.squareup.okhttp3", "mockwebserver", mockWebServerVersion) 26 | testImplementation("org.springframework.boot", "spring-boot-starter-test", springBootVersion) 27 | testImplementation("org.springframework.boot", "spring-boot-starter-websocket", springBootVersion) 28 | testImplementation("org.springframework.graphql", "spring-graphql-test", springGraphQLVersion) 29 | testImplementation("io.projectreactor", "reactor-test", reactorVersion) 30 | } 31 | 32 | java { 33 | sourceCompatibility = JavaVersion.VERSION_17 34 | targetCompatibility = JavaVersion.VERSION_17 35 | } 36 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/exception/CallbackExtensionNotSpecifiedException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.exception; 2 | 3 | /** 4 | * Exception thrown when user attempts to execute subscription through POST route without specifying 5 | * callback extension. 6 | */ 7 | public class CallbackExtensionNotSpecifiedException extends RuntimeException { 8 | 9 | public CallbackExtensionNotSpecifiedException() { 10 | super("Callback protocol not specified, subscription using POST request is not supported"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/exception/CallbackInitializationFailedException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.exception; 2 | 3 | import com.apollographql.subscription.callback.SubscriptionCallback; 4 | 5 | /** Exception thrown when callback initialization fails. */ 6 | public class CallbackInitializationFailedException extends RuntimeException { 7 | 8 | public CallbackInitializationFailedException(SubscriptionCallback callback, int statusCode) { 9 | super( 10 | "Subscription callback failed initialization: " 11 | + callback 12 | + ", server responded with: " 13 | + statusCode); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/exception/InactiveSubscriptionException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.exception; 2 | 3 | import com.apollographql.subscription.callback.SubscriptionCallback; 4 | 5 | /** 6 | * Exception thrown when subscription becomes inactive (router responds using 2xx status to any 7 | * callback message). 8 | */ 9 | public class InactiveSubscriptionException extends RuntimeException { 10 | 11 | public InactiveSubscriptionException(SubscriptionCallback callback) { 12 | super("Callback protocol " + callback + " failed to communicate with router"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/exception/InvalidCallbackExtensionException.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.exception; 2 | 3 | import java.util.Map; 4 | import java.util.stream.Collectors; 5 | 6 | /** 7 | * Exception thrown when callback extension data is malformed (missing entries or have null values). 8 | */ 9 | public class InvalidCallbackExtensionException extends RuntimeException { 10 | 11 | public InvalidCallbackExtensionException(Map callbackExtension) { 12 | super( 13 | String.format( 14 | "Invalid callback protocol extension specified, extension %s", 15 | callbackExtension.entrySet().stream() 16 | .map(mapper -> mapper.getKey() + "=" + mapper.getValue()) 17 | .collect(Collectors.joining(", ", "{", "}")))); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/message/CallbackMessageAction.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.message; 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty; 4 | 5 | /** HTTP callback message type */ 6 | public enum CallbackMessageAction { 7 | @JsonProperty("check") 8 | CHECK, 9 | @JsonProperty("next") 10 | NEXT, 11 | @JsonProperty("complete") 12 | COMPLETE 13 | } 14 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/message/CallbackMessageCheck.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.message; 2 | 3 | /** 4 | * check message is used during initialization to ensure server can send callbacks 5 | * successfully, and that the id and verifier fields provided by 6 | * Router are correct.
7 | * As long as subscription is active, server must send a check message to 8 | * Router every five seconds. This is used to confirm both that it can still reach 9 | * Router's callback endpoint, and that subscription is still active. 10 | * 11 | * @param id unique subscription ID 12 | * @param verifier value provided by Router that is used to validate requests 13 | */ 14 | public record CallbackMessageCheck(String id, String verifier) 15 | implements SubscritionCallbackMessage { 16 | 17 | @Override 18 | public CallbackMessageAction getAction() { 19 | return CallbackMessageAction.CHECK; 20 | } 21 | 22 | @Override 23 | public String getId() { 24 | return id; 25 | } 26 | 27 | @Override 28 | public String getVerifier() { 29 | return verifier; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/message/CallbackMessageComplete.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.message; 2 | 3 | import graphql.GraphQLError; 4 | import java.util.Collections; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.stream.Collectors; 8 | 9 | /** 10 | * complete message is send to the Router to terminate active 11 | * subscription. Subscription can terminate either by reaching end of the data stream OR by 12 | * encountering an error that caused subscription to fail.
13 | * If subscription failed due to an error, complete message should include list of 14 | * GraphQLErrors that caused the failure. 15 | * 16 | * @param id unique subscription ID 17 | * @param verifier value provided by Router that is used to validate requests 18 | * @param errors optional list of errors if subscription terminated abnormally 19 | */ 20 | public record CallbackMessageComplete(String id, String verifier, List errors) 21 | implements SubscritionCallbackMessage { 22 | 23 | public CallbackMessageComplete(String id, String verifier) { 24 | this(id, verifier, Collections.emptyList()); 25 | } 26 | 27 | @Override 28 | public CallbackMessageAction getAction() { 29 | return CallbackMessageAction.COMPLETE; 30 | } 31 | 32 | @Override 33 | public String getId() { 34 | return id; 35 | } 36 | 37 | @Override 38 | public String getVerifier() { 39 | return verifier; 40 | } 41 | 42 | public List> getErrors() { 43 | return errors.stream().map(GraphQLError::toSpecification).collect(Collectors.toList()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/message/CallbackMessageNext.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.message; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * next message contains emitted GraphQL subscription data. 7 | * 8 | * @param id unique subscription ID 9 | * @param verifier value provided by Router that is used to validate requests 10 | * @param payload emitted GraphQL subscription data 11 | */ 12 | public record CallbackMessageNext(String id, String verifier, Map payload) 13 | implements SubscritionCallbackMessage { 14 | 15 | @Override 16 | public CallbackMessageAction getAction() { 17 | return CallbackMessageAction.NEXT; 18 | } 19 | 20 | @Override 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | @Override 26 | public String getVerifier() { 27 | return verifier; 28 | } 29 | 30 | public Map getPayload() { 31 | return payload; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/main/java/com/apollographql/subscription/message/SubscritionCallbackMessage.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.message; 2 | 3 | /** Common interface for HTTP callback messages. */ 4 | public sealed interface SubscritionCallbackMessage 5 | permits CallbackMessageCheck, CallbackMessageNext, CallbackMessageComplete { 6 | default String getKind() { 7 | return "subscription"; 8 | } 9 | 10 | CallbackMessageAction getAction(); 11 | 12 | String getId(); 13 | 14 | String getVerifier(); 15 | } 16 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/java/com/apollographql/subscription/CallbackTestUtils.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription; 2 | 3 | import static com.apollographql.subscription.callback.SubscriptionCallback.CALLBACK_URL; 4 | import static com.apollographql.subscription.callback.SubscriptionCallback.HEARTBEAT_INTERVAL_MS; 5 | import static com.apollographql.subscription.callback.SubscriptionCallback.SUBSCRIPTION_EXTENSION; 6 | import static com.apollographql.subscription.callback.SubscriptionCallback.SUBSCRIPTION_ID; 7 | import static com.apollographql.subscription.callback.SubscriptionCallback.VERIFIER; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | public class CallbackTestUtils { 13 | public static Map createMockGraphQLRequest( 14 | String subscriptionId, String callbackUrl) { 15 | var subscriptionExtension = new HashMap(); 16 | subscriptionExtension.put(CALLBACK_URL, callbackUrl); 17 | subscriptionExtension.put(SUBSCRIPTION_ID, subscriptionId); 18 | subscriptionExtension.put(VERIFIER, "junit"); 19 | subscriptionExtension.put(HEARTBEAT_INTERVAL_MS, 5000); 20 | return Map.of( 21 | "query", 22 | "subscription { counter }", 23 | "extensions", 24 | Map.of(SUBSCRIPTION_EXTENSION, subscriptionExtension)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/java/com/apollographql/subscription/configuration/TestGraphQLConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.configuration; 2 | 3 | import org.springframework.boot.autoconfigure.graphql.GraphQlSourceBuilderCustomizer; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.graphql.data.federation.FederationSchemaFactory; 6 | 7 | public class TestGraphQLConfiguration { 8 | 9 | @Bean 10 | public GraphQlSourceBuilderCustomizer customizer(FederationSchemaFactory factory) { 11 | return builder -> builder.schemaFactory(factory::createGraphQLSchema); 12 | } 13 | 14 | @Bean 15 | public FederationSchemaFactory federationSchemaFactory() { 16 | return new FederationSchemaFactory(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/java/com/apollographql/subscription/configuration/TestSubscriptionController.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.configuration; 2 | 3 | import java.time.Duration; 4 | import org.springframework.graphql.data.method.annotation.QueryMapping; 5 | import org.springframework.graphql.data.method.annotation.SubscriptionMapping; 6 | import org.springframework.stereotype.Controller; 7 | import reactor.core.publisher.Flux; 8 | 9 | @Controller 10 | public class TestSubscriptionController { 11 | @QueryMapping 12 | public String hello() { 13 | return "Hello World!"; 14 | } 15 | 16 | @SubscriptionMapping 17 | public Flux counter() { 18 | return Flux.just(1, 2, 3).delayElements(Duration.ofMillis(10)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/java/com/apollographql/subscription/webflux/CallbackGraphQLWebfluxHttpHandlerIT.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.webflux; 2 | 3 | import com.apollographql.subscription.CallbackGraphQLHttpHandlerAbstrIT; 4 | import com.apollographql.subscription.CallbackWebGraphQLInterceptor; 5 | import com.apollographql.subscription.callback.SubscriptionCallbackHandler; 6 | import com.apollographql.subscription.configuration.TestGraphQLConfiguration; 7 | import java.util.Set; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.boot.test.web.server.LocalServerPort; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.ComponentScan; 15 | import org.springframework.context.annotation.Configuration; 16 | import org.springframework.context.annotation.Import; 17 | import org.springframework.graphql.ExecutionGraphQlService; 18 | import org.springframework.test.web.reactive.server.WebTestClient; 19 | 20 | @EnableAutoConfiguration 21 | @SpringBootTest( 22 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 23 | classes = CallbackGraphQLWebfluxHttpHandlerIT.GraphQLSubscriptionConfiguration.class, 24 | properties = { 25 | "spring.main.web-application-type=reactive", 26 | "spring.graphql.websocket.path=/subscription", 27 | }) 28 | public class CallbackGraphQLWebfluxHttpHandlerIT extends CallbackGraphQLHttpHandlerAbstrIT { 29 | 30 | @Import(TestGraphQLConfiguration.class) 31 | @Configuration 32 | @ComponentScan(basePackages = "com.apollographql.subscription.configuration") 33 | static class GraphQLSubscriptionConfiguration { 34 | 35 | @Bean 36 | public SubscriptionCallbackHandler callbackHandler(ExecutionGraphQlService graphQlService) { 37 | return new SubscriptionCallbackHandler(graphQlService); 38 | } 39 | 40 | @Bean 41 | public CallbackWebGraphQLInterceptor callbackGraphQlInterceptor( 42 | SubscriptionCallbackHandler callbackHandler) { 43 | var headers = Set.of(TEST_HEADER_NAME); 44 | return new CallbackWebGraphQLInterceptor(callbackHandler, headers); 45 | } 46 | } 47 | 48 | @Autowired private WebTestClient testClient; 49 | @LocalServerPort private int serverPort; 50 | 51 | @Test 52 | public void queries_works() { 53 | verifyQueriesWorks(testClient); 54 | } 55 | 56 | @Test 57 | public void webSocketSubscription_works() { 58 | var url = "ws://localhost:" + serverPort + "/subscription"; 59 | verifyWebSocketSubscriptionWorks(url); 60 | } 61 | 62 | @Test 63 | public void callbackSubscription_works() { 64 | verifySuccessfulCallbackSubscription(testClient); 65 | } 66 | 67 | @Test 68 | public void callbackSubscription_withHeaders_works() { 69 | verifySuccessfulCallbackSubscriptionWithHeaders(testClient); 70 | } 71 | 72 | @Test 73 | public void postSubscription_withoutCallback_returns404() { 74 | verifyPostSubscriptionsWithoutCallbackDontWork(testClient); 75 | } 76 | 77 | @Test 78 | public void callback_initFailed_returns404() { 79 | verifyFailedCallbackInit(testClient); 80 | } 81 | 82 | @Test 83 | public void callback_malformedRequest_returns404() { 84 | verifyMalformedCallbackInfo(testClient); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/java/com/apollographql/subscription/webmvc/CallbackGraphQLWebmvcHttpHandlerIT.java: -------------------------------------------------------------------------------- 1 | package com.apollographql.subscription.webmvc; 2 | 3 | import com.apollographql.subscription.CallbackGraphQLHttpHandlerAbstrIT; 4 | import com.apollographql.subscription.CallbackWebGraphQLInterceptor; 5 | import com.apollographql.subscription.callback.SubscriptionCallbackHandler; 6 | import com.apollographql.subscription.configuration.TestGraphQLConfiguration; 7 | import java.util.Set; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 11 | import org.springframework.boot.test.context.SpringBootTest; 12 | import org.springframework.boot.test.web.server.LocalServerPort; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.ComponentScan; 15 | import org.springframework.context.annotation.Configuration; 16 | import org.springframework.context.annotation.Import; 17 | import org.springframework.graphql.ExecutionGraphQlService; 18 | import org.springframework.test.web.reactive.server.WebTestClient; 19 | 20 | @EnableAutoConfiguration 21 | @SpringBootTest( 22 | webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, 23 | classes = CallbackGraphQLWebmvcHttpHandlerIT.GraphQLSubscriptionConfiguration.class, 24 | properties = { 25 | "spring.main.web-application-type=servlet", 26 | "spring.graphql.websocket.path=/subscription", 27 | }) 28 | public class CallbackGraphQLWebmvcHttpHandlerIT extends CallbackGraphQLHttpHandlerAbstrIT { 29 | 30 | @Import(TestGraphQLConfiguration.class) 31 | @Configuration 32 | @ComponentScan(basePackages = "com.apollographql.subscription.configuration") 33 | static class GraphQLSubscriptionConfiguration { 34 | @Bean 35 | public SubscriptionCallbackHandler callbackHandler(ExecutionGraphQlService graphQlService) { 36 | return new SubscriptionCallbackHandler(graphQlService); 37 | } 38 | 39 | @Bean 40 | public CallbackWebGraphQLInterceptor callbackGraphQlInterceptor( 41 | SubscriptionCallbackHandler callbackHandler) { 42 | var headers = Set.of(TEST_HEADER_NAME); 43 | return new CallbackWebGraphQLInterceptor(callbackHandler, headers); 44 | } 45 | } 46 | 47 | @Autowired private WebTestClient testClient; 48 | @LocalServerPort private int serverPort; 49 | 50 | @Test 51 | public void queries_works() { 52 | verifyQueriesWorks(testClient); 53 | } 54 | 55 | @Test 56 | public void webSocketSubscription_works() { 57 | var url = "http://localhost:" + serverPort + "/subscription"; 58 | verifyWebSocketSubscriptionWorks(url); 59 | } 60 | 61 | @Test 62 | public void callbackSubscription_works() { 63 | verifySuccessfulCallbackSubscription(testClient); 64 | } 65 | 66 | @Test 67 | public void callbackSubscription_withHeaders_works() { 68 | verifySuccessfulCallbackSubscriptionWithHeaders(testClient); 69 | } 70 | 71 | @Test 72 | public void postSubscription_withoutCallback_returns404() { 73 | verifyPostSubscriptionsWithoutCallbackDontWork(testClient); 74 | } 75 | 76 | @Test 77 | public void callback_initFailed_returns404() { 78 | verifyFailedCallbackInit(testClient); 79 | } 80 | 81 | @Test 82 | public void callback_malformedRequest_returns404() { 83 | verifyMalformedCallbackInfo(testClient); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /spring-subscription-callback/src/test/resources/graphql/schema.graphqls: -------------------------------------------------------------------------------- 1 | extend schema @link(url: "https://specs.apollo.dev/federation/v2.5") 2 | 3 | type Query { 4 | hello: String! 5 | } 6 | 7 | type Subscription { 8 | counter: Int! 9 | } 10 | --------------------------------------------------------------------------------