기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.
에서 Aurora Serverless v2 사용 AWS AppSync
를 사용하여 GraphQL API를 Aurora Serverless 데이터베이스에 연결합니다 AWS AppSync. 이 통합을 통해 GraphQL 쿼리, 변형 및 구독을 통해 SQL 문을 실행할 수 있으므로 관계형 데이터와 유연하게 상호 작용할 수 있습니다.
참고
이 자습서에서는 US-EAST-1
리전을 사용합니다.
이점
GraphQL과 관계형 데이터베이스 간의 원활한 통합
GraphQL 인터페이스를 통해 SQL 작업을 수행할 수 있는 기능
Aurora Serverless v2를 사용한 서버리스 확장성
AWS Secrets Manager를 통한 보안 데이터 액세스
입력 삭제를 통한 SQL 주입 방지
필터링 및 범위 작업을 포함한 유연한 쿼리 기능
일반 사용 사례
관계형 데이터 요구 사항을 사용하여 확장 가능한 애플리케이션 구축
GraphQL 유연성과 SQL 데이터베이스 기능이 모두 필요한 APIs 생성
GraphQL 변형 및 쿼리를 통한 데이터 작업 관리
보안 데이터베이스 액세스 패턴 구현
이 자습서에서는 다음을 학습합니다.
Aurora Serverless v2 클러스터 설정
데이터 API 기능 활성화
데이터베이스 구조 생성 및 구성
데이터베이스 작업에 대한 GraphQL 스키마 정의
쿼리 및 변형에 대한 해석기 구현
적절한 입력 삭제를 통해 데이터 액세스 보호
GraphQL 인터페이스를 통해 다양한 데이터베이스 작업 실행
주제
데이터베이스 클러스터 설정
Amazon RDS 데이터 소스를에 추가 AWS AppSync하기 전에 먼저 Aurora Serverless v2 클러스터에서 데이터 API를 활성화하고 를 사용하여 보안 암호를 구성해야 합니다AWS Secrets Manager. AWS CLI다음을 사용하여 Aurora Serverless v2 클러스터를 생성할 수 있습니다.
aws rds create-db-cluster \ --db-cluster-identifier appsync-tutorial \ --engine aurora-mysql \ --engine-version 8.0 \ --serverless-v2-scaling-configuration MinCapacity=0,MaxCapacity=1 \ --master-username USERNAME \ --master-user-password COMPLEX_PASSWORD \ --enable-http-endpoint
그러면 클러스터에 대한 ARN이 반환됩니다.
클러스터를 생성한 후 다음 명령을 사용하여 Aurora Serverless v2 인스턴스를 추가해야 합니다.
aws rds create-db-instance \ --db-cluster-identifier appsync-tutorial \ --db-instance-identifier appsync-tutorial-instance-1 \ --db-instance-class db.serverless \ --engine aurora-mysql
참고
이러한 엔드포인트를 활성화하는 데 시간이 걸립니다. 클러스터의 연결 및 보안 탭에 있는 Amazon RDS 콘솔에서 상태를 확인할 수 있습니다. 다음 AWS CLI 명령을 사용하여 클러스터의 상태를 확인할 수도 있습니다.
aws rds describe-db-clusters \ --db-cluster-identifier appsync-tutorial \ --query "DBClusters[0].Status"
AWS Secrets Manager 콘솔을 사용하거나 이전 단계의 USERNAME
및를 AWS CLI 사용하여 다음과 같은 입력 파일을 사용하여 보안 암호를 생성할 수 COMPLEX_PASSWORD
있습니다.
{ "username": "USERNAME", "password": "COMPLEX_PASSWORD" }
이를 파라미터로 AWS CLI에 전달합니다.
aws secretsmanager create-secret --name HttpRDSSecret --secret-string file://creds.json --region us-east-1
그러면 암호에 대한 ARN이 반환됩니다.
데이터 원본을 생성할 때 AppSync 콘솔에서 나중에 사용할 수 있도록 암호화 Aurora Serverless 클러스터의 ARN을 적어 둡니다.
데이터 API 활성화
RDS 문서의 지침에 따라 클러스터에 대한 데이터 API를 활성화할 수 있습니다. AppSync 데이터 소스로 추가하기 전에 데이터 API를 활성화해야 합니다.
데이터베이스 및 테이블 생성
데이터 API를 활성화하면 AWS CLI에서 데이터 API가 aws
rds-data execute-statement
명령과 작동하는지 확인할 수 있습니다. 그러면 AppSync API에 추가하기 전에 Aurora Serverless 클러스터가 올바르게 구성되도록 할 수 있습니다. 먼저 다음과 같이 --sql
파라미터를 사용하여 TESTDB라는 데이터베이스를 생성합니다.
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 --sql "create DATABASE TESTDB"
오류 없이 실행되면 create table 명령을 사용하여 테이블을 추가합니다.
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:123456789000:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:123456789000:secret:testHttp2-AmNvc1" \ --region us-east-1 \ --sql "create table Pets(id varchar(200), type varchar(200), price float)" --database "TESTDB"
모든 것이 문제 없이 실행되면 AppSync API에서 해당 클러스터를 데이터 소스로 추가하는 단계로 진행할 수 있습니다.
GraphQL 스키마
Aurora Serverless 데이터 API가 테이블과 함께 실행 중이므로 변형 및 구독을 수행하기 위해 GraphQL 스키마를 생성하고 해석기를 연결해 보겠습니다. AWS AppSync 콘솔에서 새 API를 생성하고 스키마 페이지로 이동하여 다음을 입력합니다.
type Mutation { createPet(input: CreatePetInput!): Pet updatePet(input: UpdatePetInput!): Pet deletePet(input: DeletePetInput!): Pet } input CreatePetInput { type: PetType price: Float! } input UpdatePetInput { id: ID! type: PetType price: Float! } input DeletePetInput { id: ID! } type Pet { id: ID! type: PetType price: Float } enum PetType { dog cat fish bird gecko } type Query { getPet(id: ID!): Pet listPets: [Pet] listPetsByPriceRange(min: Float, max: Float): [Pet] } schema { query: Query mutation: Mutation }
스키마를 저장하고 데이터 원본 페이지로 이동해 새 데이터 원본을 생성합니다. 데이터 원본 유형으로 관계형 데이터베이스를 선택하고 기억하기 쉬운 이름을 입력합니다. 마지막 단계에서 생성한 데이터베이스 이름과 해당 데이터베이스를 생성한 클러스터 ARN을 사용합니다. 역할의 경우 AppSync에서 새 역할을 생성하거나 아래와 유사한 정책을 사용해 역할을 하나 생성하도록 할 수 있습니다.
이 정책에는 역할 액세스 권한을 부여하는 명령문이 2개 있습니다. 첫 번째 리소스는 Aurora Serverless 클러스터이고 두 번째 리소스는 AWS Secrets Manager ARN입니다. 생성을 클릭하기 전에 AppSync 데이터 소스 구성에서 두 ARN을 모두 제공해야 합니다.
이를 파라미터로에 전달합니다 AWS CLI.
aws secretsmanager create-secret \ --name HttpRDSSecret \ --secret-string file://creds.json \ --region us-east-1
그러면 암호에 대한 ARN이 반환됩니다. AWS AppSync 콘솔에서 데이터 소스를 생성할 때 나중에 사용할 수 있도록 Aurora Serverless 클러스터의 ARN과 보안 암호를 기록해 둡니다.
데이터베이스 구조 구축
데이터 API를 활성화하면 AWS CLI에서 데이터 API가 aws
rds-data execute-statement
명령과 작동하는지 확인할 수 있습니다. 이렇게 하면 AWS AppSync API에 추가하기 전에 Aurora Serverless v2 클러스터가 올바르게 구성됩니다. 먼저 다음과 같이 --sql
파라미터를 사용하여 TESTDB라는 데이터베이스를 생성합니다.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:
111122223333
:cluster:appsync-tutorial
" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333
:secret:appsync-tutorial-rds-secret
" \ --region us-east-1 \ --sql "create DATABASE TESTDB"
오류 없이 실행되는 경우 다음 테이블 생성 명령을 사용하여 테이블을 추가합니다.
aws rds-data execute-statement \ --resource-arn "arn:aws:rds:us-east-1:
111122223333
:cluster:http-endpoint-test
" \ --secret-arn "arn:aws:secretsmanager:us-east-1:111122223333
:secret:testHttp2-AmNvc1
" \ --region us-east-1 \ --sql "create table Pets(id varchar(200), type varchar(200), price float)" \ --database "TESTDB"
API 인터페이스 설계
Aurora Serverless v2 Data API가 테이블과 함께 실행되면 GraphQL 스키마를 생성하고 변형 및 구독을 수행하기 위한 해석기를 연결합니다. AWS AppSync 콘솔에서 새 API를 생성하고 콘솔의 스키마 페이지로 이동하여 다음을 입력합니다.
type Mutation { createPet(input: CreatePetInput!): Pet updatePet(input: UpdatePetInput!): Pet deletePet(input: DeletePetInput!): Pet } input CreatePetInput { type: PetType price: Float! } input UpdatePetInput { id: ID! type: PetType price: Float! } input DeletePetInput { id: ID! } type Pet { id: ID! type: PetType price: Float } enum PetType { dog cat fish bird gecko } type Query { getPet(id: ID!): Pet listPets: [Pet] listPetsByPriceRange(min: Float, max: Float): [Pet] } schema { query: Query mutation: Mutation }
스키마를 저장하고 데이터 원본 페이지로 이동해 새 데이터 원본을 생성합니다. 데이터 소스 유형으로 관계형 데이터베이스를 선택하고 친숙한 이름을 제공합니다. 마지막 단계에서 생성한 데이터베이스 이름과 해당 데이터베이스를 생성한 클러스터 ARN을 사용합니다. 역할의 경우 새 역할을 AWS AppSync 생성하거나 다음과 유사한 정책을 사용하여 역할을 생성할 수 있습니다.
이 정책에는 역할 액세스 권한을 부여하는 명령문이 2개 있습니다. 첫 번째 리소스는 Aurora Serverless v2 클러스터이고 두 번째 리소스는 AWS Secrets Manager ARN입니다. 생성을 클릭하기 전에 AWS AppSync 데이터 소스 구성에 두 ARNs을 모두 제공해야 합니다.
API를 데이터베이스 작업에 연결
이제 유효한 GraphQL 스키마와 RDS 데이터 소스가 있으므로 해석기를 스키마의 GraphQL 필드에 연결할 수 있습니다. API는 다음과 같은 기능을 제공합니다.
-
Mutation.createPet 필드를 사용하여 반려동물 생성
-
Mutation.updatePet 필드를 사용하여 반려동물 업데이트
-
Mutation.deletePet 필드를 사용하여 반려동물 삭제
-
Query.getPet 필드를 통해를 사용하여 단일 가져오기
-
Query.listPets 필드를 사용하여 모두 나열
-
Query.listPetsByPriceRange 필드를 사용하여 가격 범위의 반려 동물 나열
Mutation.createPet
AWS AppSync 콘솔의 스키마 편집기에서 오른쪽에서 용 해석기 연결을 선택합니다createPet(input: CreatePetInput!): Pet
. RDS 데이터 원본을 선택합니다. 요청 매핑 템플릿 섹션에 다음 템플릿을 추가합니다.
#set($id=$utils.autoId()) { "version": "2018-05-29", "statements": [ "insert into Pets VALUES (:ID, :TYPE, :PRICE)", "select * from Pets WHERE id = :ID" ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }
시스템은 문 배열의 순서에 따라 SQL 문을 순차적으로 실행합니다. 결과 역시 동일한 순서로 반환됩니다. 이는 변형이므로 삽입 후 선택 문을 실행하여 커밋된 값을 검색하여 GraphQL 응답 매핑 템플릿을 채웁니다.
응답 매핑 템플릿 섹션에 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
명령문에 SQL 쿼리가 2개 있기 때문에 $utils.rds.toJsonString($ctx.result))[1][0])
을 사용하여 데이터베이스에서 반환되는 매트릭스에서 두 번째 결과를 지정해야 합니다.
Mutation.updatePet
AWS AppSync 콘솔의 스키마 편집기에서에 대한 해석기 연결을 선택합니다updatePet(input: UpdatePetInput!): Pet
. RDS 데이터 소스를 선택합니다. 요청 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
{ "version": "2018-05-29", "statements": [ $util.toJson("update Pets set type=:TYPE, price=:PRICE WHERE id=:ID"), $util.toJson("select * from Pets WHERE id = :ID") ], "variableMap": { ":ID": "$ctx.args.input.id", ":TYPE": $util.toJson($ctx.args.input.type), ":PRICE": $util.toJson($ctx.args.input.price) } }
응답 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[1][0])
Mutation.deletePet
AWS AppSync 콘솔의 스키마 편집기에서에 대한 해석기 연결을 선택합니다deletePet(input: DeletePetInput!): Pet
. RDS 데이터 소스를 선택합니다. 요청 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID"), $util.toJson("delete from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.input.id" } }
응답 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.getPet
스키마에 대한 변형이 생성되었으므로 이제 세 쿼리를 연결하여 개별 항목, 목록을 가져오고 SQL 필터링을 적용하는 방법을 보여줍니다. AWS AppSync 콘솔의 스키마 편집기에서에 대한 해석기 연결을 선택합니다getPet(id: ID!): Pet
. RDS 데이터 소스를 선택합니다. 요청 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
{ "version": "2018-05-29", "statements": [ $util.toJson("select * from Pets WHERE id=:ID") ], "variableMap": { ":ID": "$ctx.args.id" } }
응답 매핑 템플릿 섹션에 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0][0])
Query.listPets
AWS AppSync 콘솔의 스키마 편집기에서 오른쪽에서 용 해석기 연결을 선택합니다getPet(id: ID!): Pet
. RDS 데이터 소스를 선택합니다. 요청 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
{ "version": "2018-05-29", "statements": [ "select * from Pets" ] }
응답 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
Query.listPetsByPriceRange
AWS AppSync 콘솔의 스키마 편집기에서 오른쪽에서 용 해석기 연결을 선택합니다getPet(id: ID!): Pet
. RDS 데이터 소스를 선택합니다. 요청 매핑 템플릿 섹션에서 다음 템플릿을 추가합니다.
{ "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.max), ":MIN": $util.toJson($ctx.args.min) } }
응답 매핑 템플릿 섹션에 다음 템플릿을 추가합니다.
$utils.toJson($utils.rds.toJsonObject($ctx.result)[0])
API를 통해 데이터 수정
SQL 문을 사용하여 모든 해석기를 구성했고 Serverless Aurora 데이터 API에 GraphQL API를 연결했으므로 변형 및 쿼리 수행을 시작할 수 있습니다. AWS AppSync 콘솔에서 쿼리 탭을 선택하고 다음을 입력하여 Pet를 생성합니다.
mutation add { createPet(input : { type:fish, price:10.0 }){ id type price } }
응답에는 다음과 같이 id, 유형 및 가격이 포함되어 있어야 합니다.
{ "data": { "createPet": { "id": "c6fedbbe-57ad-4da3-860a-ffe8d039882a", "type": "fish", "price": "10.0" } } }
updatePet 변형을 실행하여 항목을 수정할 수 있습니다.
mutation update { updatePet(input : { id: ID_PLACEHOLDER, type:bird, price:50.0 }){ id type price } }
참고로 앞서 createPet 작업에서 반환된 id를 사용했습니다. 해석기에서 $util.autoId()
를 사용했기 때문에 이 ID는 레코드에 대해 고유한 값이 될 것입니다. 레코드는 다음과 같이 유사한 방식으로 삭제할 수 있습니다.
mutation delete { deletePet(input : {id:ID_PLACEHOLDER}){ id type price } }
첫 번째 변형을 사용해 가격에 대한 값을 다르게 해 레코드를 몇 개 생성한 다음 쿼리를 실행합니다.
데이터 검색
콘솔의 쿼리 탭에서 다음 문을 사용하여 생성한 모든 레코드를 나열합니다.
query allpets { listPets { id type price } }
다음 GraphQL 쿼리를 사용하여 Query.listPetsByPriceRange에 대한 매핑 템플릿where price > :MIN and price < :MAX
에 있는 SQL WHERE 조건자를 활용합니다.
query petsByPriceRange { listPetsByPriceRange(min:1, max:11) { id type price } }
가격이 $1 이상이거나 $10 미만인 레코드만 표시되어야 합니다. 마지막으로, 다음과 같이 개별 레코드를 검색하는 쿼리를 수행할 수 있습니다.
query onePet { getPet(id:ID_PLACEHOLDER){ id type price } }
데이터 액세스 보호
SQL 삽입은 데이터베이스 애플리케이션의 보안 취약성입니다. 공격자가 사용자 입력 필드를 통해 악성 SQL 코드를 삽입할 때 발생합니다. 이렇게 하면 데이터베이스 데이터에 대한 무단 액세스를 허용할 수 있습니다. SQL 주입 공격으로부터 보호하기 variableMap
위해를 사용하여 처리하기 전에 모든 사용자 입력을 주의 깊게 검증하고 삭제하는 것이 좋습니다. 변수 맵을 사용하지 않는 경우 GraphQL 작업의 인수를 삭제하는 것은 사용자의 책임입니다. 폐기 방법 중 하나는 데이터 API에 대해 SQL 문을 실행하기 전에 요청 매핑 템플릿에 입력 관련 확인 단계를 제공하는 것입니다. listPetsByPriceRange
예제의 요청 매핑 템플릿을 수정하는 방법을 살펴보겠습니다. 전적으로 사용자 입력에만 의존하는 대신 다음과 같이 수행할 수 있습니다.
#set($validMaxPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.maxPrice)) #set($validMinPrice = $util.matches("\d{1,3}[,\\.]?(\\d{1,2})?",$ctx.args.minPrice)) #if (!$validMaxPrice || !$validMinPrice) $util.error("Provided price input is not valid.") #end { "version": "2018-05-29", "statements": [ "select * from Pets where price > :MIN and price < :MAX" ], "variableMap": { ":MAX": $util.toJson($ctx.args.maxPrice), ":MIN": $util.toJson($ctx.args.minPrice) } }
데이터 API에 대해 해석기를 실행할 때 무단 입력을 방지하기 위한 또 다른 방법은 저장 프로시저 및 파라미터화된 입력과 함께 준비된 명령문을 사용하는 것입니다. 예를 들어, listPets
에 대한 해석기에서 준비된 명령문으로 select를 실행하는 다음 프로시저를 정의합니다.
CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END
Aurora Serverless v2 인스턴스에서 생성합니다.
aws rds-data execute-statement --resource-arn "arn:aws:rds:us-east-1:xxxxxxxxxxxx:cluster:http-endpoint-test" \ --schema "mysql" --secret-arn "arn:aws:secretsmanager:us-east-1:xxxxxxxxxxxx:secret:httpendpoint-xxxxxx" \ --region us-east-1 --database "DB_NAME" \ --sql "CREATE PROCEDURE listPets (IN type_param VARCHAR(200)) BEGIN PREPARE stmt FROM 'SELECT * FROM Pets where type=?'; SET @type = type_param; EXECUTE stmt USING @type; DEALLOCATE PREPARE stmt; END"
이제 저장 프로시저만 호출하면 되므로 결과적으로 listPets에 대한 해석기 코드가 간단해졌습니다. 최소한 문자열 입력에서는 작은 따옴표를 이스케이프 처리해야 합니다.
#set ($validType = $util.isString($ctx.args.type) && !$util.isNullOrBlank($ctx.args.type)) #if (!$validType) $util.error("Input for 'type' is not valid.", "ValidationError") #end { "version": "2018-05-29", "statements": [ "CALL listPets(:type)" ] "variableMap": { ":type": $util.toJson($ctx.args.type.replace("'", "''")) } }
이스케이프 문자열 사용
작은따옴표를 사용하여와 같은 SQL 문에서 문자열 리터럴의 시작과 끝을 표시합니다'some string value'
. 문자열 내에서 하나 이상의 작은 따옴표 문자('
)가 있는 문자열 값을 사용할 수 있게 하려면 각 문자열 값을 두 개의 작은 따옴표(''
)로 바꿔야 합니다. 예를 들어 입력 문자열이 Nadia's dog
인 경우 SQL 문에 대해 이스케이프 처리합니다.
update Pets set type='Nadia''s dog' WHERE id='1'