Java의 GraphQL 또는 gRPC

57621 단어 graphqlgrpchelidonjava
이 모든 문장은 나의 저장소에서 찾을 수 있다

주파포 / 헬리콥터


GraphQL 및 gRPC 근처 실험실에서 Helidon과 협력


본고는 자바로 이루어진GraphQL과 gRPC를 소개한다.
같은 용례에서, 나는 당신에게 이 협의들을 어떻게 공개하고 실현하는지 보여줄 것입니다.
나는 간단한 용례를 사용하지만, 단지 하나의 용례만 사용하는 것은 아니다.네, 시계 두 개, 일대일 관계입니다.
본문을 쓰기 위해 Helidon를 사용했습니다.
왜 Helidon이야?왜 안 해...사실대로 말하자면, 이 프레임워크는 이러한 협의를 실현할 가능성을 제공했기 때문이다(물론, 나에게 있어서 이 프레임워크를 발견했다;-)

카탈로그

  • About Helidon

  • Use case
  • Definition
  • Helidon DB Client
  • Init Project

  • GraphQL
  • Schema
  • Maven
  • Implementation
  • Test

  • gRPC
  • Protocol buffers
  • Maven
  • Implementation
  • Test
  • Conclusion
  • Helidon 정보


    Helidon는 자바 프레임워크로 두 가지 버전이 있다.
  • Helidon SE: 반응성 마이크로 프레임
  • 작은 발자국
  • 기능성 스타일
  • 단순 투명
  • GraalVM 로컬 이미지
  • More information here
  • Helidon MP: 마이크로파일 1개
  • MP 3.3
  • 지원
  • 작은 설치 공간
  • 프레젠테이션 스타일
  • 의존 주입
  • CDI、JAX-RS、JSON-P/B
  • More information here
  • 이 두 버전에서Helidon은 GraphQL이나 gRPC의 실현에 관한 많은 도구를 제공했다. (이것은 본고가 그것을 사용하는 좋은 이유이다.)
    반응 흐름, 반응 메시지 또는 미리 정의된 건강 검사나 지표 등 다른 가능성도 많다.
    또한 docker나 GraalVM을 사용하여 Kubernetes 배치를 구축하고 사용할 수 있는 편리함을 제공합니다.
    그래서 재미를 위해 시도해 봤는데, 왜 당신의 프로젝트를 위해 하지 않았는지;-)

    용례


    정의


    단지 간단한 용례일 뿐이다. 주소가 =>address인 사람은 본문의 다른 표에 있다.
    그래서 우리는 다음과 같은 것이 있다.

    Helidon DB 클라이언트


    데이터베이스와 나의 용례에 대해 나는 H2 메모리 데이터베이스와Helidon DB-Client를 사용했다.
    Helidon DB Client는access 데이터베이스의 반응 API입니다.JDBC 드라이버(H2, Oracle, MySQL 등)를 사용하여 액세스 가능Mongodb와 직접 합작하거나
    본문에서 나는 JDBC를 사용했다.그래서 나는 이러한 의존항을 추가했다.
         <dependency>
             <groupId>io.helidon.dbclient</groupId> 
             <artifactId>helidon-dbclient</artifactId>
         </dependency>
         <dependency>
             <groupId>io.helidon.dbclient</groupId> 
             <artifactId>helidon-dbclient-jdbc</artifactId>
         </dependency>
    
    모든 데이터베이스 구현here in this maven module
    여기에는 resources의 두 가지 중요한 파일이 포함되어 있습니다.

  • db.yaml: h2 데이터베이스
  • 구성 포함

  • statements.yaml: 테이블 생성이나 시퀀스와 같은 모든 문을 포함합니다.
  • Init 프로젝트


    사용documentation의 원형
    mvn -U archetype:generate -DinteractiveMode=false \
        -DarchetypeGroupId=io.helidon.archetypes \
        -DarchetypeArtifactId=helidon-quickstart-se \
        -DarchetypeVersion=2.2.1 \
        -DgroupId=fr.jufab \
        -DartifactId=graphql-helidon \
        -Dpackage=fr.jufab.graphql
    

    mvn -U archetype:generate -DinteractiveMode=false \
        -DarchetypeGroupId=io.helidon.archetypes \
        -DarchetypeArtifactId=helidon-quickstart-se \
        -DarchetypeVersion=2.2.1 \
        -DgroupId=fr.jufab \
        -DartifactId=grpc-helidon \
        -Dpackage=fr.jufab.grpc
    
    프로젝트를 3개의 마벤트 모듈로 변환하고GraalVM이나 Dockerbuilder에서 다시 사용할 수 있는graphQL이나 gRPC 모듈의 데이터베이스를 삭제했습니다.
    또는 Helidon cli를 사용하여 프로젝트를 관리할 수 있습니다.
    https://helidon.io/docs/latest/#/about/05_cli

    GraphQL


    이제 GraphQL에 대해 이야기해 봅시다.
    GraphQL은 단일 엔드포인트에서 실행되는 쿼리 언어입니다.JSON 언어를 사용합니다.이것은 패턴을 사용하여 정의를 하고 효과적인 속성, 조작 등을 설명한다.
    GraphQL은 1개specification

    패턴


    GraphQL을 정의하려면 다음 정보가 포함된 모드를 사용해야 합니다.
  • 대상: 대상 응답의 구성
  • 조회: 요청 대상이나 그룹 대상의 조회.
  • 돌연변이: 저장/수정 대상.
  • 구독: 웹소켓
  • 으로 양방향 통신 채널 구축
    용례에 대해 모드available here는:
    # Objects
    type Person {
        id: ID!
        firstname: String!
        lastname: String!
        age: Int
        gender: Gender!
        address: Address
    }
    
    enum Gender {
        WOMAN,
        MAN
    }
    
    type Address {
        id: ID!
        street: String!
        zipCode: String!
        city: String!
    }
    # Query
    type Query {
        personById(id: ID!): Person
        personsByFirstName(firstname: String!): [Person]
        persons:[Person]
    }
    # Mutation
    type Mutation {
        createPersonWithAddress(firstname: String!, lastname: String!, age: Int, gender: Gender, street: String!, zipCode: String!, city: String!):Person
        createPerson(firstname: String!, lastname: String!, age: Int, gender: Gender, idAddress: ID!):Person
        createAddress(street: String!, zipCode: String!, city: String!): Address
    }
    

    마문


    helidon SE에는 GraphQL을 helidon GraphQL 라이브러리와 함께 사용할 수 있는 시설이 있다.
    More information about this integration in the documentation
    현재로서는 이 기능은 실험적이다...그러나 이 항목에 적용됩니다.
    프로젝트에GraphQL을 삽입하기 위해 pom.xml 파일에 의존항을 추가했습니다
    <dependency>
      <groupId>io.helidon.graphql</groupId>
      <artifactId>helidon-graphql-server</artifactId>
    </dependency>
    
    이 의존항은 사용GraphQL java version 15.0.

    구현


    서버


    GraphQL은 웹 서버에 등록해야 합니다.
    Main class에 등록되어 있습니다.
    WebServer server = WebServer.builder()
            .routing(Routing.builder()
                .register(health)                   // Health at "/health"
                .register(MetricsSupport.create())  // Metrics at "/metrics"
                .register(GraphQlSupport.create(buildSchema(dbClient)))
                .build())
            .config(config.get("server"))
            .build();
    
    바로 이 말입니다.
    register(GraphQlSupport.create(buildSchema(dbClient)))
    
    GraphQlSupport 클래스는 GraphQLSchema를 사용합니다.메서드buildSchema()는 구성된 GraphQLSchema를 생성합니다.
    private static GraphQLSchema buildSchema(DbClient dbClient) {
        SchemaParser schemaParser = new SchemaParser();
        Resource schemaResource = Resource.create(PERSON_GRAPHQLS);
        TypeDefinitionRegistry typeDefinitionRegistry =
            schemaParser.parse(schemaResource.string(StandardCharsets.UTF_8));
        SchemaGenerator schemaGenerator = new SchemaGenerator();
        return schemaGenerator.makeExecutableSchema(typeDefinitionRegistry,
            buildRuntimeWiring(dbClient));
      }
    
    요구 사항:
  • 모드:person.graphqls
  • 해석기: 실례화 typeDefinitionRegistry
  • 실행 시 연결: 데이터를 데이터fetcher에 연결
  • 방법buildRuntimeWiring은 대상(개인, 주소)을 데이터fetcher와 연결합니다.
    private static RuntimeWiring buildRuntimeWiring(DbClient dbClient) {
      AddressRepository addressRepository = new AddressRepository(dbClient);
      AddressDataFetcher addressDataFetcher = new AddressDataFetcher(addressRepository);
      PersonRepository personRepository = new PersonRepository(dbClient);
      PersonDataFetcher personDataFetcher = new PersonDataFetcher(personRepository);
      return RuntimeWiring.newRuntimeWiring()
        .type(TypeRuntimeWiring.newTypeWiring("Query")
          .dataFetcher("persons", personDataFetcher.getPersons()))
        .type(TypeRuntimeWiring.newTypeWiring("Query")
          .dataFetcher("personById", personDataFetcher.getPersonById()))
        .type(TypeRuntimeWiring.newTypeWiring("Query")
         .dataFetcher("personsByFirstName", personDataFetcher.getPersonsByFirstName()))
        .type(TypeRuntimeWiring.newTypeWiring("Person")
         .dataFetcher("address", addressDataFetcher.getAddressById()))
        .type(TypeRuntimeWiring.newTypeWiring("Mutation")
         .dataFetcher("createPersonWithAddress", personDataFetcher.createPersonWithAddress()))
        .type(TypeRuntimeWiring.newTypeWiring("Mutation").dataFetcher("createAddress",
          addressDataFetcher.createAddress()))
        .build();
    }
    
    이 방법에는 모든 조회나 변이가 있는데, 그것들은 데이터 취득 프로그램과 연결되어 있다

    데이터 취득 프로그램


    모든 객체가 DataFetcher 객체와 연관됩니다.DataFetcher는 질의할 객체를 로드하거나 수정할 객체를 저장합니다.
    작동 방식:
    DataFetchingEnvironment 객체를 사용하여 DataFetcher를 정의합니다.이 대상에는 가져올 매개 변수나 필드가 모두 포함되어 있습니다.
    이렇게 (PersonDataFetcher:
    // To get all Persons... no arguments
    public DataFetcher<List<Person>> getPersons() {
        return environment -> personRepository.getPersons().collectList().get();
    }
    //To get all by FirstName
    public DataFetcher<List<Person>> getPersonsByFirstName() {
        return environment -> personRepository.getPersonsByFirstName(environment.getArgument("firstname")).collectList().get();
    }
    // Or to create a person
    public DataFetcher<Person> createPersonWithAddress() {
        return environment -> this.personRepository.createPerson(
            new Person(environment.getArgument("firstname"), environment.getArgument("lastname"),
              environment.getArgument("age"),
              new Address(environment.getArgument("street"), environment.getArgument("zipCode"),
                environment.getArgument("city")),
              Gender.valueOf(environment.getArgument("gender")))).get();
    }
    
    DataFetching=>https://www.graphql-java.com/documentation/v16/data-fetching/에 대한 자세한 내용

    테스트


    테스트 자원에 대해 insomnia를 사용합니다.
    이러한 GraphQL 요청에 액세스할 수 있습니다.

    모드 정보 보기,

    그리고 몇 가지 요구를 제기했다.

    GraphQL은 그렇습니다...

    gRPC


    gRPC는 웹 서비스를 구축하는 데 도움을 줍니다.이 항목은 다국어이지만 Java 항목이므로...:)
    서비스를 정의하고 설명하기 위해서 gRPC는 간단한 정의 파일을 사용하고 프로토콜 버퍼 형식을 사용합니다.
    자세한 내용: https://grpc.io/

    프로토콜 버퍼


    gRPC 사용 프로토콜 버퍼: https://developers.google.com/protocol-buffers
    프로토콜 버퍼는 구조화된 데이터를 서열화하는 데 사용되는 언어이다.
    각 언어에 대해 자바의'package'또는 Objective-C의'objc class prefix'를 생성 클래스의 접두사로 정의할 수 있습니다.
    이 실험에서 나는 문법 버전'proto3'을 사용했다
    Protobuf 파일에는 다음이 포함됩니다.
  • 메시지: 개체 데이터
  • 열거: 정의 열거
  • 서비스: 데이터를 조회, 수정 또는 저장하는 서비스
  • 프로토 파일available here에 대한 정의가 있습니다.
    syntax = "proto3";
    option java_package = "fr.jufab.grpc.proto";
    option java_multiple_files = true;
    option java_generic_services = true;
    option java_outer_classname = "Helidon";
    
    enum Gender {
      WOMAN = 0;
      MAN = 1;
    }
    
    message Person {
      int32 id = 1;
      string firstname = 2;
      string lastname = 3;
      int32 age = 4;
      Gender gender = 5;
      Address address = 6;
    }
    
    message Address {
      int32 id = 1;
      string street = 2;
      string zipCode = 3;
      string city = 4;
    }
    
    message Persons {
      repeated Person persons=1;
    }
    
    message QueryPerson {
      int32 id=1;
      string firstname=2;
    }
    
    message PersonWithAddressToSave {
      string firstname = 1;
      string lastname = 2;
      int32 age = 3;
      Gender gender = 4;
      string street = 5;
      string zipCode = 6;
      string city = 7;
    }
    
    message PersonToSave{
      string firstname = 1;
      string lastname = 2;
      int32 age = 3;
      Gender gender = 4;
      int32 idAddress = 5;
    }
    
    message AddressToSave{
      string street = 1;
      string zipCode = 2;
      string city = 3;
    }
    
    message QueryAddress {
      int32 id = 1;
    }
    
    service PersonService {
      rpc persons(QueryPerson) returns (Persons);
      rpc personById(QueryPerson) returns (Person);
      rpc personsByFirstName(QueryPerson) returns (Persons);
    
      rpc createPersonWithAddress(PersonWithAddressToSave) returns (Person);
      rpc createPerson(PersonToSave) returns (Person);
    }
    
    service AddressService {
      rpc createAddress(AddressToSave) returns (Address);
      rpc addressById(QueryAddress) returns (Address);
    }
    
    

    마문


    Helidon SE는 gRPC 서버를 배포하기 위한 maven 의존 항목을 제공합니다.
    More information about this integration in the documentation
    GraphQL과 마찬가지로 gRPC 기능도 현재 실험적이다...그러나 이 항목에 적용됩니다.
    프로젝트에 gRPC를 삽입하기 위해 pom.xml에 의존항을 추가했습니다
    <dependency>
        <groupId>io.helidon.grpc</groupId>
        <artifactId>helidon-grpc-server</artifactId>
    </dependency>
    
    하지만 gRPC와protobuf를 사용하기에는 부족합니다...
    특수한 마ven 플러그인을 사용하여protobuf 파일에서 데이터를 생성해야 합니다.이 플러그인은 프로토콜 버퍼 컴파일러를 사용합니다.
    이 프로젝트에서 클래스를 생성하기 위해 pom.xml에 마벤트 정의가 있습니다.
    <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.6.1</version>
        <configuration>
            <protocArtifact>com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}</protocArtifact>
            <pluginId>grpc-java</pluginId>
            <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}</pluginArtifact>
        </configuration>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>compile-custom</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
    
    이 플러그인에 대한 더 많은 정보 https://www.xolstice.org/protobuf-maven-plugin/
    모든 클래스는 생성된 소스에서 생성됩니다.

    구현


    서버


    Helidon은 gRPC 서버를 시작하기 위해 특정 서버를 제공합니다.
    이렇게 Grpc 서버를 시작해야 합니다.
    GrpcServer grpcServer = GrpcServer
            .create(GrpcServerConfiguration.create(config.get("grpcserver")),GrpcRouting.builder()
                .register(buildPersonServiceGrpc(dbClient)) //See after for this
                .register(buildAddressServiceGrpc(dbClient)) //See after for this
                .build())
            .start()
            .toCompletableFuture()
            .get(10, TimeUnit.SECONDS);
    
    기본적으로 포트는 1408이지만 다음과 같이 yaml에서 다시 정의할 수 있습니다.
    grpcserver:
      port: 3333
    
    You can see example here

    서비스


    "Person Service Grpc"또는 "Address Service Grpc"로 등록된 서비스는 서버에서 볼 수 있습니다.
    2가지 서비스 사용 가능herehere
    이 서비스들은 Protobuf가 생성한 클래스가 제공하는 서비스를 실현합니다.따라서'Person Grpc 서비스'에서 이 클래스는'Person Service Grpc.person 서비스 inmplbase'를 실현했다.
    기본적으로, 이 클래스 'Person Service Grpc' 를 볼 수 없습니다. 프로토콜 파일로 클래스를 만들어야 하기 때문입니다.왜 제 가방은 "fr.jufab.grpc.proto"에 있습니까?protobuf에서 옵션을 사용했기 때문입니다.
    option java_package = "fr.jufab.grpc.proto";
    
    예를 들어 Person Service GRPC는 protobuf에 정의된 모든 방법을 제공합니다.
    protbuf의 서비스에 유의하십시오.
    service PersonService {
      rpc persons(QueryPerson) returns (Persons);
      rpc personById(QueryPerson) returns (Person);
      rpc personsByFirstName(QueryPerson) returns (Persons);
    
      rpc createPersonWithAddress(PersonWithAddressToSave) returns (Person);
      rpc createPerson(PersonToSave) returns (Person);
    }
    
    PersonService GRPC는 다음과 같은 기능을 제공합니다.
    public static abstract class PersonServiceImplBase implements io.grpc.BindableService {
    
      /**
       */
      public void persons(fr.jufab.grpc.proto.QueryPerson request,
              io.grpc.stub.StreamObserver<fr.jufab.grpc.proto.Persons> responseObserver) {
        asyncUnimplementedUnaryCall(METHOD_PERSONS, responseObserver);
      }
    
      /**
       */
      public void personById(fr.jufab.grpc.proto.QueryPerson request,
              io.grpc.stub.StreamObserver<fr.jufab.grpc.proto.Person> responseObserver) {
        asyncUnimplementedUnaryCall(METHOD_PERSON_BY_ID, responseObserver);
      }
    
      /**
       */
      public void personsByFirstName(fr.jufab.grpc.proto.QueryPerson request,
              io.grpc.stub.StreamObserver<fr.jufab.grpc.proto.Persons> responseObserver) {
        asyncUnimplementedUnaryCall(METHOD_PERSONS_BY_FIRST_NAME, responseObserver);
      }
    
      /**
       */
      public void createPersonWithAddress(fr.jufab.grpc.proto.PersonWithAddressToSave request,
              io.grpc.stub.StreamObserver<fr.jufab.grpc.proto.Person> responseObserver) {
        asyncUnimplementedUnaryCall(METHOD_CREATE_PERSON_WITH_ADDRESS, responseObserver);
      }
    
      /**
       */
      public void createPerson(fr.jufab.grpc.proto.PersonToSave request,
              io.grpc.stub.StreamObserver<fr.jufab.grpc.proto.Person> responseObserver) {
        asyncUnimplementedUnaryCall(METHOD_CREATE_PERSON, responseObserver);
      }
    }
    
    이제 메모리 라이브러리나 데이터베이스 접근만으로 이 방법을 실현할 수 있다.
    PersonGrpcService 중의'persons'방법에 대해 나는 이렇게 실현했다.
    @Override public void persons(QueryPerson request,
          StreamObserver<fr.jufab.grpc.proto.Persons> responseObserver) {
        try {
          complete(responseObserver, buildPersonsGrpc(personRepository.getPersons()
              .collectList()
              .get()));
        } catch (InterruptedException e) {
          LOGGER.log(Level.SEVERE, "Error", e);
        } catch (ExecutionException e) {
          LOGGER.log(Level.SEVERE, "Error", e);
        }
      }
    
    PersonGrpcServiceAddressGrpcService에서 모든 구현을 확인할 수 있습니다.

    테스트


    gRPC 서비스를 테스트하기 위해 저도 사용했습니다insomnia.
    당신은 이런 gRPC 서비스에 접근할 수 있습니다.

    protobuf 파일을 불러오기,

    URL을 추가한 후 테스트할 서비스를 선택하고,

    그것을 사용하라.

    이것이 바로 gRPC다.

    결론


    GraphQL과 gRPC는 같은 방법을 제공합니다. 모드를 사용하고 설명에서 자원을 생성합니다.
    GraphQL은 패턴 정의가 있는 HTTP 프로토콜입니다.따라서 HTTP 요청을 수락한 모든 언어로 이 리소스에 액세스할 수 있습니다.
    gRPC는 그의 프로토콜(HTTP/2)을 통해 통신을 하고 이 프로토콜에서 서비스를 생성해야 합니다.
    내가 보기엔
  • GraphQL은 외부 전시에 더욱 적합할 수 있다. 예를 들어 이동, 오픈 API 등이다. 물론 다른 상황도 있다.
  • gRPC는 내부 통신에 더욱 적합할 수 있다. 예를 들어 클라우드, 정의된 클라이언트, K8s 집단, 정보 시스템에서...
  • 물론, 이것은 너의 사용에 달려 있다.아마도 이 문장은 네가 선택하는 것을 도울 수 있을 것이다.

    좋은 웹페이지 즐겨찾기