-
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmain-7.go
156 lines (142 loc) · 3.81 KB
/
main-7.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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package main
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
graphql "github.com/graph-gophers/graphql-go"
)
// This example builds on main-2.go. The intent of this
// example is to demonstrate how to serve and respond to
// GraphQL queries over HTTP.
/*
* Responders
*
* Responders are a clever pattern I developed that makes
* responding to HTTP requests simpler.
*/
// stripe.com/docs/api/errors
const (
StatusCodeOK = 200
StatusCodeBadRequest = 400
StatusCodeUnauthorized = 401
StatusCodeRequestFailed = 402
StatusCodeNotFound = 404
StatusCodeConflict = 409
StatusCodeTooManyRequests = 429
StatusCodeServerError = 500
)
var Statuses = map[int]string{
StatusCodeOK: "OK",
StatusCodeBadRequest: "Bad Request",
StatusCodeUnauthorized: "Unauthorized",
StatusCodeRequestFailed: "Request Failed",
StatusCodeNotFound: "Not Found",
StatusCodeConflict: "Conflict",
StatusCodeTooManyRequests: "Too Many Requests",
StatusCodeServerError: "Server Error",
}
var (
RespondOK = NewResponder(StatusCodeOK)
RespondBadRequest = NewResponder(StatusCodeBadRequest)
RespondUnauthorized = NewResponder(StatusCodeUnauthorized)
RespondRequestFailed = NewResponder(StatusCodeRequestFailed)
RespondNotFound = NewResponder(StatusCodeNotFound)
RespondConflict = NewResponder(StatusCodeConflict)
RespondTooManyRequests = NewResponder(StatusCodeTooManyRequests)
RespondServerError = NewResponder(StatusCodeServerError)
)
func NewResponder(statusCode int) func(http.ResponseWriter) {
respond := func(w http.ResponseWriter) {
if statusCode >= 200 && statusCode <= 299 {
w.WriteHeader(statusCode)
return
}
status := Statuses[statusCode]
http.Error(w, status, statusCode)
}
return respond
}
/*
* main
*/
const schemaString = `
schema {
query: Query
}
type Query {
greet: String!
}
`
type RootResolver struct{}
func (*RootResolver) Greet() (string, error) {
return "Hello, world!", nil
}
var Schema = graphql.MustParseSchema(schemaString, &RootResolver{})
func main() {
// Client-side request; this goroutine simulates a client-
// side service, e.g. an app or a service that consumes
// this API.
//
// The reason we’re using a goroutine is so we don’t block
// the server from responding to the request.
go func() {
// To perform a query over HTTP, we can use a GET
// request and concatenate the query to the ?query= URL
// parameter. This is common practice for getting
// started.
queryParam := url.QueryEscape(`{ greet }`)
resp, err := http.Get("http://localhost:8000/graphql?query=" + queryParam)
if err != nil {
panic(err)
}
defer resp.Body.Close()
bstr, err := ioutil.ReadAll(resp.Body)
if err != nil {
panic(err)
}
fmt.Println(string(bstr))
// Expected output:
//
// {
// "data": {
// "greet": "Hello, world!"
// }
// }
}()
http.HandleFunc("/graphql", func(w http.ResponseWriter, r *http.Request) {
// This is the GraphQL endpoint (/graphql). It has
// several responsibilities:
//
// - Ignore non non-GET request.
// - Get the URL’s parameters (to access ?query=...).
// - Perform the query against the schema.
// - Respond to errors with HTTP status codes.
//
if r.Method != http.MethodGet {
RespondNotFound(w)
return
}
params := r.URL.Query()
resp := Schema.Exec(context.Background(), params.Get("query"), "", nil)
if len(resp.Errors) > 0 {
RespondServerError(w)
log.Printf("Schema.Exec: %+v", resp.Errors)
return
}
json, err := json.MarshalIndent(resp, "", "\t")
if err != nil {
RespondServerError(w)
log.Printf("json.MarshalIndent: %s", err)
return
}
fmt.Fprint(w, string(json))
})
err := http.ListenAndServe(":8000", nil)
if err != nil {
panic(err)
}
}