Best way to store values from URL params as arbitrary data types


(Ross Bown) #1

Hi All,

didn’t know how to explain it in the title, so what I basically want to achieve is:

I’m creating a key-value store as a little project, but want to be able to store any data type via the URL (would it be easier via GUI?). For example… you enter /Dog/Zeus then it would save that to a map as Dog: “Zeus” (string)… but when i enter /Cash/1000 it would save that to a map as Cash: 1000 (int). At the moment, all my code is doing, is saving the entry as a string. I need to allow for arbitrary data types

FULL CODE:

Map:

var data map[string][]string

HandleFunc for the functions:

	r.HandleFunc("/keys", handleDisplay).Methods("GET")
r.HandleFunc("/keys/{key}", handleDisplay).Methods("GET")
r.HandleFunc("/updatekey/{key}/{newkey}", handleUpdate).Methods("PUT")
r.HandleFunc("/update/{key}/{value}/{newvalue}", handleUpdate).Methods("PUT")
r.HandleFunc("/insert/{key}/{value}", handleCreate).Methods("POST")
r.HandleFunc("/delete/{key}", handleDelete).Methods("DELETE")
r.HandleFunc("/delete/{key}/{value}", handleDelete).Methods("DELETE")

Display, Create and Update functions:

func handleDisplay(w http.ResponseWriter, r *http.Request) {

params := mux.Vars(r)

k := params["key"]

if k != "" {
	for item := range data {
		if item == k {
			for _, value := range data[k] {
				fmt.Fprintf(w, "KEY: %v: VALUE: %v\n", k, value)
			}
		}
	}
} else {
	for item := range data {
		for _, value := range data[item] {
			fmt.Fprintf(w, "KEY: %v: VALUE: %v\n", item, value)
		}
	}
}
}

func handleUpdate(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)

k := params["key"]
v := params["value"]
nv := params["newvalue"]
nk := params["newkey"]

if v == "" && nv == "" {
	if val, ok := data[k]; ok {
		data[nk] = val
		delete(data, k)
		fmt.Fprintf(w, "KEY: %v has been updated with new KEY: %v", k, nk)
	} else {
		fmt.Fprintf(w, "The KEY: %v doesn't exist", k)
	}
} else {
	if _, ok := data[k]; ok {
		for i := range data[k] {
			data[k] = append(data[k][:i], data[k][i+1:]...)
		}
		data[k] = append(data[k], nv)
		fmt.Fprintf(w, "KEY: %v: VALUE: %v has been updated with Value: %v", k, v, nv)
	} else {
		fmt.Fprintf(w, "KEY: %s doesn't exist", k)
	}
}
}

func handleCreate(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)

k := params["key"]
v := params["value"]

data[k] = append(data[k], v)
fmt.Fprintf(w, "KEY: %v: VALUE: %v was inserted into the key-value store successfully", k, v)
}

(Johan Dahl) #2

Hi

Is there any advantage of storing them as anything than string? You will then have to convert them into strings then you deliver them back with the GET methods.

If you want to you could always try to use https://golang.org/pkg/strconv/ and first try to convert to a bool, then int, float and if nothing works just leave it as a string.


(George Calianu) #3

Just an observation, in CRUD operations is no need to use method name in the route :wink:


(Ross Bown) #4

I know it’s not best practice… however for testing purposes and ease I have decided to name them after the CRUD capabilities.


(Ross Bown) #5

This isn’t really what I’m looking for. I want to parse the values entered in the URL and decide whether the value is a bool, int or string, then store them accordingly.


(Johan Dahl) #6

I thought you could do like this: https://goplay.space/#2BKtalFyGXl

package main

import (
	"fmt"
	"strconv"
)

func parseValue(s string) interface{} {
	b, err := strconv.ParseBool(s)
	if err == nil {
		return b
	}
	i, err := strconv.ParseInt(s, 10, 64)
	if err == nil {
		return i
	}
	f, err := strconv.ParseFloat(s, 64)
	if err == nil {
		return f
	}
	return s
}

func main() {
	v := parseValue("false")
	fmt.Printf("%T %#v\n", v, v)
	v = parseValue("33")
	fmt.Printf("%T %#v\n", v, v)
	v = parseValue("3.14")
	fmt.Printf("%T %#v\n", v, v)
	v = parseValue("hello")
	fmt.Printf("%T %#v\n", v, v)

}