몇 주 전에 저는 점점 인기를 얻고 있는 GraphQL에 대해 배우고 있으며, 이것이 어떻게 일반적인 RESTful API를 대체할 수 있는지에 대해 언급한 적이 있습니다. 저의 이전 예제에서 Node.js를 사용하여 GraphQL 애플리케이션을 만드는 방법과 카우치베이스 NoSQL 데이터베이스. 하지만 저는 Node.js만큼이나 Go 프로그래밍 언어의 팬입니다.
다음을 사용하여 데이터를 생성하고 쿼리할 수 있는 애플리케이션을 Golang으로 만드는 방법을 살펴보겠습니다. GraphQL 쿼리 대신 여러 개의 RESTful API 엔드포인트를 사용합니다.
GraphQL에 익숙하지 않으시다면, 이 방식은 프론트엔드에서 백엔드로 쿼리를 전달하고 데이터의 출처나 복잡성에 관계없이 요청한 데이터만 가져오는 방식으로 작동하며, 관련성이 없는 수많은 API 엔드포인트에서 데이터를 소비하는 대신에 데이터의 출처나 복잡성에 관계없이 요청된 데이터만 반환합니다. 이렇게 하면 요청과 데이터 페이로드가 줄어들어 빠르고 효율적으로 업무를 처리할 수 있습니다.
GraphQL 및 Golang 시작하기
RESTful API와 마찬가지로 GraphQL 애플리케이션의 대부분은 설정으로 구성됩니다. 그러나 GraphQL 애플리케이션은 계획에 따라 달라지는 부분이 적기 때문에 사용하기 쉽도록 많은 계획이 필요한 RESTful API와는 다릅니다.
계속 진행하려면 먼저 Golang에 대한 GraphQL 패키지 종속성을 설치해야 합니다. 명령줄에서 다음을 실행합니다:
|
1 |
go get github.com/그래프 쿼리-go/그래프 쿼리 |
종속성을 사용할 수 있는 경우, 프로젝트 내에서 새 프로젝트를 생성하세요. $GOPATH. 해당 프로젝트 내에서 다음과 같은 파일을 만듭니다. main.go 의 애플리케이션 기반이 될 다음 사항을 포함합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
패키지 메인 가져오기 ( "encoding/json" "fmt" "log" "net/http" "github.com/graphql-go/graphql" ) 유형 계정 구조체 { ID 문자열 `json:"id,생략"` 이름 문자열 `json:"이름"` 성 문자열 `json:"성"` 유형 문자열 `json:"type"` } 유형 블로그 구조체 { ID 문자열 `json:"id,생략"` 계정 문자열 `json:"계정"` 제목 문자열 `json:"title"` 콘텐츠 문자열 `json:"content"` 유형 문자열 `json:"type"` } func 메인() { fmt.Println("신청 시작 중...") 계정 유형 := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "계정", 필드: 그래프 쿼리.필드{}, }) 블로그 유형 := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "블로그", 필드: 그래프 쿼리.필드{}, }) rootQuery := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "쿼리", 필드: 그래프 쿼리.필드{}, }) rootMutation := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "RootMutation", 필드: 그래프 쿼리.필드{}, }) 스키마, _ := 그래프 쿼리.새로운 스키마(그래프 쿼리.스키마 구성{ 쿼리: rootQuery, 돌연변이: rootMutation, }) http.핸들펀크("/그래프QL", func(w http.응답서 작성기, r *http.요청) { 결과 := 그래프 쿼리.Do(그래프 쿼리.매개변수{ 스키마: 스키마, 요청 문자열: r.URL.쿼리().Get("query"), }) json.새 인코더(w).인코딩(결과) }) http.ListenAndServe(":8080", nil) } |
저희의 계획은 특정 계정에 대한 블로그 항목을 생성하고 쿼리할 뿐만 아니라 계정을 생성하고 쿼리할 수 있는 애플리케이션을 만드는 것입니다. 애플리케이션의 데이터 모델은 다음과 같이 정의됩니다. 계정 구조체와 블로그 구조체. 이 데이터 모델은 데이터베이스 데이터 모델과 GraphQL 데이터 모델을 강화하는 데 도움이 됩니다.
GraphQL 설정과 관련하여 몇 가지 객체가 생성된 것을 볼 수 있습니다. 객체의 계정 유형 및 블로그 유형 는 Go 구조체를 중심으로 만들어질 GraphQL 데이터 모델을 나타냅니다. 아직 구성되지 않았지만 곧 구성될 예정입니다. 그리고 rootQuery 는 우리가 실행할 수 있는 쿼리 집합이 되고 rootMutation 는 실행할 수 있는 모든 데이터 변경 변이가 됩니다. GraphQL을 사용하면 데이터를 읽는 데만 국한되지 않습니다.
GraphQL 스키마를 사용하면 무엇이 쿼리이고 무엇이 변이인지 정의할 수 있습니다. 이는 쿼리를 사용하고자 할 때 필요합니다. RESTful API를 만들지 않더라도 HTTP 엔드포인트는 여전히 필요합니다. 이 단일 /graphql 엔드포인트는 모든 쿼리 및 변형을 처리하며 스키마에 의해 구동됩니다.
데이터베이스를 연결하기 전에 GraphQL 스키마를 정의할 수 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
계정 유형 := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "계정", 필드: 그래프 쿼리.필드{ "id": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, "이름": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, "성": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, }, }) 블로그 유형 := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "블로그", 필드: 그래프 쿼리.필드{ "id": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, "계정": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, "title": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, "content": &그래프 쿼리.필드{ 유형: 그래프 쿼리.문자열, }, }, }) |
속성 이름과 그에 해당하는 데이터 유형만 정의하고 있다는 점에 주목하세요. Go에서 데이터 구조를 정의하는 방식과 매우 유사하다고 말씀드렸습니다.
이제 Couchbase Server의 데이터로 스키마를 로드하는 데 집중해 보겠습니다.
GraphQL을 사용하여 NoSQL 데이터베이스에서 데이터 쿼리하기
현재로서는 데이터베이스 준비를 완료하지 않았습니다. 이 튜토리얼의 요점은 Couchbase를 구성하는 것이 아닙니다. N1QL을 지원하는 Couchbase Server, 버킷, 일부 인덱스, 애플리케이션에 대한 역할 기반 액세스 제어 계정이 필요합니다.
명령줄에서 다음 줄을 실행하여 데이터베이스 패키지를 가져옵니다:
|
1 2 |
go get github.com/사토리/go.uuid go get gopkg.in/카우치베이스/gocb.v1 |
위의 명령은 문서 키에 대한 UUID 값을 생성하기 위한 패키지와 Couchbase Go SDK를 가져옵니다.
우리가 이미 수행한 모든 작업을 무시하고 main.go 파일을 열고 다음 코드를 살펴본 후 적절한 곳에 적용하세요:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
패키지 메인 가져오기 ( "encoding/json" "fmt" "log" "net/http" "github.com/graphql-go/graphql" uuid "github.com/satori/go.uuid" gocb "gopkg.in/couchbase/gocb.v1" ) var 버킷 *gocb.버킷 func 메인() { fmt.Println("신청 시작 중...") 클러스터, err := gocb.연결("couchbase://localhost") 만약 err != nil { 로그.치명적(err) } 클러스터.인증(gocb.비밀번호 인증기{사용자 이름: "예제", 비밀번호: "123456"}) 버킷, err = 클러스터.OpenBucket("예제", "") 만약 err != nil { 로그.치명적(err) } } |
데이터베이스와 상호 작용할 때 사용할 버킷을 정의했음을 알 수 있습니다. 우리는 Couchbase 클러스터에 연결하고 있습니다. 메인 함수, RBAC 계정으로 인증하기, 버킷 열기 등 이 튜토리얼을 시작하기 전에 모두 정의했어야 합니다.
데이터베이스에 이미 데이터가 있다고 가정해 보겠습니다. 먼저 데이터를 쿼리해 보겠습니다. 이전에 추가한 다음 코드 덩어리를 기억하시나요?
|
1 2 3 4 |
rootQuery := 그래프 쿼리.새 개체(그래프 쿼리.ObjectConfig{ 이름: "쿼리", 필드: 그래프 쿼리.필드{ }, }) |
각 필드는 필드 속성을 추가합니다. 데이터베이스에서 모든 계정을 가져오고 싶다고 가정해 보겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
"계정": &그래프 쿼리.필드{ 유형: 그래프 쿼리.뉴리스트(계정 유형), 해결: func(p 그래프 쿼리.ResolveParams) (인터페이스{}, 오류) { 쿼리 := gocb.NewN1qlQuery("SELECT META(account).id, account.* FROM example AS account WHERE account.type = 'account'") 행, err := 버킷.ExecuteN1qlQuery(쿼리, nil) 만약 err != nil { 반환 nil, err } var 계정 []계정 var 행 계정 에 대한 행.다음(&행) { 계정 = 추가(계정, 행) } 반환 계정, nil }, }, |
위 코드에서는 다음과 같은 GraphQL 필드를 만들고 있습니다. 계정 의 목록을 반환합니다. 계정 유형 를 실행합니다. 그리고 해결 함수가 무거운 작업을 수행합니다. 선택적으로 쿼리 매개 변수를 전달할 수 있지만 이 특정 필드에서는 그렇지 않습니다. 계정을 쿼리하려고 할 때 가능한 모든 속성과 결과를 반환하는 N1QL 쿼리를 만들고 있습니다. GraphQL 쿼리는 이러한 속성 및 결과 중 어떤 것이 클라이언트에 전달될지 결정합니다.
실행할 수 있는 프런트엔드 쿼리는 다음과 같습니다:
|
1 2 3 4 5 6 |
{ 계정 { id, 이름 } } |
우리는 id, 이름및 성의 경우, 우리는 id 그리고 이름 를 반환합니다. 실제로 쿼리를 실행하려면 다음과 같이 cURL 문을 발행합니다:
|
1 |
curl -g 'http://localhost:8080/graphql?query={accounts{id,name}}' |
GraphQL 쿼리는 쿼리 매개변수 보기를 통해 API 엔드포인트로 전송된다는 점을 기억하세요.
다른 가능한 GraphQL 쿼리를 살펴보겠습니다. 모든 계정이 아닌 특정 계정에 대해 쿼리하고 싶다고 가정해 보겠습니다. 다음과 같은 필드를 만들 수 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
"계정": &그래프 쿼리.필드{ 유형: 계정 유형, Args: 그래프 쿼리.필드 구성 인수{ "id": &그래프 쿼리.ArgumentConfig{ 유형: 그래프 쿼리.NewNonNull(그래프 쿼리.문자열), }, }, 해결: func(매개변수 그래프 쿼리.ResolveParams) (인터페이스{}, 오류) { var 계정 계정 계정.ID = 매개변수.Args["id"].(문자열) _, err := 버킷.Get(계정.ID, &계정) 만약 err != nil { 반환 nil, err } 반환 계정, nil }, }, |
이 필드는 쿼리 시 하나의 계정 유형를 사용할 수 있지만 전달할 수 있는 인수가 있습니다. 우리는 id 가 있어야 하며 문자열이어야 합니다. 에서 해결를 사용하여 id 매개변수를 추가하고 이를 사용하여 문서 키로 NoSQL 문서를 가져옵니다. 결과가 반환되고 GraphQL 쿼리를 통해 클라이언트로 다시 전송할 속성을 결정합니다.
다음 쿼리를 입력합니다:
|
1 2 3 4 5 6 |
{ 계정(id:"2345345435") { 이름, 성 } } |
위의 쿼리에서는 ID를 전달하고 이름 그리고 성 를 반환합니다. 이 쿼리를 실제로 실행하려면 다음과 같은 cURL 문을 실행하면 됩니다:
|
1 |
curl -g 'http://localhost:8080/graphql?query={account(id:"2345345435"){이름,성}}' |
이제 특정 사용자 계정에 대한 모든 블로그를 반환한다고 가정해 보겠습니다. 단계는 특정 계정을 쿼리할 때 보았던 것과 유사합니다. 다음은 우리의 rootQuery:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
"블로그": &그래프 쿼리.필드{ 유형: 그래프 쿼리.뉴리스트(블로그 유형), Args: 그래프 쿼리.필드 구성 인수{ "계정": &그래프 쿼리.ArgumentConfig{ 유형: 그래프 쿼리.NewNonNull(그래프 쿼리.문자열), }, }, 해결: func(매개변수 그래프 쿼리.ResolveParams) (인터페이스{}, 오류) { 계정 := 매개변수.Args["계정"].(문자열) 쿼리 := gocb.NewN1qlQuery("SELECT META(blog).id, blog.* FROM example AS blog WHERE blog.type = 'blog' AND blog.account = $1") var n1qlParams []인터페이스{} n1qlParams = 추가(n1qlParams, 계정) 행, err := 버킷.ExecuteN1qlQuery(쿼리, n1qlParams) 만약 err != nil { 반환 nil, err } var 블로그 []블로그 var 행 블로그 에 대한 행.다음(&행) { 블로그 = 추가(블로그, 행) } 반환 블로그, nil }, }, |
결과는 다음과 같은 목록이 표시됩니다. 블로그 유형 그리고 우리는 필수 계정 매개변수를 문자열 형식으로 전달합니다. 내부의 해결 함수를 사용하면 계정 값을 매개변수로 설정하여 매개변수화된 N1QL 쿼리에 사용합니다. 쿼리는 특정 계정에 대한 모든 블로그 항목만 반환합니다. 계정 값입니다.
모든 블로그를 가져오기 위한 쿼리는 다음과 같습니다:
|
1 2 3 4 5 6 |
{ 블로그(계정:"2345345435") { id, title } } |
위의 내용은 특정 계정을 쿼리할 때 본 것과 매우 유사합니다. 변수를 예상하고 있으며, 변수가 없는 id 및 title 속성입니다.
지금까지의 데이터를 기반으로 한 꽤 깔끔한 쿼리를 보고 싶으신가요? 다음 쿼리를 확인해 보세요:
|
1 2 3 4 5 6 7 8 9 10 |
{ 계정(id:"2345345435") { 이름, 성 } 블로그(계정:"2345345435") { title, 콘텐츠 } } |
위의 예에서는 단일 요청을 하고 있습니다. 단일 쿼리이지만 특정 계정에 대한 계정 데이터와 블로그 데이터를 요청하고 있습니다. RESTful API로 이 작업을 수행했다면 서버에 여러 번 요청하여 애플리케이션 수준의 잠재적 변형을 만들었을 것입니다.
cURL 명령은 다음과 같습니다:
|
1 |
curl -g 'http://localhost:8080/graphql?query={account(id:"2345345435"){이름,성}blogs(계정:"2345345435"){제목,내용}}' |
지금까지는 읽기 쿼리만 수행했습니다. 데이터를 생성하거나 변경하는 변형을 수행하려면 어떻게 해야 할까요?
GraphQL을 사용한 데이터 변형을 살펴보겠습니다.
대신 rootQuery에서 작업할 것입니다. rootMutation. 필드의 경우 다음을 추가합니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
"createAccount": &그래프 쿼리.필드{ 유형: 계정 유형, Args: 그래프 쿼리.필드 구성 인수{ "이름": &그래프 쿼리.ArgumentConfig{ 유형: 그래프 쿼리.NewNonNull(그래프 쿼리.문자열), }, "성": &그래프 쿼리.ArgumentConfig{ 유형: 그래프 쿼리.NewNonNull(그래프 쿼리.문자열), }, }, 해결: func(매개변수 그래프 쿼리.ResolveParams) (인터페이스{}, 오류) { var 계정 계정 계정.이름 = 매개변수.Args["이름"].(문자열) 계정.성 = 매개변수.Args["성"].(문자열) 계정.유형 = "계정" id, _ := uuid.NewV4() _, err := 버킷.삽입(id.문자열(), &계정, 0) 만약 err != nil { 반환 nil, err } 계정.ID = id.문자열() 반환 계정, nil }, }, |
우리가 반환하는 것을 주목하십시오. 계정 유형 쿼리와 함께 두 개의 매개변수가 전달될 것으로 예상하고 있습니다. 그러나 전략은 실제로 크게 다르지 않습니다.
에서 해결 함수를 사용하여 매개변수를 가져와 데이터베이스에 새 계정을 만드는 데 사용하고 있습니다. 이것은 스키마에 변이로 연결되어 있기 때문에 쿼리 방식이 달라집니다.
먼저 실행할 쿼리는 다음과 같습니다:
|
1 2 3 4 5 6 7 |
돌연변이+_ { createAccount(이름:"매트",성:"Groves") { id, 이름, 성 } } |
앞에 다음과 같은 단어가 붙는 것을 주목하세요. 돌연변이. cURL에서는 다음과 같이 표시됩니다:
|
1 |
curl -g 'http://localhost:8080/graphql?query=mutation+_{계정 만들기(이름:"매트",성:"그로브스"){id,이름,성}}' |
이제 쿼리 또는 변형을 수행하는 필드를 계속 만들 수 있지만 단계는 동일합니다. 이 특정 애플리케이션 아이디어에 계속 기여하는 것은 여러분의 상상력에 맡기겠습니다.
결론
방금 사용 방법을 확인하셨습니다. GraphQL 를 사용하는 Golang 애플리케이션에서 데이터를 쿼리하려면 NoSQL 데이터베이스. GraphQL은 사용자가 추적해야 하는 여러 RESTful API 엔드포인트를 끊임없이 생성하는 대신 사용자가 단일 요청에서 원하는 데이터를 정의하도록 하려는 경우에 매우 유용합니다. 애플리케이션이 데이터베이스를 쿼리할 때 GraphQL이 이를 대체할 수 없다는 점에 유의하세요. 여전히 다음에서 적절한 N1QL 쿼리를 만들어야 합니다. 카우치베이스. GraphQL은 클라이언트 수준에서만 작동합니다.
카우치베이스와 함께 Go를 사용하는 방법에 대한 자세한 내용은 다음과 같이 확인하세요. 카우치베이스 개발자 포털.