Last active
August 18, 2021 14:38
-
-
Save alexyslozada/904e4d6788fe925ede85113d397f5d28 to your computer and use it in GitHub Desktop.
How to process a raw json
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 ( | |
"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 | |
} |
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 ( | |
"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() | |
} |
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 ( | |
"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