Last active
May 6, 2024 12:27
-
-
Save humangrass/ea4d31b62938f2b77f620c0f6eac1fa7 to your computer and use it in GitHub Desktop.
Golang graphql example. HTTP-POST
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/json" | |
"fmt" | |
"math/rand" | |
"net/http" | |
"time" | |
"github.com/graphql-go/graphql" | |
) | |
type Product struct { | |
ID int64 `json:"id"` | |
Name string `json:"name"` | |
Info string `json:"info,omitempty"` | |
Price float64 `json:"price"` | |
} | |
var products = []Product{ | |
{ | |
ID: 1, | |
Name: "Chicha Morada", | |
Info: "Chicha morada is a beverage originated in the Andean regions of Perú but is actually consumed at a national level (wiki)", | |
Price: 7.99, | |
}, | |
{ | |
ID: 2, | |
Name: "Chicha de jora", | |
Info: "Chicha de jora is a corn beer chicha prepared by germinating maize, extracting the malt sugars, boiling the wort, and fermenting it in large vessels (traditionally huge earthenware vats) for several days (wiki)", | |
Price: 5.95, | |
}, | |
{ | |
ID: 3, | |
Name: "Pisco", | |
Info: "Pisco is a colorless or yellowish-to-amber colored brandy produced in winemaking regions of Peru and Chile (wiki)", | |
Price: 9.95, | |
}, | |
} | |
var productType = graphql.NewObject( | |
graphql.ObjectConfig{ | |
Name: "Product", | |
Fields: graphql.Fields{ | |
"id": &graphql.Field{ | |
Type: graphql.Int, | |
}, | |
"name": &graphql.Field{ | |
Type: graphql.String, | |
}, | |
"info": &graphql.Field{ | |
Type: graphql.String, | |
}, | |
"price": &graphql.Field{ | |
Type: graphql.Float, | |
}, | |
}, | |
}, | |
) | |
var queryType = graphql.NewObject( | |
graphql.ObjectConfig{ | |
Name: "Query", | |
Fields: graphql.Fields{ | |
/* Get (read) single product by id | |
curl --location 'http://localhost:8080/product' \ | |
--header 'Content-Type: application/json' \ | |
--data '{"query":"query { product(id:1){id,name,info,price} }","variables":{}}' | |
*/ | |
"product": &graphql.Field{ | |
Type: productType, | |
Description: "Get product by id", | |
Args: graphql.FieldConfigArgument{ | |
"id": &graphql.ArgumentConfig{ | |
Type: graphql.Int, | |
}, | |
}, | |
Resolve: func(p graphql.ResolveParams) (interface{}, error) { | |
id, ok := p.Args["id"].(int) | |
if ok { | |
// Find product | |
for _, product := range products { | |
if int(product.ID) == id { | |
return product, nil | |
} | |
} | |
} | |
return nil, nil | |
}, | |
}, | |
/* Get (read) product list | |
curl --location 'http://localhost:8080/product' \ | |
--header 'Content-Type: application/json' \ | |
--data '{"query":"query { list{id,name,info,price} }","variables":{}}' | |
*/ | |
"list": &graphql.Field{ | |
Type: graphql.NewList(productType), | |
Description: "Get product list", | |
Resolve: func(params graphql.ResolveParams) (interface{}, error) { | |
return products, nil | |
}, | |
}, | |
}, | |
}) | |
var mutationType = graphql.NewObject(graphql.ObjectConfig{ | |
Name: "Mutation", | |
Fields: graphql.Fields{ | |
/* Create new product item | |
curl --location 'http://localhost:8080/product' \ | |
--header 'Content-Type: application/json' \ | |
--data '{"query":"mutation { create(name:\"Inca Kola\",info:\"Inca Kola is a soft drink!\",price:1.99){id,name,info,price} }","variables":{}}' | |
*/ | |
"create": &graphql.Field{ | |
Type: productType, | |
Description: "Create new product", | |
Args: graphql.FieldConfigArgument{ | |
"name": &graphql.ArgumentConfig{ | |
Type: graphql.NewNonNull(graphql.String), | |
}, | |
"info": &graphql.ArgumentConfig{ | |
Type: graphql.String, | |
}, | |
"price": &graphql.ArgumentConfig{ | |
Type: graphql.NewNonNull(graphql.Float), | |
}, | |
}, | |
Resolve: func(params graphql.ResolveParams) (interface{}, error) { | |
rand.Seed(time.Now().UnixNano()) | |
product := Product{ | |
ID: int64(rand.Intn(100000)), // generate random ID | |
Name: params.Args["name"].(string), | |
Info: params.Args["info"].(string), | |
Price: params.Args["price"].(float64), | |
} | |
products = append(products, product) | |
return product, nil | |
}, | |
}, | |
/* Update product by id | |
curl --location 'http://localhost:8080/product' \ | |
--header 'Content-Type: application/json' \ | |
--data '{"query":"mutation { update(id:1,price:3.95){id,name,info,price} }","variables":{}}' | |
*/ | |
"update": &graphql.Field{ | |
Type: productType, | |
Description: "Update product by id", | |
Args: graphql.FieldConfigArgument{ | |
"id": &graphql.ArgumentConfig{ | |
Type: graphql.NewNonNull(graphql.Int), | |
}, | |
"name": &graphql.ArgumentConfig{ | |
Type: graphql.String, | |
}, | |
"info": &graphql.ArgumentConfig{ | |
Type: graphql.String, | |
}, | |
"price": &graphql.ArgumentConfig{ | |
Type: graphql.Float, | |
}, | |
}, | |
Resolve: func(params graphql.ResolveParams) (interface{}, error) { | |
id, _ := params.Args["id"].(int) | |
name, nameOk := params.Args["name"].(string) | |
info, infoOk := params.Args["info"].(string) | |
price, priceOk := params.Args["price"].(float64) | |
product := Product{} | |
for i, p := range products { | |
if int64(id) == p.ID { | |
if nameOk { | |
products[i].Name = name | |
} | |
if infoOk { | |
products[i].Info = info | |
} | |
if priceOk { | |
products[i].Price = price | |
} | |
product = products[i] | |
break | |
} | |
} | |
return product, nil | |
}, | |
}, | |
/* Delete product by id | |
curl --location 'http://localhost:8080/product' \ | |
--header 'Content-Type: application/json' \ | |
--data '{"query":"mutation { delete(id:1){id,name,info,price} }","variables":{}}' | |
*/ | |
"delete": &graphql.Field{ | |
Type: productType, | |
Description: "Delete product by id", | |
Args: graphql.FieldConfigArgument{ | |
"id": &graphql.ArgumentConfig{ | |
Type: graphql.NewNonNull(graphql.Int), | |
}, | |
}, | |
Resolve: func(params graphql.ResolveParams) (interface{}, error) { | |
id, _ := params.Args["id"].(int) | |
product := Product{} | |
for i, p := range products { | |
if int64(id) == p.ID { | |
product = products[i] | |
// Remove from product list | |
products = append(products[:i], products[i+1:]...) | |
} | |
} | |
return product, nil | |
}, | |
}, | |
}, | |
}) | |
var schema, _ = graphql.NewSchema( | |
graphql.SchemaConfig{ | |
Query: queryType, | |
Mutation: mutationType, | |
}, | |
) | |
func executeQuery(query string, schema graphql.Schema) *graphql.Result { | |
result := graphql.Do(graphql.Params{ | |
Schema: schema, | |
RequestString: query, | |
}) | |
if len(result.Errors) > 0 { | |
fmt.Printf("errors: %v", result.Errors) | |
} | |
return result | |
} | |
func main() { | |
http.HandleFunc("/product", func(w http.ResponseWriter, r *http.Request) { | |
if r.Method != http.MethodPost { | |
http.Error(w, "Only POST requests are supported", http.StatusMethodNotAllowed) | |
return | |
} | |
w.Header().Set("Content-Type", "application/json") | |
var requestBody struct { | |
Query string `json:"query"` | |
} | |
if err := json.NewDecoder(r.Body).Decode(&requestBody); err != nil { | |
http.Error(w, "Failed to parse request body", http.StatusBadRequest) | |
return | |
} | |
result := executeQuery(requestBody.Query, schema) | |
err := json.NewEncoder(w).Encode(result) | |
if err != nil { | |
fmt.Println(err) | |
} | |
}) | |
fmt.Println("Server is running on port 8080") | |
err := http.ListenAndServe(":8080", nil) | |
if err != nil { | |
fmt.Println(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment