Skip to content

Instantly share code, notes, and snippets.

@humangrass
Last active May 6, 2024 12:27
Show Gist options
  • Save humangrass/ea4d31b62938f2b77f620c0f6eac1fa7 to your computer and use it in GitHub Desktop.
Save humangrass/ea4d31b62938f2b77f620c0f6eac1fa7 to your computer and use it in GitHub Desktop.
Golang graphql example. HTTP-POST
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