All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.apollographql.federation.graphqljava.printer.ServiceSDLPrinter Maven / Gradle / Ivy

There is a newer version: 5.2.0
Show newest version
package com.apollographql.federation.graphqljava.printer;

import com.apollographql.federation.graphqljava.FederationDirectives;
import com.apollographql.federation.graphqljava._Any;
import com.apollographql.federation.graphqljava._Entity;
import com.apollographql.federation.graphqljava._FieldSet;
import com.apollographql.federation.graphqljava._Service;
import graphql.schema.GraphQLCodeRegistry;
import graphql.schema.GraphQLDirective;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLFieldsContainer;
import graphql.schema.GraphQLNamedSchemaElement;
import graphql.schema.GraphQLSchema;
import graphql.schema.GraphQLSchemaElement;
import graphql.schema.idl.SchemaPrinter;
import graphql.schema.visibility.GraphqlFieldVisibility;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

/**
 * graphql.schema.idl.SchemaPrinter wrapper that is used to generate SDL returned by the 
 * _service { sdl } query and is compatible with Federation v1 and v2 specs.
 */
public final class ServiceSDLPrinter {

  // Apollo Gateway will fail Federation v1 composition if it sees standard directive definitions.
  private static final Set STANDARD_DIRECTIVES =
      new HashSet<>(Arrays.asList("deprecated", "include", "skip", "specifiedBy"));

  private ServiceSDLPrinter() {
    // hidden constructor as this is static utility class
  }

  /**
   * Generate service SDL compatible with Federation v1 specification.
   *
   * @param schema target schema
   * @param queryTypeShouldBeEmpty boolean indicating whether query type contains "fake" query that
   *     should be removed (at least a single query has to be present for graphql-java to consider
   *     it as a valid schema)
   * @return SDL compatible with Federation v1
   */
  public static String generateServiceSDL(GraphQLSchema schema, boolean queryTypeShouldBeEmpty) {
    // Gather directive definitions to hide.
    final Set hiddenDirectiveDefinitions = new HashSet<>();
    hiddenDirectiveDefinitions.addAll(STANDARD_DIRECTIVES);
    hiddenDirectiveDefinitions.addAll(FederationDirectives.allNames);

    // Gather type definitions to hide.
    final Set hiddenTypeDefinitions = new HashSet<>();
    hiddenTypeDefinitions.add(_Any.typeName);
    hiddenTypeDefinitions.add(_Entity.typeName);
    hiddenTypeDefinitions.add(_FieldSet.typeName);
    hiddenTypeDefinitions.add(_Service.typeName);

    // Change field visibility for the query type if needed.
    if (queryTypeShouldBeEmpty) {
      final String queryTypeName = schema.getQueryType().getName();
      final GraphqlFieldVisibility oldFieldVisibility =
          schema.getCodeRegistry().getFieldVisibility();
      final GraphqlFieldVisibility newFieldVisibility =
          new GraphqlFieldVisibility() {
            @Override
            public List getFieldDefinitions(
                GraphQLFieldsContainer fieldsContainer) {
              return fieldsContainer.getName().equals(queryTypeName)
                  ? Collections.emptyList()
                  : oldFieldVisibility.getFieldDefinitions(fieldsContainer);
            }

            @Override
            public GraphQLFieldDefinition getFieldDefinition(
                GraphQLFieldsContainer fieldsContainer, String fieldName) {
              return fieldsContainer.getName().equals(queryTypeName)
                  ? null
                  : oldFieldVisibility.getFieldDefinition(fieldsContainer, fieldName);
            }
          };
      final GraphQLCodeRegistry newCodeRegistry =
          schema
              .getCodeRegistry()
              .transform(
                  codeRegistryBuilder -> codeRegistryBuilder.fieldVisibility(newFieldVisibility));
      schema = schema.transform(schemaBuilder -> schemaBuilder.codeRegistry(newCodeRegistry));
    }

    final Predicate excludeFedTypeDefinitions =
        element ->
            !(element instanceof GraphQLNamedSchemaElement
                && hiddenTypeDefinitions.contains(((GraphQLNamedSchemaElement) element).getName()));
    final Predicate excludeFedDirectiveDefinitions =
        element ->
            !(element instanceof GraphQLDirective
                && hiddenDirectiveDefinitions.contains(((GraphQLDirective) element).getName()));
    final SchemaPrinter.Options options =
        SchemaPrinter.Options.defaultOptions()
            .includeScalarTypes(true)
            .includeSchemaDefinition(true)
            .includeDirectives(FederationDirectives.allNames::contains)
            .includeSchemaElement(
                element ->
                    excludeFedTypeDefinitions.test(element)
                        && excludeFedDirectiveDefinitions.test(element));
    return new SchemaPrinter(options).print(schema).trim();
  }

  /**
   * Generate service SDL compatible with Federation v2 specification.
   *
   * @param schema target schema
   * @return SDL compatible with Federation v2
   */
  public static String generateServiceSDLV2(GraphQLSchema schema) {
    // federation v2 SDL does not need to filter federation directive definitions
    final Set standardDirectives =
        new HashSet<>(Arrays.asList("deprecated", "include", "skip", "specifiedBy"));
    return new SchemaPrinter(
            SchemaPrinter.Options.defaultOptions()
                .includeSchemaDefinition(true)
                .includeScalarTypes(true)
                .includeDirectives(def -> !standardDirectives.contains(def)))
        .print(schema)
        .trim();
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy