Skip to content

Instantly share code, notes, and snippets.

@alexyslozada
Last active August 18, 2021 14:38
Show Gist options
  • Save alexyslozada/904e4d6788fe925ede85113d397f5d28 to your computer and use it in GitHub Desktop.
Save alexyslozada/904e4d6788fe925ede85113d397f5d28 to your computer and use it in GitHub Desktop.
How to process a raw json
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"regexp"
"strconv"
"strings"
)
type Query struct {
Name string `json:"name"`
Filter Filter `json:"filter"`
Queries []Query `json:"queries"`
}
type Filter struct {
Name string `json:"name"`
Conditional string `json:"conditional"`
Value interface{} `json:"value"`
}
var data = []byte(`{
"first_name": "Pedro",
"last_name": "Perez",
"is_active": true,
"children": [
"a", "b", "c"
],
"pets": [
{
"name": "dog",
"friends": ["eagle"],
"children": [
{
"name": "hijo de dog"
},
{
"name": "otro hijo de dog"
}
]
},
{
"name": "cat",
"friends": ["alfa", "beta"]
}
],
"information": {
"timestamp": 123456789,
"status": "complete",
"internal": [
"a", "b", "c"
]
}
}`)
func main() {
http.HandleFunc("/cache", EDql)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatalf("hubo un problema al intentar levantar el servidor: %v", err)
}
}
func EDql(w http.ResponseWriter, r *http.Request) {
query := Query{}
err := json.NewDecoder(r.Body).Decode(&query)
if err != nil {
log.Fatalf("no se pudo leer el body: %v", err)
}
fmt.Println(query)
var f interface{}
err = json.Unmarshal(data, &f)
if err != nil {
log.Fatalf("marshaling: %v", err)
}
dataJSON := parseJSON(f, query)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, err = w.Write(dataJSON)
if err != nil {
log.Fatalf("hubo un error al escribir la respuesta: %v", err)
}
}
// parseJSON read the `f` interface{} and write the json into a slice of bytes.
func parseJSON(f interface{}, query Query) []byte {
result := bytes.Buffer{}
result.WriteByte('{')
m := f.(map[string]interface{})
if len(query.Queries) == 0 {
for k, v := range m {
result.WriteString(`"` + k + `":`)
internalResult := writeSpecificType(v, Query{})
result.Write(internalResult)
}
} else {
for _, keyQuery := range query.Queries {
value, exists := m[keyQuery.Name]
if !exists {
continue
}
result.WriteString(`"` + keyQuery.Name + `":`)
internalResult := writeSpecificType(value, keyQuery)
result.Write(internalResult)
}
}
// We remove the latest `,`
result.Truncate(result.Len() - 1)
result.WriteByte('}')
return result.Bytes()
}
func writeSpecificType(f interface{}, query Query) []byte {
result := bytes.Buffer{}
switch value := f.(type) {
case string:
value = cleanString(value)
result.WriteString(`"` + value + `",`)
case float64:
result.WriteString(strconv.FormatFloat(value, 'f', -1, 64) + ",")
case bool:
result.WriteString(strconv.FormatBool(value) + ",")
case nil:
result.WriteString("null,")
case []interface{}:
internalResult := writeSliceOfInterfaces(value, query)
result.Write(internalResult)
result.WriteByte(',')
case map[string]interface{}:
if isFilter(query, value) {
return result.Bytes()
}
internalResult := parseJSON(value, query)
result.Write(internalResult)
result.WriteByte(',')
default:
log.Fatalf("%s is of a type I don't know how to handle, is %T", value, f)
}
return result.Bytes()
}
// cleanString scape the quotes and remove the new lines
func cleanString(value string) string {
result := strings.ReplaceAll(value, `"`, `\"`)
re := regexp.MustCompile(`\r?\n`)
return re.ReplaceAllString(result, " ")
}
func writeSliceOfInterfaces(f []interface{}, query Query) []byte {
result := bytes.Buffer{}
result.WriteByte('[')
for _, internalValue := range f {
internalResult := writeSpecificType(internalValue, query)
result.Write(internalResult)
}
result.Truncate(result.Len() - 1)
if result.Len() == 0 {
result.WriteString("[]")
} else {
result.WriteString("]")
}
return result.Bytes()
}
// isFilter returns true if we don't want to return data. Returns false if we want to show.
func isFilter(query Query, value map[string]interface{}) bool {
if query.Filter.Name == "" {
return false
}
data, exists := value[query.Filter.Name]
if !exists {
return false
}
switch query.Filter.Conditional {
case "eq":
if data == query.Filter.Value {
return false
}
case "neq":
if data != query.Filter.Value {
return false
}
//case "lt":
// return data < query.Filter.Value
//case "gt":
// return data > query.Filter.Value
//case "le":
// return data <= query.Filter.Value
//case "ge":
// return data >= query.Filter.Value
}
// If we fall here means the data we don't want to return
return true
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"regexp"
"strconv"
"strings"
)
var data = []byte(`{
"first_name": "Pedro",
"last_name": "Perez",
"is_active": true,
"children": [
"a", "b", "c"
],
"pets": [
{"name": "dog", "friends": ["eagle"], "children": [{"name": "hijo de dog"}, {"name": "otro hijo de dog"}]},
{"name": "cat", "friends": ["alfa", "beta"]}
],
"information": {
"timestamp": 123456789,
"status": "complete",
"internal": [
"a", "b", "c"
]
}
}`)
func main() {
var f interface{}
err := json.Unmarshal(data, &f)
if err != nil {
log.Fatalf("marshaling: %v", err)
}
result := parseJSON(f)
fmt.Println("result is:", string(result))
}
func parseJSON(f interface{}) []byte {
result := bytes.Buffer{}
result.WriteByte('{')
m := f.(map[string]interface{})
fmt.Println("la interface base es:", m)
for k, v := range m {
result.WriteString(`"` + k + `":`)
internalResult := writeSpecificType(v)
result.Write(internalResult)
}
// We remove the latest `,`
result.Truncate(result.Len() - 1)
result.WriteByte('}')
return result.Bytes()
}
func writeSpecificType(f interface{}) []byte {
result := bytes.Buffer{}
switch value := f.(type) {
case string:
value = cleanString(value)
result.WriteString(`"` + value + `",`)
case float64:
result.WriteString(strconv.FormatFloat(value, 'f', -1, 64) + ",")
case bool:
result.WriteString(strconv.FormatBool(value) + ",")
case nil:
result.WriteString("null,")
case []interface{}:
internalResult := writeSliceOfInterfaces(value)
result.Write(internalResult)
result.WriteByte(',')
case map[string]interface{}:
internalResult := parseJSON(value)
result.Write(internalResult)
result.WriteByte(',')
default:
log.Fatalf("%s is of a type I don't know how to handle, is %T", value, f)
}
return result.Bytes()
}
// cleanString scapes the quotes and remove the new lines
func cleanString(value string) string {
result := strings.ReplaceAll(value, `"`, `\"`)
re := regexp.MustCompile(`\r?\n`)
return re.ReplaceAllString(result, " ")
}
func writeSliceOfInterfaces(f []interface{}) []byte {
result := bytes.Buffer{}
result.WriteByte('[')
for _, internalValue := range f {
internalResult := writeSpecificType(internalValue)
result.Write(internalResult)
}
result.Truncate(result.Len() - 1)
if result.Len() == 0 {
result.WriteString("[]")
} else {
result.WriteString("]")
}
return result.Bytes()
}
package main
import (
"bytes"
"encoding/json"
"log"
"net/http"
"regexp"
"strconv"
"strings"
)
type Query struct {
Name string
Queries []Query
}
var data = []byte(`{
"first_name": "Pedro",
"last_name": "Perez",
"is_active": true,
"children": [
"a", "b", "c"
],
"pets": [
{"name": "dog", "friends": ["eagle"], "children": [{"name": "hijo de dog"}, {"name": "otro hijo de dog"}]},
{"name": "cat", "friends": ["alfa", "beta"]}
],
"information": {
"timestamp": 123456789,
"status": "complete",
"internal": [
"a", "b", "c"
]
}
}`)
func main() {
http.HandleFunc("/cache", EDql)
http.ListenAndServe(":8080", nil)
}
func EDql(w http.ResponseWriter, r *http.Request) {
query := Query{}
err := json.NewDecoder(r.Body).Decode(&query)
if err != nil {
log.Fatalf("no se pudo leer el body: %v", err)
}
var f interface{}
err = json.Unmarshal(course, &f)
if err != nil {
log.Fatalf("marshaling: %v", err)
}
dataJSON := parseJSON(f, query)
w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(dataJSON)
}
func parseJSON(f interface{}, query Query) []byte {
result := bytes.Buffer{}
result.WriteByte('{')
m := f.(map[string]interface{})
if len(query.Queries) == 0 {
for k, v := range m {
result.WriteString(`"` + k + `":`)
internalResult := writeSpecificType(v, Query{})
result.Write(internalResult)
}
} else {
for _, keyQuery := range query.Queries {
value, exists := m[keyQuery.Name]
if !exists {
continue
}
result.WriteString(`"` + keyQuery.Name + `":`)
internalResult := writeSpecificType(value, keyQuery)
result.Write(internalResult)
}
}
// We remove the latest `,`
result.Truncate(result.Len() - 1)
result.WriteByte('}')
return result.Bytes()
}
func writeSpecificType(f interface{}, query Query) []byte {
result := bytes.Buffer{}
switch value := f.(type) {
case string:
value = cleanString(value)
result.WriteString(`"` + value + `",`)
case float64:
result.WriteString(strconv.FormatFloat(value, 'f', -1, 64) + ",")
case bool:
result.WriteString(strconv.FormatBool(value) + ",")
case nil:
result.WriteString("null,")
case []interface{}:
internalResult := writeSliceOfInterfaces(value, query)
result.Write(internalResult)
result.WriteByte(',')
case map[string]interface{}:
internalResult := parseJSON(value, query)
result.Write(internalResult)
result.WriteByte(',')
default:
log.Fatalf("%s is of a type I don't know how to handle, is %T", value, f)
}
return result.Bytes()
}
// cleanString scapes the quotes and remove the new lines
func cleanString(value string) string {
result := strings.ReplaceAll(value, `"`, `\"`)
re := regexp.MustCompile(`\r?\n`)
return re.ReplaceAllString(result, " ")
}
func writeSliceOfInterfaces(f []interface{}, query Query) []byte {
result := bytes.Buffer{}
result.WriteByte('[')
for _, internalValue := range f {
internalResult := writeSpecificType(internalValue, query)
result.Write(internalResult)
}
result.Truncate(result.Len() - 1)
if result.Len() == 0 {
result.WriteString("[]")
} else {
result.WriteString("]")
}
return result.Bytes()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment