GraphQL Java - Schema

15378 단어
Schema
schema 만 들 기
GraphQL API 는 하나의 Schema 를 가지 고 있 으 며, 이 Schema 는 Query (조회) 나 Mutation (변경) 이 가능 한 필드 와 이 필드 의 종 류 를 정의 합 니 다.
graphql - java 는 schema 를 정의 하 는 두 가지 방식 을 제공 합 니 다. 프로 그래 밍 방식 으로 작성 하고 graphql dsl 문법 (SDL 이 라 고도 함) 으로 작성 합 니 다.
예 를 들 면:
SDL 예제:
    type Foo {
        bar: String
    }

Java 코드 예제:
    GraphQLObjectType fooType = newObject()
        .name("Foo")
        .field(newFieldDefinition()
                .name("bar")
                .type(GraphQLString))
        .build();

DataFetcher 와 TypeResolver
DataFetcher 는 필드 (field) 에 대응 하 는 데 이 터 를 가 져 오 는 데 사 용 됩 니 다.또 뮤 테 이 션 (변경) 유형 이 라면 데 이 터 를 업데이트 하 는 데 사용 할 수 있다.
GraphQL 의 필드 (Field Definition) 마다 DataFetcher 가 있 습 니 다.DataFetcher 가 지정 되 지 않 으 면 이 필드 에 서 는 기본 Property DataFetcher 를 사용 합 니 다.
Property DataFetcher 는 Map 과 자바 빈 에서 데 이 터 를 가 져 옵 니 다.필드 이름 이 맵 의 key 나 bean 대상 의 속성 과 함께 DataFetcher 를 명시 적 으로 지정 할 필요 가 없습니다.
TypeResolver (형식 해석 기) 는 graphql - 자바 가 데이터 의 실제 유형 을 판단 하 는 데 도움 을 줍 니 다.예 를 들 어 인터페이스 와 Union 유형 에 대해 TypeResolver 는 최종 적 으로 얻 은 대상 이 인터페이스 (인터페이스) 의 어느 실현 에 속 하 는 지, 또는 Union (연합) 의 어떤 구체 적 인 유형 에 속 하 는 지 확인 하 는 데 사용 된다.
예 를 들 어 인터페이스 유형 을 MagicUserType 이 라 고 가정 하면 이 인 터 페 이 스 를 실현 하 는 구체 적 인 유형 이 있 습 니 다. Wizard, Witch, Necomancer.TypeResolver (형식 해석 기) 는 실행 할 때 데이터 의 구체 적 인 유형 (Type) 을 식별 하여 어떤 DataFetcher 와 필드 를 호출 할 지 결정 합 니 다.
        new TypeResolver() {
            @Override
            public GraphQLObjectType getType(TypeResolutionEnvironment env) {
                Object javaObject = env.getObject();
                if (javaObject instanceof Wizard) {
                    return env.getSchema().getObjectType("WizardType");
                } else if (javaObject instanceof Witch) {
                    return env.getSchema().getObjectType("WitchType");
                } else {
                    return env.getSchema().getObjectType("NecromancerType");
                }
            }
        };

SDL 로 schema 만 들 기
SDL 정의 모드 를 통 해 DataFetcher 와 TypeResolver 를 제공 해 야 합 니 다.
예 를 들 어 다음 schema 에 대한 정의: (starWarsSchema. graphqls)
    schema {
        query: QueryType
    }

    type QueryType {
        hero(episode: Episode): Character
        human(id : String) : Human
        droid(id: ID!): Droid
    }


    enum Episode {
        NEWHOPE
        EMPIRE
        JEDI
    }

    interface Character {
        id: ID!
        name: String!
        friends: [Character]
        appearsIn: [Episode]!
    }

    type Human implements Character {
        id: ID!
        name: String!
        friends: [Character]
        appearsIn: [Episode]!
        homePlanet: String
    }

    type Droid implements Character {
        id: ID!
        name: String!
        friends: [Character]
        appearsIn: [Episode]!
        primaryFunction: String
    }

이 schema 정 의 는 필드 (field) 와 형식 (type) 정 의 를 포함 하지만 '실행 시 바 인 딩' (runtime wiring) 이 필요 합 니 다. 자바 방법 에 연결 하여 실행 가능 한 schema 로 만 듭 니 다.
다음 코드 를 사용 하여 귀속 (wiring) 과정 을 완성 할 수 있 습 니 다.
    RuntimeWiring buildRuntimeWiring() {
        return RuntimeWiring.newRuntimeWiring()
                .scalar(CustomScalar)
                // this uses builder function lambda syntax
                .type("QueryType", typeWiring -> typeWiring
                        .dataFetcher("hero", new StaticDataFetcher(StarWarsData.getArtoo()))
                        .dataFetcher("human", StarWarsData.getHumanDataFetcher())
                        .dataFetcher("droid", StarWarsData.getDroidDataFetcher())
                )
                .type("Human", typeWiring -> typeWiring
                        .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())
                )
                // you can use builder syntax if you don't like the lambda syntax
                .type("Droid", typeWiring -> typeWiring
                        .dataFetcher("friends", StarWarsData.getFriendsDataFetcher())
                )
                // or full builder syntax if that takes your fancy
                .type(
                        newTypeWiring("Character")
                                .typeResolver(StarWarsData.getCharacterTypeResolver())
                                .build()
                )
                .build();
    }

마지막 으로 schema 파일 과 '바 인 딩' (wiring) 을 결합 하여 실행 가능 한 schema 를 만들어 야 합 니 다.예 는 다음 과 같다.
        SchemaParser schemaParser = new SchemaParser();
        SchemaGenerator schemaGenerator = new SchemaGenerator();

        File schemaFile = loadSchema("starWarsSchema.graphqls");

        TypeDefinitionRegistry typeRegistry = schemaParser.parse(schemaFile);
        RuntimeWiring wiring = buildRuntimeWiring();
        GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring);

위의 build 방식 을 사용 하 는 것 외 에 TypeResolver 와 DataFetcher 도 WiringFactory 인터페이스 로 바 인 딩 을 완료 할 수 있 습 니 다.
예제 코드 는 다음 과 같다.
    RuntimeWiring buildDynamicRuntimeWiring() {
        WiringFactory dynamicWiringFactory = new WiringFactory() {
            @Override
            public boolean providesTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) {
                return getDirective(definition,"specialMarker") != null;
            }

            @Override
            public boolean providesTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) {
                return getDirective(definition,"specialMarker") != null;
            }

            @Override
            public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, InterfaceTypeDefinition definition) {
                Directive directive  = getDirective(definition,"specialMarker");
                return createTypeResolver(definition,directive);
            }

            @Override
            public TypeResolver getTypeResolver(TypeDefinitionRegistry registry, UnionTypeDefinition definition) {
                Directive directive  = getDirective(definition,"specialMarker");
                return createTypeResolver(definition,directive);
            }

            @Override
            public boolean providesDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) {
                return getDirective(definition,"dataFetcher") != null;
            }

            @Override
            public DataFetcher getDataFetcher(TypeDefinitionRegistry registry, FieldDefinition definition) {
                Directive directive = getDirective(definition, "dataFetcher");
                return createDataFetcher(definition,directive);
            }
        };
        return RuntimeWiring.newRuntimeWiring()
                .wiringFactory(dynamicWiringFactory).build();
    }

프로 그래 밍 식 구축 schema
프로 그래 밍 방식 으로 모드 를 만 들 때, 형식 을 만 들 때 DataFetcher 와 TypeResolver 를 제공 합 니 다.
예제 코드 는 다음 과 같다.
        DataFetcher fooDataFetcher = new DataFetcher() {
            @Override
            public Foo get(DataFetchingEnvironment environment) {
                // environment.getSource() is the value of the surrounding
                // object. In this case described by objectType
                Foo value = perhapsFromDatabase(); // Perhaps getting from a DB or whatever
                return value;
            }
        };

        GraphQLObjectType objectType = newObject()
                .name("ObjectType")
                .field(newFieldDefinition()
                        .name("foo")
                        .type(GraphQLString)
                )
                .build();

        GraphQLCodeRegistry codeRegistry = newCodeRegistry()
                .dataFetcher(
                        coordinates("ObjectType", "foo"),
                        fooDataFetcher)
                .build();

유형 (유형)
Graphql 형식 시스템 은 다음 과 같은 몇 가지 유형 을 지원 합 니 다.
  • Scalar
  • Object
  • Interface
  • Union
  • InputObject
  • Enum

  • Scalar
    graphql - java 는 다음 과 같은 Scalars 를 지원 합 니 다.
  • 표준 graphql scalars: GraphQLstring, GraphQLpoolean, GraphQLint, GraphQLfloat, GraphQLID
  • graph - java 확장 스칼라:
  • GraphQLLong
  • GraphQLShort
  • GraphQLByte
  • GraphQLFloat
  • GraphQLBigDecimal
  • GraphQLBigInteger

  • 확 장 된 스칼라 의 의 미 는 graphql 클 라 이언 트 에 의 해 정확하게 이해 되 지 않 을 수 있 습 니 다.예 를 들 어 자바 랭 (최대 값 263 - 1) 을 자바 스 크 립 트 숫자 (최대 값 253 - 1) 로 변환 하면 문제 가 발생 할 수 있 습 니 다. Object
    SDL 예 는 다음 과 같다.
        type SimpsonCharacter {
            name: String
            mainCharacter: Boolean
        }
    
    

    자바 예제:
        GraphQLObjectType simpsonCharacter = newObject()
        .name("SimpsonCharacter")
        .description("A Simpson character")
        .field(newFieldDefinition()
                .name("name")
                .description("The name of the character.")
                .type(GraphQLString))
        .field(newFieldDefinition()
                .name("mainCharacter")
                .description("One of the main Simpson characters?")
                .type(GraphQLBoolean))
        .build();
    
    

    Interface
    인터페이스 는 추상 적 인 유형의 정의 이다.
    SDL 예 는 다음 과 같다.
        interface ComicCharacter {
            name: String;
        }
    
    

    자바 예제:
        GraphQLInterfaceType comicCharacter = newInterface()
            .name("ComicCharacter")
            .description("An abstract comic character.")
            .field(newFieldDefinition()
                    .name("name")
                    .description("The name of the character.")
                    .type(GraphQLString))
            .build();
    
    

    Union
    SDL 예 는 다음 과 같다.
        type Cat {
            name: String;
            lives: Int;
        }
    
        type Dog {
            name: String;
            bonesOwned: int;
        }
    
        union Pet = Cat | Dog
    
    

    자바 예제:
            TypeResolver typeResolver = new TypeResolver() {
                @Override
                public GraphQLObjectType getType(TypeResolutionEnvironment env) {
                    if (env.getObject() instanceof Cat) {
                        return CatType;
                    }
                    if (env.getObject() instanceof Dog) {
                        return DogType;
                    }
                    return null;
                }
            };
            GraphQLUnionType PetType = newUnionType()
                    .name("Pet")
                    .possibleType(CatType)
                    .possibleType(DogType)
                    .build();
    
            GraphQLCodeRegistry codeRegistry = newCodeRegistry()
                    .typeResolver("Pet", typeResolver)
                    .build();
    
    

    Enum
    SDL 예제:
        enum Color {
            RED
            GREEN
            BLUE
        }
    
    

    자바 예제:
        GraphQLEnumType colorEnum = newEnum()
            .name("Color")
            .description("Supported colors.")
            .value("RED")
            .value("GREEN")
            .value("BLUE")
            .build();
    
    

    ObjectInputType
    SDL 예제:
        input Character {
            name: String
        }
    
    

    자바 예제:
        GraphQLInputObjectType inputObjectType = newInputObject()
            .name("inputObjectType")
            .field(newInputObjectField()
                    .name("field")
                    .type(GraphQLString))
            .build();
    
    

    Type References (형식 참조, 재 귀적 형식 생 성 에 사용)
    GraphQL 은 재 귀적 형식 을 지원 합 니 다. 예 를 들 어 Person 클래스 는 같은 유형의 friends 를 포함 할 수 있 습 니 다.
    이러한 유형 을 지원 하기 위해 graphql - java 는 GraphQLtype Reference 클래스 를 제공 합 니 다.
    schema 가 생 성 될 때 GraphQLtype Reference 는 실제 형식 으로 대 체 됩 니 다.
    예 를 들 면:
        GraphQLObjectType person = newObject()
                .name("Person")
                .field(newFieldDefinition()
                        .name("friends")
                        .type(GraphQLList.list(GraphQLTypeReference.typeRef("Person"))))
                .build();
    
    

    schema 가 SDL 로 만 들 면 name 재 귀적 형식 은 표시 되 지 않 아 도 됩 니 다. graphql 은 자동 으로 검 측 됩 니 다.
    Schema SDL 모듈 화
    비교적 큰 schema 파일 을 유지 하 는 것 은 가능 하지 않 습 니 다. graphql - 자바 도 두 가지 방식 을 제공 하여 schema 에 대해 모듈 화 할 수 있 습 니 다.
    첫 번 째 방법 은 여러 개의 Schema SDL 파일 을 하나의 논리 단위 로 통합 하 는 것 입 니 다. 아래 의 경우 Schema 는 여러 개의 파일 로 나 누 어 Schema 가 생 성 되 기 전에 합 칩 니 다.
        SchemaParser schemaParser = new SchemaParser();
        SchemaGenerator schemaGenerator = new SchemaGenerator();
    
        File schemaFile1 = loadSchema("starWarsSchemaPart1.graphqls");
        File schemaFile2 = loadSchema("starWarsSchemaPart2.graphqls");
        File schemaFile3 = loadSchema("starWarsSchemaPart3.graphqls");
    
        TypeDefinitionRegistry typeRegistry = new TypeDefinitionRegistry();
    
        // each registry is merged into the main registry
        typeRegistry.merge(schemaParser.parse(schemaFile1));
        typeRegistry.merge(schemaParser.parse(schemaFile2));
        typeRegistry.merge(schemaParser.parse(schemaFile3));
    
        GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, buildRuntimeWiring());
    
    

    Graphql SDL 형식 시스템 은 모듈 화 모드 에 사용 할 다른 방법 을 가지 고 있 습 니 다. 형식 확장 을 사용 하여 형식 에 추가 필드 와 인 터 페 이 스 를 추가 할 수 있 습 니 다.
    모드 파일 에서 이러한 형식 으로 시작한다 고 가정 합 니 다.
        type Human {
            id: ID!
            name: String!
        }
    
    

    시스템 의 다른 부분 은 이 형식 을 확장 하고 더 많은 필드 를 추가 할 수 있 습 니 다. 예 를 들 어:
        extend type Human implements Character {
            id: ID!
            name: String!
            friends: [Character]
            appearsIn: [Episode]!
        }
    
    

    가능 한 한 많은 확장 을 사용 할 수 있 습 니 다. 발 견 된 순서 로 합 쳐 집 니 다. 중 복 된 필드 는 하나 로 합 쳐 집 니 다.
        extend type Human {
            homePlanet: String
        }
    
    

    이상 의 여러 schema 파일 은 실행 할 때 Human 형식 으로 합 쳐 집 니 다. 다음 과 같 습 니 다.
        type Human implements Character {
            id: ID!
            name: String!
            friends: [Character]
            appearsIn: [Episode]!
            homePlanet: String
        }
    
    

    이것 은 schema 의 맨 위 에 디자인 할 때 매우 중요 합 니 다. 확장 형식 을 사용 하여 맨 위 에 있 는 schema 의 "query"에 새로운 필드 를 추가 할 수 있 습 니 다.
    팀 은 최상 위 graphql 조 회 를 위해 각자 의 모듈 기능 을 독립 적 으로 수행 할 수 있 습 니 다.
        schema {
          query: CombinedQueryFromMultipleTeams
        }
    
        type CombinedQueryFromMultipleTeams {
            createdTimestamp: String
        }
    
        # maybe the invoicing system team puts in this set of attributes
        extend type CombinedQueryFromMultipleTeams {
            invoicing: Invoicing
        }
    
        # and the billing system team puts in this set of attributes
        extend type CombinedQueryFromMultipleTeams {
            billing: Billing
        }
    
        # and so and so forth
        extend type CombinedQueryFromMultipleTeams {
            auditing: Auditing
        }
    
    

    구독 지원
    구독 은 조 회 를 허용 하고 관련 조회 의 백 엔 드 대상 이 변경 되면 업 데 이 트 된 대상 은 실시 간 으로 추 송 됩 니 다.
        subscription foo {
            # normal graphql query
        }
    
    

    좋은 웹페이지 즐겨찾기