GraphQL 구독(Subscription) 기능을 통해 실시간으로 클라이언트에 이벤트를 스트리밍할 수 있습니다.
아래 코드는 go run github.com/99designs/gqlgen init
으로 만들어진 기본 코드입니다.
server.go
package main
import (
"log"
"net/http"
"os"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/songtomtom/gqlgen-apollo-subscriptions/graph"
)
const defaultPort = "8080"
func main() {
port := os.Getenv("PORT")
if port == "" {
port = defaultPort
}
srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)
log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
Subscription
을 사용하려면AddTransport(&transport.Websocket{})
를 호출하여 클라이언트와 서버를 연결하세요.
server.go
AddTransport(&transport.Websocket{})
를 추가한 코드입니다.
package main
import (
"github.com/99designs/gqlgen/graphql/handler/transport"
"log"
"net/http"
"os"
"github.com/99designs/gqlgen/graphql/handler"
"github.com/99designs/gqlgen/graphql/playground"
"github.com/songtomtom/gqlgen-apollo-subscriptions/graph"
)
const defaultPort = "8080"
func main() {
port := os.Getenv("PORT")
if port == "" {
port = defaultPort
}
srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}}))
srv.AddTransport(&transport.Websocket{}) // <---- This is the important part!
http.Handle("/", playground.Handler("GraphQL playground", "/query"))
http.Handle("/query", srv)
log.Printf("connect to http://localhost:%s/ for GraphQL playground", port)
log.Fatal(http.ListenAndServe(":"+port, nil))
}
schema.graphqls
"""
Make sure you have at least something in your `Query` type.
If you don't have a query the playground will be unable
to introspect your schema!
"""
type Query {
placeholder: String
}
"""
`Time` is a simple type only containing the current time as
a unix epoch timestamp and a string timestamp.
"""
type Time {
unixTime: Int!
timeStamp: String!
}
"""
`Subscription` is where all the subscriptions your clients can
request. You can use Schema Directives like normal to restrict
access.
"""
type Subscription {
"""
`currentTime` will return a stream of `Time` objects.
"""
currentTime: Time!
}
ch := make(chan *model.Time)
채널을 생성하고 ch
를 리턴하는 리졸버입니다. Go 의 채널은 클라이언트에 데이터를 보내는데 사용합니다.
schema.resolvers.go
// CurrentTime is the resolver for the currentTime field.
func (r *subscriptionResolver) CurrentTime(ctx context.Context) (<-chan *model.Time, error) {
// First you'll need to `make()` your channel. Use your type here!
ch := make(chan *model.Time)
// You can (and probably should) handle your channels in a central place outside of `schema.resolvers.go`.
// For this example we'll simply use a Goroutine with a simple loop.
go func() {
for {
// In our example we'll send the current time every second.
time.Sleep(1 * time.Second)
fmt.Println("Tick")
// Prepare your object.
currentTime := time.Now()
t := &model.Time{
UnixTime: int(currentTime.Unix()),
TimeStamp: currentTime.Format(time.RFC3339),
}
// The channel may have gotten closed due to the client disconnecting.
// To not have our Goroutine block or panic, we do the send in a select block.
// This will jump to the default case if the channel is closed.
select {
case ch <- t: // This is the actual send.
// Our message went through, do nothing
default: // This is run when our send does not work.
fmt.Println("Channel closed.")
// You can handle any deregistration of the channel here.
return // We'll just return ending the routine.
}
}
}()
// We return the channel and no error.
return ch, nil
}
subscription OnCurrentTime {
currentTime {
unixTime
timeStamp
}
}
1초 마다 시간이 바뀌는 값이 반환되어야 합니다.
{
"data": {
"currentTime": {
"unixTime": 1672931488,
"timeStamp": "2023-01-06T00:11:28+09:00"
}
}
}