Clearing out Previous Request RESTFul with Go(Golang)? - rest

I've created a RESTFul API via golang.
The Issue is that when I send a /product request I will be given the result in json and when I repeat this request the result will append prevoius.
I want to clear the REST data buffer and whenever I send a request, API send me fresh data, not with prevoius. What should I do?
Route Handler
func main() {
router := mux.NewRouter()
router.HandleFunc("/product", GetProductInfo).Methods("GET")
log.Printf("Listenning on Port %s ...\n", PORT)
log.Fatal(http.ListenAndServe(PORT, router))
}
Request Handler
type ProductOut struct {
ID int `json:"id,omitempty"`
Title string `json:"title,omitempty"`
Description string `json:"description,omitempty"`
Price string `json:"price,omitempty"`
Location string `json:"location,omitempty"`
Created_at string `json:"created_at,omitempty"`
Images []string `json:"images,omitempty"`
}
var product_out []ProductOut
func GetProductInfo(w http.ResponseWriter, r *http.Request) {
db_select_products := db.SelectProducts() // Gets data from database
var out ProductOut
for _, ele := range db_select_products {
out.ID = contentGetFieldInteger(ele, "out_id") // A method for getting integer from struct field
out.Title = contentGetFieldString(ele, "out_title") // A method for getting string from struct field
out.Description = contentGetFieldString(ele, "out_description")
out.Price = contentGetFieldString(ele, "out_price")
out.Location = contentGetFieldString(ele, "out_location")
out.Created_at = contentGetFieldString(ele, "out_created_at")
db_select_image := db.SelectImages(out.ID) // Gets another data from database
for _, imele := range db_select_image {
out.Images = append(out.Images, imageGetFieldString(imele, "out_path"))
fmt.Println(out.Images)
}
product_out = append(product_out, out)
out.Images = nil
}
json.NewEncoder(w).Encode(product_out)
}

You are declaring this as a global variable in your package:
var product_out []ProductOut
That way, the slice is just created once, and you are sharing it between requests.
If you want to declare a new slice for each request, you should move that line inside your GetProductInfo function.

Related

Golang serialize form-urlencoded to object

I've made a post request where I'm sending data as JSON and this code creates a new row in the DB.
json.NewDecoder(r.Body).Decode(&user)
DB.Create(&user)
json.NewEncoder(w).Encode(user)
But parsing the form data shows this error
I figured this is how I would read every individual value
for key, value := range r.PostForm {
fmt.Printf("Key:%s, Value:%s\n", key, value)
}
My model looks like this
type User struct {
gorm.Model
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
Email string `json:"email"`
}
How would I convert this to user and insert to DB?
Another way to do it (a bit overengineered, better to use r.FormValue), without having to type the fields again, such as r.FormValue("firstname"), etc if you already know the data, types etc.
func handleUser(w http.ResponseWriter, r *http.Request) {
user := User{}
userType := reflect.TypeOf(user)
for i := 0; i < userType.NumField(); i++ {
// Get the JSON tag of the field, use it for the r.FormValue
f := userType.Field(i).Tag.Get("json")
if f != "" {
reflect.ValueOf(&user).Elem().FieldByName(
userType.Field(i).Name).SetString(r.FormValue(f))
}
}
// DB.Create(&user) need a reference to DB here.
json.NewEncoder(w).Encode(user)
}
Note: This is just an example that will work for string fields, may panic otherwise because it's calling SetString. Additionally, a field may not exist and could panic when trying to access it in the FieldByName(..., but I think your question was geared to this direction of not having to type each field, so leaving it as an example.
The right way to do it, as Cerise Limón pointed out, would be
func handleUser(w http.ResponseWriter, r *http.Request) {
user := User{}
user.FirstName = r.FormValue("firstname")
user.LastName = r.FormValue("lastname")
user.Email = r.FormValue("email")
// DB.Create(&user) need a reference to DB here.
json.NewEncoder(w).Encode(user)
}
Note that you can also add a method for populating the user with the form if you do this in several places, for example
func (u *User) setFormData(r *http.Request) {
u.FirstName = r.FormValue("firstname")
u.LastName = r.FormValue("lastname")
u.Email = r.FormValue("email")
}
And then use it like this
func handleUser(w http.ResponseWriter, r *http.Request) {
user := User{}
user.setFormData(r)
// DB.Create(&user)
json.NewEncoder(w).Encode(user)
}

Omitempty in struct not omitting

I'm trying to store data to MongoDB without sending null data. The Struct in question is Poll and Question. Incoming data can range from have 2 questions, to 5. So if a user only enters 2 questions I wont have a need to use the 3 other fields in Poll struct. Id rather have the fields not appear at all than send null data to the server.
package main
// Omit Empty not working
type Poll struct {
Id bson.ObjectId `bson:"_id"`
Quest0 *Question `json:"quest0,omitempty"`
Quest1 *Question `json:"quest1,omitempty"`
Quest2 *Question `json:"quest2,omitempty"`
Quest3 *Question `json:"quest3,omitempty"`
Quest4 *Question `json:"quest4,omitempty"`
Quest5 *Question `json:"quest5,omitempty"`
}
type Question struct {
Count *int `json:"count,omitempty"`
Question *string `json:"question,omitempty"`
}
type ReceivedPoll struct {
Quest0 string `db:"quest0"`
Quest1 string `db:"quest1"`
Quest2 string `db:"quest2"`
Quest3 string `db:"quest3"`
Quest4 string `db:"quest4"`
Quest5 string `db:"quest5"`
}
func main() {
fmt.Println("server running...")
router := httprouter.New()
router.POST("/api/create", api)
router.NotFound = http.FileServer(http.Dir("./public"))
log.Fatal(http.ListenAndServe(":5000", router))
}
func api(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
w.Header().Set("Content-type", "application/json")
session, err := mgo.Dial(mkey)
if err != nil {
panic(err)
}
defer session.Close()
fmt.Println("is this running?")
switch r.URL.String() {
case "/api/create":
// LOOK HERE
poll := &Poll{}
json.NewDecoder(r.Body).Decode(&poll)
poll.Id = bson.NewObjectId()
fmt.Println(*poll)
c := session.DB("abase").C("polls")
err = c.Insert(*poll)
if err != nil {
fmt.Println(err)
}
rz, _ := json.Marshal(poll.Id)
w.Write(rz)
}
}
Add the bson key used by the mgo BSON encoder. The encoder ignores the json key. See bson.Marshal documentation for the details.
type Poll struct {
Id bson.ObjectId `bson:"_id"`
Quest0 *Question `json:"quest0,omitempty" bson:"ques0:omitempty"`
...

Go optional fields with SQLX

I'm learning Go and am trying to create an api endpoint that has an 'fields' parameter. When I try to scan the sqlx resulting rows it into a struct,however the fields omitted by the user are being returned as as an empty string. Is there a way that I can change the struct to reflect only the fields that the user passed? I don't think I want to use omitempty in case for example user_name is an empty string.
type User struct {
Id int `db:"id"`
UserName string `db:"user_name"`
}
func GetUsers(w http.ResponseWriter,r *http.Request,db *sqlx.DB) {
acceptedFields := map[string]bool {
"id":true,
"user_name":true,
}
var requestedFields string = "id"
if r.URL.Query().Get("fields") != ""{
requestedFields = r.URL.Query().Get("fields");
}
for _, requestedField := range strings.Split(requestedFields,",") {
if !acceptedFields[requestedField] {
http.Error(w, fmt.Sprintf("Unknown Field '%s'",requestedField), http.StatusBadRequest)
}
}
users := []User{}
err := db.Select(&users,fmt.Sprintf("SELECT %s FROM users",requestedFields));
if err != nil {
log.Fatal(err)
}
response, _ := json.Marshal(users)
fmt.Fprintf(w,string(response))
}
Resulting Endpoint Output
/users?fields=id => [{"Id":12,"UserName":""}]
Desired Endpoint Output
/users?fields=id => [{"Id":12}]
Also using sql.NullString results in this:
[{"Id":12,"UserName":{"String":"","Valid":false}}]
Thanks to mkorpriva here is a solution
type User struct {
Id int `db:"id"`
UserName *string `db:"user_name" json:",omitempty"`
}

How do I place the AVG of a row into a new column?

Hey everyone I am using golang to build a super simple API. I have this json data being passed from a POST request and being stored in my DB. I would like to take the tts data which is an integer array and average that array and place it in the ttc column and return that number on the json response. I am having a hard time doing that any help would be greatly appreciated. My source code is below as well as my DB Model. I know I would have to use the AVG() function somehow in postgres but I am brand new to postgres so I am super confused.
main.go
package main
import (
"encoding/json"
"github.com/gorilla/mux"
"github.com/jinzhu/gorm"
"github.com/lib/pq"
"github.com/rs/cors"
"log"
"net/http"
_ "github.com/jinzhu/gorm/dialects/postgres"
)
type Resource struct {
gorm.Model
Name string
TTS pq.Int64Array `gorm:"type:integer[]"`
TTC int
}
var db *gorm.DB
var err error
func main() {
router := mux.NewRouter()
db, err = gorm.Open(
"postgres",
"host=localhost"+" user=postgres"+
" dbname=Shoes"+" sslmode=disable password=root")
if err != nil {
panic("failed to connect database")
}
defer db.Close()
db.AutoMigrate(&Resource{})
router.HandleFunc("/resources", GetResources).Methods("GET")
router.HandleFunc("/resources/{id}", GetResource).Methods("GET")
router.HandleFunc("/resources", CreateResource).Methods("POST")
router.HandleFunc("/resources/{id}", DeleteResource).Methods("DELETE")
handler := cors.Default().Handler(router)
log.Fatal(http.ListenAndServe(":8080", handler))
}
func GetResources(w http.ResponseWriter, r *http.Request) {
var resources []Resource
db.Find(&resources)
json.NewEncoder(w).Encode(&resources)
}
func GetResource(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var resource Resource
db.First(&resource, params["id"])
json.NewEncoder(w).Encode(&resource)
}
func CreateResource(w http.ResponseWriter, r *http.Request) {
var resource Resource
json.NewDecoder(r.Body).Decode(&resource)
db.Create(&resource)
json.NewEncoder(w).Encode(&resource)
}
func DeleteResource(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var resource Resource
db.First(&resource, params["id"])
db.Delete(&resource)
var resources []Resource
db.Find(&resources)
json.NewEncoder(w).Encode(&resources)
}
I am thinking I could do something like
db.Select("AVG(tts)")
I am just not sure how to put that result in the column ttc
Since the json of the post request already contains the tts_data, you can get the average before setting it in the database
sum := 0
for _, i := range tts_data {
sum += i
}
avg := sum / len(tts_data)
// save the data in your db
rs := Ressource{Name: "name", TTS: tts_data, ttc: avg}
b := db.Create(&rs)
if b {
// send all the resource
json.NewEncoder(w).Encode(&rs)
// or send only the avg
json.NewEncoder(w).Encode(struct{avg: int}{avg: avg})
} else {
// handle error
}

Google App Engine Go PostForm not sending any url.Values?

I have a simple function in GAE golang:
func Call(c appengine.Context, guid string, function string, parameters map[string]string) string {
client:=urlfetch.Client(c)
values := url.Values{}
c.Infof("%v", parameters)
for k, v := range parameters {
values.Set(k, v)
}
c.Infof("%v", values)
resp, err:=client.PostForm("https://blockchain.info/merchant/"+guid+"/"+function, values)
var answer string
if err != nil {
c.Errorf("BlockchainAPI post error: %s", err)
}
c.Infof("%v", resp.Request.PostForm)
[...]
I get these printouts:
2013/10/14 23:17:51 INFO: map[main_password:password]
2013/10/14 23:17:51 INFO: map[main_password:[password]]
2013/10/14 23:17:52 INFO: https://blockchain.info/merchant/guid/function
2013/10/14 23:17:52 INFO: map[]
It looks as if client.PostForm does not pass values to the request and not get them back in response. What can be causing this error?
`client.PostForm` uses the body not the request.PostForm values.
It says so in the [documentation][1] :
// PostForm contains the parsed form data from POST or PUT
// body parameters.
// This field is only available after ParseForm is called.
// The HTTP client ignores PostForm and uses Body instead.
PostForm url.Values
So your code needs to change from:
c.Infof("%v", resp.Request.PostForm)
To something like this (I haven't tested it for accuracy in the string handling):
bd, _ := ioUtil.ReadAll(resp.Body)
c.Infof("%v", string(bd[:len(bd)])