golang: can't execute t.execute - go

I'm trying to make an Handler to update one row each time getting data from a submitt button,
here is my code:
func RowHandler(res http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
http.ServeFile(res, req, "homepage.html")
return
}
Person_id := req.FormValue("Person_id")
stmt, err := db.Prepare("update Cityes set Status='right' where Person_id=?")
if err != nil {
log.Print("error ", err)
}
_, err = stmt.Exec(&Person_id)
t, err := template.ParseFiles("city_update.html") //hier i just want to show a text in html Page
if err != nil {
log.Fatal(err)
}
err = t.Execute(res, "/city_update")
}

Here instead of following
err = t.Execute(res, "/city_update")
pass data to be used to fill your template as send arguement to Execute not string. link to doc
For example .
err = t.Execute(res,struct{ID string}{Person_id})

Related

How can I resolve 400 status code by sending POST in Golang?

I have Python script, that works fine
def register():
url = prime_url + '/v2/mobile/user/register?lang=ru'
payload = {
'email' : 'test#test.test.mail.com',
'deviceId' : 'testId',
'password' : 'Test1234'
}
response = requests.post(url, data = payload)
print(response.text)
Response:
{"success":true,"data":"SUCCESS_FIRST_STAGE_REGISTER","params":"Two-factor authentication code sent to test#testtest.test.mail.com","code":200,"runTime":2.391624927520752}
I wrote code on Golang:
func postRequest(target string, params string) {
var jsonStr = []byte(`{"email":"testtestetetsees#mail.ru", "deviceId":"ftefst891", "password":"qwertyQwerty132"}`)
req, err := http.NewRequest("POST", target, bytes.NewBuffer(jsonStr))
if err != nil {
log.Fatalln(err)
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
fmt.Println(result)
}
Response:
map[code:400 data:ERROR_VALIDATE params:map[deviceId:[Device Id cannot be blank.] email:[Email cannot be blank.] password:[Password cannot be blank.]] runTime:0.023465871810913086 success:false]
I see that problem is by sending JSON string. What should I do?
As mentioned by Peter in the comments you can use PostForm once you convert the data into url.Values.
If the server expects content in urlencoded form but the input you have is json you'll have to convert it first.
var data = []byte(`{"email":"testtestetetsees#mail.ru", "deviceId":"ftefst891", "password":"qwertyQwerty132"}`)
m := map[string]string{}
if err := json.Unmarshal(data, &m); err != nil {
panic(err)
}
v := url.Values{}
for key, val := range m {
v.Add(key, val)
}
resp, err := http.PostForm("https://example.com", v)
if err != nil {
panic(err)
}
// ...
If the input you have is already in urlencoded form but it needs escaping you can parse it using url.ParseQuery and let the result of that do the escaping.
var data = "email=testtestetetsees#mail.ru&deviceId=ftefst891&password=qwertyQwerty132"
v, err := url.ParseQuery(data)
if err != nil {
panic(err)
}
resp, err := http.PostForm("https://example.com", v)
if err != nil {
panic(err)
}
// ...
Mention content type as "application/json"
For simplicity you can use http.Post, use the below code as a example:
resp, err := http.Post(target, "application/json", bytes.NewBuffer([]byte("{\"email\":\"testtestetetsees#mail.ru\", \"deviceId\":\"ftefst891\", \"password\":\"qwertyQwerty132\"}")))

Getting data from Firestore to display a go template file

How can I get the p.template from firestore, which is a string, into template.ParseFiles function? Is it possible to use the field value in the function to select the correct template file?
type Property struct {
Name string `firestore:"name"`
ApprovedOrigins []interface{} `firestore:"approvedOrigins"`
Template string `firestore:"selected"`
}
As you can see above the firestore field name is selected
func serveHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
ctx := context.Background()
client, err := firestore.NewClient(ctx, projectId)
if err != nil {
// TODO: Handle error.
log.Println("FIREBASE ERROR:", err)
}
// collection group query in firestore
q := client.CollectionGroup("data").Where("approvedOrigins", "array-contains", r.Host).Limit(1)
// iterate through the document query
iter := q.Documents(ctx)
defer iter.Stop()
for {
doc, err := iter.Next()
if err == iterator.Done {
break
}
if err != nil {
// TODO: Handle error.
log.Println("FIREBASE ERROR:", err)
}
fmt.Println("Database connected...")
var p Property
if err := doc.DataTo(&p); err != nil {
fmt.Println(err)
}
fmt.Println(p.Template) // This is not logging any data/string
t, _ := template.ParseFiles(p.Template + ".html")
fmt.Println(t.Execute(w, p)) //504 error happens here
}
}

How do I send an http post request with image and with some parameters in Go?

I am trying to make an http post request with image and parameters in the form-data, but when I am adding image, my parameters are lost.
testProduct := &Product{
Name: "TestProductName",
ImageExtension: "png",
}
var b bytes.Buffer
multipartWriter := multipart.NewWriter(&b)
multipartWriter.CreateFormFile("image", "../test.png")
multipartWriter.Close()
form = url.Values{}
form.Add("name", testProduct.Name)
form.Add("image_extension", testProduct.ImageExtension)
req, _ := http.NewRequest(http.MethodPost, "api/v1/admin/products/", &b)
req.PostForm = form
req.Header.Add("Authorization", "Bearer "+loginResponse.Token)
req.Header.Set("Content-Type", multipartWriter.FormDataContentType())
recorder := httptest.NewRecorder()
router.ServeHTTP(recorder, req)
But when the request handled the parameters doesn't bind:
https://i.imgur.com/JmT4qLh.png
This is the product struct:
type Product struct {
ID string `form:"id" json:"id"`
Name string `form:"name" json:"name"`
Price int64 `form:"price" json:"price"`
ImageExtension string `form:"image_extension" json:"image_extension"`
}
testProduct := &Product{
Name: "TestProductName",
ImageExtension: "png",
}
pr, pw := io.Pipe()
form := multipart.NewWriter(pw)
go func() {
defer pw.Close()
err := form.WriteField("name", testProduct.Name)
if err != nil {
return
}
err = form.WriteField("image_extension", testProduct.ImageExtension)
file, err := os.Open("a.png") // path to image file
if err != nil {
return
}
w, err := form.CreateFormFile("image", "sampleImageFileName.png")
if err != nil {
return
}
_, err = io.Copy(w, file)
if err != nil {
return
}
form.Close()
}()
r, err := http.NewRequest(http.MethodPost, "api/v1/admin/products/", pr)
if err != nil {
return
}
r.Header.Set("Content-Type", form.FormDataContentType())

Want to add a FormFile in unit test Golang

I want to test a httpRequest with a json body and a test file.
I don't know how to add the created test file to the request beside body json.
body := strings.NewReader(URLTest.RequestBody)
request, err := http.NewRequest(URLTest.MethodType, "localhost:"+string(listeningPort)+URLTest.URL, body)
if err != nil {
t.Fatalf("HTTP NOT WORKING")
}
fileBuffer := new(bytes.Buffer)
mpWriter := multipart.NewWriter(fileBuffer)
fileWriter, err := mpWriter.CreateFormFile("file", "testfile.pdf")
if err != nil {
t.Fatalf(err.Error())
}
file, err := os.Open("testfile.pdf")
if err != nil {
t.Fatalf(err.Error())
}
defer file.Close()
_, err = io.Copy(fileWriter, file)
if err != nil {
t.Fatalf(err.Error())
}
rec := httptest.NewRecorder()
UploadFiles(rec, request, nil)
response := rec.Result()
if response.StatusCode != URLTest.ExpectedStatusCode {
t.Errorf(URLTest.URL + " status mismatch")
}
responseBody, err := ioutil.ReadAll(response.Body)
defer response.Body.Close()
if err != nil {
t.Errorf(URLTest.URL + " cant read response")
} else {
if strings.TrimSpace(string(responseBody)) != URLTest.ExpectedResponseBody {
t.Errorf(URLTest.URL + " response mismatch - have: " + string(responseBody) + " want: " + URLTest.ExpectedResponseBody)
}
}
}
Can I add file as a value like request.FormFile.Add(...) or something?
Regarding your question about how to send a file in an HTTP request with Go, here's some sample code.
And you will need the mime/multipart package to build the form.
package main
import (
"bytes"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/http/httptest"
"net/http/httputil"
"os"
"strings"
)
func main() {
var client *http.Client
var remoteURL string
{
//setup a mocked http client.
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := httputil.DumpRequest(r, true)
if err != nil {
panic(err)
}
fmt.Printf("%s", b)
}))
defer ts.Close()
client = ts.Client()
remoteURL = ts.URL
}
//prepare the reader instances to encode
values := map[string]io.Reader{
"file": mustOpen("main.go"), // lets assume its this file
"other": strings.NewReader("hello world!"),
}
err := Upload(client, remoteURL, values)
if err != nil {
panic(err)
}
}
func Upload(client *http.Client, url string, values map[string]io.Reader) (err error) {
// Prepare a form that you will submit to that URL.
var b bytes.Buffer
w := multipart.NewWriter(&b)
for key, r := range values {
var fw io.Writer
if x, ok := r.(io.Closer); ok {
defer x.Close()
}
// Add an image file
if x, ok := r.(*os.File); ok {
if fw, err = w.CreateFormFile(key, x.Name()); err != nil {
return
}
} else {
// Add other fields
if fw, err = w.CreateFormField(key); err != nil {
return
}
}
if _, err = io.Copy(fw, r); err != nil {
return err
}
}
// Don't forget to close the multipart writer.
// If you don't close it, your request will be missing the terminating boundary.
w.Close()
// Now that you have a form, you can submit it to your handler.
req, err := http.NewRequest("POST", url, &b)
if err != nil {
return
}
// Don't forget to set the content type, this will contain the boundary.
req.Header.Set("Content-Type", w.FormDataContentType())
// Submit the request
res, err := client.Do(req)
if err != nil {
return
}
// Check the response
if res.StatusCode != http.StatusOK {
err = fmt.Errorf("bad status: %s", res.Status)
}
return
}
Hope you can use this in your unit test

How to get response with JWT in Golang

I'm trying get the response from an API that uses JSON Web token, I need use the header : {
Authorization: "Bearer token"
}
But I would like to keep the timeout of the http.Client that I'm using. How could I do it?
var myClient = &http.Client{Timeout: 10 * time.Second}
func getJson(url string, target interface{}) error {
r, err := myClient.Get(url)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
net/http.Request has a Header field that you can directly edit, but this means you can't use the shortcut client.Get method. Something more like:
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return err
}
req.Header = map[string][]string{
"Authorization": {fmt.Sprintf("Bearer %s", jwt)},
}
r, err := myClient.Do(req)
...
You could do something like this,
func getJson(url string, target interface{}) error {
req, err := http.NewRequest(http.MethodGet, url, nil)
if nil != err {
return err
}
r, err := myClient.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
Alternatively , you could also use context to control the request timeout
func getJsonWithContext(url string, target interface{}) error {
req, err := http.NewRequest(http.MethodGet, url, nil)
if nil != err {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second*1)
defer cancel()
reqWithContext := req.WithContext(ctx)
r, err := myClient.Do(reqWithContext)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}

Resources