Firebase Data Connect를 사용하면 Google Cloud SQL로 관리되는 PostgreSQL 인스턴스의 커넥터를 만들 수 있습니다. 이러한 커넥터는 스키마의 데이터를 사용하기 위한 쿼리와 변이의 조합입니다.
시작 가이드에서는 PostgreSQL용 영화 리뷰 앱 스키마를 소개했습니다.
또한 이 가이드에서는 변형을 비롯한 배포 가능 및 임시 관리 작업도 소개했습니다.
- 배포 가능한 변이는 정의한 API 엔드포인트로 커넥터의 클라이언트 앱에서 호출하기 위해 구현하는 변이입니다. Data Connect는 인증 및 승인을 이러한 변이에 통합하고 API를 기반으로 클라이언트 SDK를 생성합니다.
- 임시 관리 변이는 권한이 있는 환경에서 실행되어 테이블을 채우고 관리합니다. Firebase 콘솔에서, Firebase Admin SDK를 사용하는 권한이 있는 환경에서, Data Connect VS Code 확장 프로그램을 사용하는 로컬 개발 환경에서 만들고 실행할 수 있습니다.
이 가이드에서는 배포 가능한 변이를 자세히 살펴봅니다.
Data Connect 변형의 기능
Data Connect를 사용하면 PostgreSQL 데이터베이스가 제공될 때 예상되는 모든 방식으로 기본 변형을 실행할 수 있습니다.
- CRUD 작업 실행
- 트랜잭션으로 다단계 작업 관리
하지만 Data Connect의 GraphQL 확장 프로그램을 사용하면 더 빠르고 효율적인 앱을 위한 고급 변형을 구현할 수 있습니다.
- 많은 작업에서 반환된 키 스칼라를 사용하여 레코드에 대한 반복 작업을 단순화합니다.
- 서버 값을 사용하여 서버에서 제공하는 작업으로 데이터를 채웁니다.
- 다단계 변이 작업 중에 쿼리를 실행하여 데이터를 조회하면 코드 줄과 서버로의 왕복을 절약할 수 있습니다.
생성된 필드를 사용하여 변이 구현
Data Connect 작업은 스키마의 유형 및 유형 관계에 따라 자동으로 생성된 Data Connect 필드 집합을 확장합니다. 이러한 필드는 스키마를 수정할 때마다 로컬 도구에 의해 생성됩니다.
생성된 필드를 사용하여 단일 테이블에서 개별 레코드를 생성, 업데이트, 삭제하는 것부터 더 복잡한 다중 테이블 업데이트에 이르기까지 변형을 구현할 수 있습니다.스키마에 Movie
유형과 연결된 Actor
유형이 포함되어 있다고 가정합니다.
Data Connect는 movie_insert
, movie_update
, movie_delete
필드 등을 생성합니다.
movie_insert
필드를 사용한 변형
|
이 필드를 사용하여 단일 영화를 만듭니다. mutation CreateMovie($data: Movie_Data!) { movie_insert(data: $data) { key } } |
movie_update
필드를 사용한 변형
|
이 필드를 사용하여 키로 단일 영화를 업데이트합니다. mutation UpdateMovie($myKey: Movie_Key!, $data: Movie_Data!) { movie_update(key: $myKey, data: $data) { key } } |
movie_delete
필드를 사용한 변형
|
이 필드를 사용하여 키로 단일 영화를 삭제합니다. mutation DeleteMovie($myKey: Movie_Key!) { movie_delete(key: $myKey) { key } } |
변이의 필수 요소
Data Connect 변형은 Data Connect 확장 프로그램이 있는 GraphQL 변형입니다. 일반 GraphQL 변형과 마찬가지로 작업 이름과 GraphQL 변수 목록을 정의할 수 있습니다.
Data Connect는 @auth
및 @transaction
과 같은 맞춤 지시어로 GraphQL 쿼리를 확장합니다.
따라서 다음 변이에는 다음이 있습니다.
mutation
유형 정의SignUp
작업 (변형) 이름- 단일 변수
$username
작업 인수 - 단일 지시문
@auth
- 단일 필드
user_insert
mutation SignUp($username: String!) @auth(level: USER) {
user_insert(data: {
id_expr: "auth.uid"
username: $username
})
}
모든 변이 인수에는 유형 선언(예: String
와 같은 내장 유형 또는 Movie
와 같은 맞춤 스키마 정의 유형)이 필요합니다.
기본 변형 작성
데이터베이스에서 개별 레코드를 생성, 업데이트, 삭제하는 변형을 작성할 수 있습니다.
만들기
기본적인 생성 작업을 해 보겠습니다.
# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
movie_insert(data: {
title: $title
releaseYear: $releaseYear
genre: $genre
rating: $rating
})
}
# Create a movie with default values
mutation CreateMovie2 {
movie_insert(data: {
title: "Sherlock Holmes"
releaseYear: 2009
genre: "Mystery"
rating: 5
})
}
또는 upsert입니다.
# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
movie_upsert(data: {
title: $title
releaseYear: 2009
genre: "Mystery"
rating: 5
genre: "Mystery/Thriller"
})
}
업데이트 실행
업데이트를 알려드립니다. 제작자와 감독은 이러한 평균 등급이 추세에 부합하기를 바랍니다.
movie_update
필드에는 레코드를 식별하는 예상 id
인수와 이 업데이트에서 값을 설정하는 데 사용할 수 있는 data
필드가 포함됩니다.
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$rating: Int!,
$description: String!
) {
movie_update(id: $id,
data: {
genre: $genre
rating: $rating
description: $description
})
}
여러 업데이트를 실행하려면 movie_updateMany
필드를 사용하세요.
# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $rating: Int!) {
movie_updateMany(
where: { genre: { eq: $genre } },
data:
{
rating: $rating
})
}
_update
를 사용하여 증가, 감소, 추가, 앞에 추가 작업 사용
_update
및 _updateMany
변이에서 data:
의 값을 명시적으로 설정할 수 있지만, 값을 업데이트하기 위해 증가와 같은 연산자를 적용하는 것이 더 합리적인 경우가 많습니다.
이전 업데이트 예시를 수정하여 특정 영화의 등급을 늘린다고 가정해 보겠습니다. inc
연산자와 함께 rating_update
구문을 사용할 수 있습니다.
mutation UpdateMovie(
$id: UUID!,
$ratingIncrement: Int!
) {
movie_update(id: $id, data: {
rating_update: {
inc: $ratingIncrement
}
})
}
Data Connect는 필드 업데이트를 위해 다음 연산자를 지원합니다.
inc
:Int
,Int64
,Float
,Date
,Timestamp
데이터 유형을 증분합니다.dec
을 사용하여Int
,Int64
,Float
,Date
,Timestamp
데이터 유형 감소
목록의 경우 다음을 사용하여 개별 값 또는 값 목록으로 업데이트할 수도 있습니다.
add
: 벡터 목록을 제외한 목록 유형에 항목이 아직 없는 경우 항목을 추가합니다.remove
를 사용하여 벡터 목록을 제외한 목록 유형에서 항목을 모두 삭제합니다(있는 경우).append
: 벡터 목록을 제외한 목록 유형에 항목 추가prepend
: 벡터 목록을 제외한 목록 유형에 항목을 추가합니다.
삭제 실행
물론 영화 데이터를 삭제할 수 있습니다. 영화 보존 전문가들은 물리적 영화를 최대한 오랫동안 유지하고 싶어 할 것입니다.
# Delete by key
mutation DeleteMovie($id: UUID!) {
movie_delete(id: $id)
}
여기서는 _deleteMany
를 사용할 수 있습니다.
# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
movie_deleteMany(where: { rating: { le: $minRating } })
}
관계에 변형 작성
관계에서 암시적 _upsert
변형을 사용하는 방법을 확인합니다.
# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
movieMetadata_upsert(
data: { movie: { id: $movieId }, director: $director }
)
}
효율적인 변형을 위한 스키마 설계
Data Connect는 더 효율적인 변이를 작성하고 왕복 작업을 저장할 수 있는 두 가지 중요한 기능을 제공합니다.
키 스칼라는 Data Connect가 스키마의 키 필드에서 자동으로 어셈블하는 간결한 객체 식별자입니다. 주요 스칼라는 효율성에 관한 것으로, 단일 호출에서 데이터의 ID와 구조에 관한 정보를 찾을 수 있습니다. 새 레코드에 순차적 작업을 실행하고 후속 작업에 전달할 고유 식별자가 필요한 경우와 추가적인 복잡한 작업을 실행하기 위해 관계형 키에 액세스하려는 경우에 특히 유용합니다.
서버 값을 사용하면 expr
인수의 특정 서버 측 CEL 표현식에 따라 저장된 값이나 쉽게 계산할 수 있는 값을 사용하여 서버가 테이블의 필드를 동적으로 채우도록 할 수 있습니다. 예를 들어 작업 요청에 저장된 시간 updatedAt: Timestamp!
@default(expr: "request.time")
를 사용하여 필드에 액세스할 때 타임스탬프가 적용된 필드를 정의할 수 있습니다.
고급 변형 작성: field_expr
구문을 사용하여 Data Connect가 값을 제공하도록 허용
주요 스칼라 및 서버 값에서 설명한 대로 클라이언트 요청에 대한 응답으로 서버가 id
s 및 날짜와 같은 일반 필드의 값을 채우도록 스키마를 설계할 수 있습니다.
또한 클라이언트 앱에서 Data Connect request
객체로 전송된 사용자 ID와 같은 데이터를 사용할 수 있습니다.
변형을 구현할 때는 field_expr
구문을 사용하여 서버 생성 업데이트를 트리거하거나 요청에서 데이터에 액세스합니다. 예를 들어 요청에 저장된 승인 uid
을 _upsert
작업에 전달하려면 userId_expr
필드에 "auth.uid"
를 전달합니다.
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}
# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
또는 익숙한 할 일 목록 앱에서 새 할 일 목록을 만들 때 id_expr
를 전달하여 서버가 목록의 UUID를 자동 생성하도록 지시할 수 있습니다.
mutation CreateTodoListWithFirstItem(
$listName: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
}
자세한 내용은 스칼라 참조의 _Expr
스칼라를 참고하세요.
고급 변형 작성: 다단계 작업
하나의 변형에 여러 쓰기 필드 (예: 삽입)를 포함하려는 경우가 많습니다. 또한 삽입이나 업데이트를 실행하기 전에 변이 실행 중에 데이터베이스를 읽어 기존 데이터를 조회하고 확인할 수도 있습니다. 이러한 옵션은 왕복 작업을 절약하므로 비용이 절감됩니다.
Data Connect를 사용하면 다음을 지원하여 변이에서 다단계 논리를 실행할 수 있습니다.
여러 쓰기 필드
변형에 여러 읽기 필드가 있습니다 (
query
필드 키워드 사용).관계형 데이터베이스에서 익숙한 트랜잭션 지원을 제공하는
@transaction
지시문CEL 표현식을 사용하여 읽기의 콘텐츠를 평가하고 평가 결과를 기반으로 다음 작업을 실행할 수 있는
@check
지시어- 변형에 정의된 생성, 업데이트, 삭제를 진행합니다.
- 쿼리 필드의 결과를 반환합니다.
- 반환된 메시지를 사용하여 클라이언트 코드에서 적절한 로직 실행
@redact
지시어: 쿼리 필드 결과를 와이어 프로토콜 결과에서 생략할 수 있습니다.복잡한 다단계 작업에서 실행된 모든 변형과 쿼리의 누적 결과를 저장하는 CEL
response
바인딩response
바인딩에 액세스할 수 있습니다.@check
지시어에서expr:
인수를 통해- 서버 값(
field_expr
문법 사용)
@transaction
지시문
다단계 변형 지원에는 트랜잭션을 사용한 오류 처리가 포함됩니다.
@transaction
지시어는 단일 쓰기 필드 (예: _insert
또는 _update
) 또는 여러 쓰기 필드가 있는 변형이 항상 데이터베이스 트랜잭션에서 실행되도록 강제합니다.
@transaction
가 없는 변형은 각 루트 필드를 순서대로 하나씩 실행합니다. 이 작업은 오류를 부분 필드 오류로 표시하지만 후속 실행의 영향은 표시하지 않습니다.@transaction
가 있는 변이는 완전히 성공하거나 완전히 실패합니다. 트랜잭션 내 필드 중 하나라도 실패하면 전체 트랜잭션이 롤백됩니다.
@check
및 @redact
지시어
@check
지시어는 지정된 필드가 쿼리 결과에 있는지 확인합니다. 필드 값을 테스트하는 데 Common Expression Language (CEL) 표현식이 사용됩니다. 지시문의 기본 동작은 값이 null
또는 []
(빈 목록)인 노드를 확인하고 거부하는 것입니다.
@redact
지시문은 클라이언트의 응답 일부를 수정합니다. 수정된 필드는 부작용 (데이터 변경 및 @check
포함)에 대해 계속 평가되며 결과는 CEL 표현식의 후속 단계에서 계속 사용할 수 있습니다.
@check
, @check(message:)
, @redact
사용
@check
및 @redact
의 주요 용도는 관련 데이터를 조회하여 특정 작업의 승인 여부를 결정하는 것입니다. 조회는 로직에서 사용되지만 클라이언트에서는 숨겨집니다. 쿼리는 클라이언트 코드에서 올바르게 처리하는 데 유용한 메시지를 반환할 수 있습니다.
예를 들어 다음 쿼리 필드는 요청자에게 영화를 수정할 수 있는 사용자를 볼 수 있는 적절한 '관리자' 역할이 있는지 확인합니다.
query GetMovieEditors($movieId: UUID!) @auth(level: USER) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
승인 확인의 @check
및 @redact
지시문에 대해 자세히 알아보려면 승인 데이터 조회에 관한 토론을 참고하세요.
@check
을 사용하여 키 확인
_update
과 같은 일부 변이 필드는 지정된 키가 있는 레코드가 없는 경우 작동하지 않을 수 있습니다. 마찬가지로 조회에서 null 또는 빈 목록이 반환될 수 있습니다. 이는 오류로 간주되지 않으므로 롤백이 트리거되지 않습니다.
이러한 결과를 방지하려면 @check
지시어를 사용하여 키를 찾을 수 있는지 테스트하세요.
# Delete by key, error if not found
mutation MustDeleteMovie($id: UUID!) @transaction {
movie_delete(id: $id) @check(expr: "this != null", message: "Movie not found, therefore nothing is deleted")
}
response
바인딩을 사용하여 다단계 변형 연결
관련 레코드(예: 새 Movie
및 연결된 MovieMetadata
항목)를 만드는 기본 접근 방식은 다음과 같습니다.
Movie
에 대한_insert
변형 호출- 생성된 영화의 반환된 키를 저장합니다.
- 그런 다음 두 번째
_insert
변형을 호출하여MovieMetadata
레코드를 만듭니다.
하지만 Data Connect를 사용하면 두 번째 _insert
에서 첫 번째 _insert
의 결과에 액세스하여 일반적인 이 사례를 단일 다단계 작업으로 처리할 수 있습니다.
성공적인 영화 리뷰 앱을 만드는 것은 많은 노력이 필요합니다. 새 예시로 할 일 목록을 추적해 보겠습니다.
response
를 사용하여 서버 값으로 필드 설정
다음 할 일 목록 변이에서
response
바인딩은 현재 필드 이전의 모든 최상위 수준 변이 필드를 포함하는 지금까지의 부분 응답 객체를 나타냅니다.id
(키) 필드를 반환하는 초기todoList_insert
작업의 결과는 나중에response.todoList_insert.id
에서 액세스하여 새 할 일 항목을 즉시 삽입할 수 있습니다.
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1:
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
response
를 사용하여 @check
를 사용하는 필드 유효성 검사
response
은 @check(expr: "...")
에서도 사용할 수 있으므로 이를 사용하여 훨씬 더 복잡한 서버 측 로직을 빌드할 수 있습니다. 변이의 query { … }
단계와 결합하면 추가 클라이언트-서버 왕복 없이 훨씬 더 많은 작업을 할 수 있습니다.
다음 예시에서 @check
는 항상 연결된 단계 후에 실행되므로 @check
가 이미 response.query
에 액세스할 수 있습니다.
mutation CreateTodoInNamedList(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1: Look up List.id by its name
query
@check(expr: "response.query.todoLists.size() > 0", message: "No such TodoList with the name!")
@check(expr: "response.query.todoLists.size() < 2", message: "Ambiguous listName!") {
todoLists(where: { name: $listName }) {
id
}
}
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoLists[0].id" # <-- Now we have the parent list ID to insert to
content: $itemContent,
})
}
response
바인딩에 대한 자세한 내용은 CEL 참조를 확인하세요.
@transaction
및 query @check
으로 중단된 작업 이해하기
다단계 변형에서 오류가 발생할 수 있습니다.
- 데이터베이스 작업이 실패할 수 있습니다.
@check
논리를 쿼리하면 작업이 종료될 수 있습니다.
Data Connect에서는 다단계 변형과 함께 @transaction
지시어를 사용할 것을 권장합니다. 이렇게 하면 클라이언트 코드에서 더 쉽게 처리할 수 있는 일관된 데이터베이스와 변이 결과가 생성됩니다.
- 첫 번째 오류 또는 실패한
@check
에서 작업이 종료되므로 후속 필드의 실행이나 CEL 평가를 관리할 필요가 없습니다. - 롤백은 데이터베이스 오류 또는
@check
로직에 대한 응답으로 실행되어 일관된 데이터베이스 상태를 생성합니다. - 롤백 오류는 항상 클라이언트 코드에 반환됩니다.
@transaction
를 사용하지 않는 사용 사례도 있을 수 있습니다. 예를 들어 처리량, 확장성 또는 가용성이 더 필요한 경우 eventual consistency를 선택할 수 있습니다. 하지만 결과를 허용하려면 데이터베이스와 클라이언트 코드를 관리해야 합니다.
- 데이터베이스 작업으로 인해 한 필드가 실패하면 후속 필드가 계속 실행됩니다. 하지만 실패한
@check
는 여전히 전체 작업을 종료합니다. - 롤백이 실행되지 않습니다. 즉, 일부 업데이트는 성공하고 일부 업데이트는 실패한 혼합 데이터베이스 상태가 됩니다.
@check
로직에서 이전 단계의 읽기 또는 쓰기 결과를 사용하는 경우@check
를 사용한 작업의 결과가 더 일관되지 않을 수 있습니다.- 클라이언트 코드에 반환되는 결과에는 처리해야 하는 성공 및 실패 응답이 더 복잡하게 혼합되어 있습니다.
Data Connect 변형 지시어
유형과 테이블을 정의하는 데 사용하는 지시어 외에도 Data Connect는 작업의 동작을 보강하기 위한 @auth
, @check
, @redact
, @transaction
지시어를 제공합니다.
지시문 | 적용 대상 | 설명 |
---|---|---|
@auth |
쿼리 및 변형 | 쿼리 또는 변이의 승인 정책을 정의합니다. 승인 및 증명 가이드를 참고하세요. |
@check |
다단계 작업의 query 필드 |
지정된 필드가 쿼리 결과에 있는지 확인합니다. 필드 값을 테스트하는 데 Common Expression Language (CEL) 표현식이 사용됩니다. 다단계 작업을 참고하세요. |
@redact |
쿼리 | 클라이언트의 응답 일부를 수정합니다. 다단계 작업을 참고하세요. |
@transaction |
변형 | 변형이 항상 데이터베이스 트랜잭션에서 실행되도록 강제합니다. 다단계 작업을 참고하세요. |
다음 단계
관심 있을 만한 항목:
- AI 지원 도구를 사용하여 앱의 변이 생성
- 승인 가이드에 따라 변이 승인
- 웹, iOS, Android, Flutter용 클라이언트 코드에서 변이를 호출합니다.
- 변형을 사용하여 대량 데이터 작업 실행