Flutter Hasura+Firebase에서 제작한Graph QL API 사용

안녕하세요.
이 글은 Fluter advent 캘린더 다섯째 날의 글이다.
평소 취미Flutter로 애플리케이션을 개발하려고 노력한다.
이번에 그때 개인개발 백엔드Hasura를 활용해서 아주 편리하게 소개한 기사입니다.
본고는 데이터를 얻고 유형을 생성하는 방법을 설명하지만 위젯의 삽입 방법과 상태 관리 방법은 언급하지 않습니다.Hasura 및 인증에 사용된Firebase Authentication 참조Hasura+Firebase에서 GraphiQL 입문 실천.

Fluter에 GraphiQL을 추가하는 이유는 무엇입니까?


최근 선언 UI를 활용한 개발에서는 그래픽QL을 활용한 개발이 주목받고 있다.
특히 리액트Apollo 세대에서는 생태계가 상당히 완비됐다는 인상을 준다.
선언 UI를 이용한 개발에서는 복잡한 UX를 보장하기 위해 API에서 확보한 데이터 구조와 상태 관리 등을 고려할 때가 많다.
GraphiQL의 가장 큰 장점은 클라이언트가 최종적으로 가져올 데이터 구조를 결정하는 것이다
특히 과도한 초과 취득(데이터 취득)과 해석(데이터 부족으로 인한 API 요청)을 피할 수 있다.
GraphiQL의 조회에서 유형을 생성할 수 있기 때문에 안전하게 데이터를 교환할 수 있다.
또한 가져올 객체에 대한 ID캐시 메서드 정의를 정의합니다.
그럼에도 불구하고 Flutter의 클라이언트 라이브러리는 Apollo만큼 성숙하지 않기 때문에 주의해야 할 것은 캐시 장치가 없다는 것이다.
이번에 사용했어요Artemis.
집필할 때의 판본을 사용했다7.2.3-beta`
Artiemis 개인이 가장 쉽게 사용할 수 있는 질의 유형으로 생성된 구성을 나열할 수 있습니다.
캐시 캐싱 기관이 없기 때문에 필요할 때 사용ferry 등을 고려해야 한다.
Fluter GraphiQL에 대한 자세한 내용은 며칠 전 개최된Flutter Kaigi2021 발표에서 자세히 소개됐으니 꼭 보십시오.
이 자리를 빌려 감사 드립니다.

Fluter에서 GraphiQL(Hasura)을 사용하기 위한 준비


플루터에서 그래픽QL(Hasura)을 활용할 준비를 한다.
전제는 앞당겨 완성하는 것이다Hasura+Firebase에서 GraphiQL 입문 실천.

스키를 다운로드하다.


먼저 Hasura에서 모드를 다운로드합니다.
GraphiQL을 사용하여 데이터 교환을 할 때 고객은 서버가 공개한 모델 정보에 따라 조회 정보를 만들 수 있습니다.
필자는 하수라가 만든 hasura/graphqurl를 사용했다.
HASURA_GRAPHQL_ENDPONINT는 GraphiQL 서버의 단점, HASURAGRAPHQL_ADMIN_SECRET는 Hasura의 관리 토큰을 지정합니다.
하수라 이외에도 사용할 수 있으니 각각 그래피QL 서버의 인증 방법 등을 사용해 변경해 주십시오.
이번에 FlutterでGraphQLを扱う에 서류를 넣었어요.
$ npx gq $(HASURA_GRAPHQL_ENDPOINT)/v1/graphql -H "X-Hasura-Admin-Secret: $(HASURA_GRAPHQL_ADMIN_SECRET)" --introspect > lib/schema.graphql

유형 생성 설정


build_runner를 사용하여 몰드lib/schema.graphql를 생성합니다.build.yml와 합작할 때 일부 유형은 데이터와 대응하지 않기 때문에 맵을 준비해야 한다.
또한 이번Hasura에서 말한 바와 같이 금형을 생성하는 데 사용되는 조회는 queries_glob: lib/**.gql의 확장명을 전제로 한다.
개인적으로 사용하는 곳 근처에 조회 파일을 놓으면 관리와 논리적 대응이 쉬워지기 때문에 추천합니다.
파일 생성에 관해서는 패턴 파일gql을 대상으로 하지 않도록 주의해야 한다.
targets:
  $default:
    sources:
      - lib/**
      - lib/$lib$
      - $package$
      - graqhql/schema.graphql
      - test/**.dart
    builders:
      artemis:
        options:
          custom_parser_import: 'package:パッケージ名/path/to/dir/convert.dart'
          schema_mapping:
            - schema: lib/schema.graphql
              queries_glob: lib/**.gql
              output: lib/graphql/gen.dart
          scalar_mapping:
            - graphql_type: bigint
              dart_type: int
            - graphql_type: timestamptz
              dart_type: DateTime
              use_custom_parser: true
확장형에는 두 가지 방법이 있다.

유형 별칭이 필요한 경우


비긴트라면 실제 상황에서 int로 설명하면 되고 원시 유형과 대응하려면 그 유형만 쓰면 된다.lib/schema.graphqlHasura측의 유형, graphql_typeFluter측에 설명하고 싶은 유형을 기술한다.
 scalar_mapping:
   - graphql_type: bigint
     dart_type: int

사용자 정의 유형 스키마가 필요한 경우


하나의 유형의 별명일 뿐만 아니라 비추면서 논리를 넣고 싶은 것도 있다.
예를 들어 UTC 타임 스탬프(timestamptz)는 로컬 시간의 데이터를 처리하기 쉬워야 한다.
이 경우 Parer를 dart_type로 기술하고 custom_parser_import를 진짜로 설정합니다.use_custom_parser에 지정된 경로 이름은 custom_parser_import와 일치합니다.다음 예에서는 lib 以下를 지정합니다.
 custom_parser_import: 'package:パッケージ名/graphql/convert.dart'
 scalar_mapping:
   - graphql_type: timestamptz
     dart_type: DateTime
     use_custom_parser: true
lib/graphql/convert.dart의 내용은 다음과 같다.
함수 이름은 자동으로 형식 매핑에 대응합니다.
명명 규칙 자체는convert.dart이다.
// 2021-10-24T05:30:11.549928+00:00 のようなUTCでくるので変換する
DateTime fromGraphQLtimestamptzToDartDateTime(String date) =>
    DateTime.parse(date).toLocal();
필자는 용례를 생각하지 못했지만Dart의 유형을 하수라로 변환할 때 원본 코드만 보면 상반된 명명 규칙fromGraphQL{$Hasra 側の型名}ToDart{$Dart 側の型名}으로 바꿀 수 있다.
 jsonKeyAnnotation['fromJson'] =
            'fromGraphQL${graphqlTypeSafeStr.namePrintable}ToDart${dartTypeSafeStr.namePrintable}';
 jsonKeyAnnotation['toJson'] =
            'fromDart${dartTypeSafeStr.namePrintable}ToGraphQL${graphqlTypeSafeStr.namePrintable}';
https://github.com/comigor/artemis/blob/e1a213400a84dc44eb830bd90f26efe12bb2874c/lib/visitor/generator_visitor.dart#L192-L195

query 정보 설정


최종적으로 사용할 조회 정보fromDart{$dart側の型名}ToGraphQL{$Hasura側の型名}와 같은 확장자 파일에 따라 형식을 생성합니다.
예에서 기술한 .gql과items 모델에 대해 조회는 적합한 견본이기 때문에 설명하지 않습니다.

질의 준비


모드를 다운로드하면 조회가 제공됩니다.
안드로이드 스튜디오JS GraphQL라면 스타일 보정 효과가 좋아 선택할 수 있다.
query fetch_items {
    items  {
       id
       name
       created_at
       updated_at
    }
}
형식 정의에서 나온 코드 사용 예시.질의 이름에서 유형Item型을 생성합니다.
  Future<List<Item>> fetchItems() async {
    final response = await gqlClient.execute(FetchItemsQuery());
    if (response.hasErrors) {
      return [];
    }
    return response.data?.items
        .map<Item>((response) => Item.fromResponse(response))
        .toList() ?? [];
  }
물론 ID도 지정할 수 있습니다. 다음where로 축소된 조회를 준비하세요.
query fetch_item($id: bigint!) {
    items(where: {id: {_eq: $id}}) {
        id
        name
        created_at
        updated_at
    }
}
유형 정의의 코드 사용 예시 2.쿼리 이름에서 유형XXXXQuery을 생성하고 관리 파라미터XXXXQuery를 추가합니다.
    Future<Item?> fetchItem(int id) async {
    final response = await gqlClient.execute(
        FetchTimesDetailQuery(variables: FetchItemArguments(id: id)));
    if (response.hasErrors) {
      return null
    }
    final items = response.data?.items
        .map<Times>((response) => Item.fromResponse(response))
        .toList();
    return items?.first;
  }
모듈 생성과 관련해서는 Mutation과 Subscription도 동일하게 처리할 수 있다.

Fluter Hasura의 인증 설정


이것은 완성Hasura+Firebase에서 GraphiQL 입문 실천의 전제 조건이다.
기본적으로Firebase Authentication에서 JWT 영패를 받았는데, 요청할 때 쪽지에 넣으면 OK입니다.
중첩Link 구조를 통해GraphiQL의 데이터를 얻습니다.

일반적인 검색과 선별 및 사용 시 터미널 링크는 HttpLink와 WebSocketLink 두 가지를 사용하기 때문에 반드시 분할해야 합니다.
이 경우 다음 클라이언트를 먼저 정의할 수 있습니다.
인증 헤드는 큐리와 뮤테이션에 사용되는 HttpLink의 경우 AuthLink를 무는 것이 비교적 수월하게 설정된다.
필터링에 사용된 WebSocketLink의 경우 XXXArguments initPayload에서 Authorization 머리글로 설정할 수 있습니다.
ArtemisClient.fromLink(
     Link.from([
      DedupeLink(), //重複リクエスト防止
      LoggerLink(),
    ]).split(
      (request) => request.isSubscription, //終端が複数になるのでsplitでわける
      WebSocketLink(
          config: SocketClientConfig(
            autoReconnect: true,
            initialPayload: () async {
              final token = await _getToken();
              return {'headers': {
                  'Authorization': token
              }};
      })),
      AuthLink(getToken: _getToken).concat(HttpLink()),
    )
Firebase에서 영패를 얻는 것은 매우 간단하다.
  Future<String?> _getToken() async {
    final token = FirebaseAuth.instance.currentUser?.getIdToken();
    return 'Bearer $token';
  }
또한 필자는 다음과 같은 Logger용 Link를 정의하여 일률적으로 로그에 넣었다.
class LoggerLink extends Link {
  Logger logger;
  LoggerLink({required this.logger});

  
  Stream<Response> request(Request request, [NextLink? forward]) async* {
    yield* forward!(request).map((event) {
      logger.d(event);
      if (event.errors != null) {
        logger.e(event.errors);
      }
      if (event.data != null) {
        logger.i(event.data);
      }
      return event;
    });
  }
}
이상의 설정이 종료되었습니다.이렇게 하면 데이터를 얻을 수 있다.

응용 프로그램 상태 관리 정보

SocketClientConfig 등도 직접 사용 논의 가능
만약에 처리StreamBuilder한다면 저는 개인적으로 응용 프로그램에 상업 논리를 삽입하는 것이 처리하기 쉽다고 생각하기 때문에 한 층state_notifier 등을 더 사용하는 것이 좋습니다.
Hasura에서도 사용custom function하는 방법이 있어요.
백엔드를 얇게 만드는 장점을 버리기 위해서이니 논의가 필요하다.

끝말


Flutter에서 사용HasuraHasuraFirebase Authentication 합작에 대한 해설을 했다.
GraphiQL의 생태계는 React에 비해 아직 성숙하지 않지만
형 생성과 캐시 등 어느 정도 할 수 있는 일이 인상적이다.(이번에 건드린 GraphQL API현금이 없다는 게 곤란해요.)
선언한 UI와 GraphiQL은 의기투합한 것이 틀림없다. 이번 기회에 하수라와 함께 놀아보는 건 어떨까?
그럼에도 그래픽QL은 은의 총알이 아니어서 주변 인증과 N+1 등을 고려하는 사람들이 많아 적절하다고 느낀다.
그런 문제의 대부분이 배려Artemis되는 것이 좋은 제품이라고 생각합니다.
이번 인증 주위Hasura에서 데이터베이스FirebaseSupabasePostgress의 조합에 도전하고 싶습니다.HasuraFlutter의일들이가끔씩징징거리기도 하고가능하면주목해주세요.

좋은 웹페이지 즐겨찾기