Issues with transitioning from index html page to city html after user enters search critieria

I'm having issues with my route where the user enters their search and after pressing enter, the url changes but the redirect isnt happening. The content is displaying on the index.html page when it isn't suppose to. Here is a link to the github of the current standing of the project https://github.com/MD-2016/Weather-App/ There is also an issue with the http request with the log http: superfluous response.WriteHeader call from main.search (main.go:77) showing up. The issue is starting in main.go Thank you for your time looking into my issue 🙂
GitHub
GitHub - MD-2016/Weather-App: A weather app using a third party api...
A weather app using a third party api with the goal being a build upon project with additional features as time goes on. - GitHub - MD-2016/Weather-App: A weather app using a third party api with t...
174 Replies
ErickO
ErickO14mo ago
superfluous response.WriteHeader
this simply means that a response header has already been written and you're trying to re-write but that cannot be done don't use numbers for your status check, go has consts for that
MD
MD14mo ago
which part is being written twice?
package main

import (
"encoding/json"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/model"

"github.com/MD-2016/Weather-App/src/server/formatinput"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", search)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

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

weatherResponse := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

formattedCall := formatinput.FormatWeatherApiCall(userInput.UserInput)

resp, err := http.Get(formattedCall)

if err != nil {
log.Fatal(err)
return
}

if resp.StatusCode != 200 {
log.Fatal("unable to obtain forecast from weather api")
return
}

defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&weatherResponse); err != nil {
log.Fatal(err)
return
}

temp := template.Must(template.ParseFiles("./src/pages/city.html"))

temp.Execute(w, weatherResponse)

http.Redirect(w, r, "./src/pages/city.html", http.StatusOK)

}
package main

import (
"encoding/json"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/model"

"github.com/MD-2016/Weather-App/src/server/formatinput"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", search)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

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

weatherResponse := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

formattedCall := formatinput.FormatWeatherApiCall(userInput.UserInput)

resp, err := http.Get(formattedCall)

if err != nil {
log.Fatal(err)
return
}

if resp.StatusCode != 200 {
log.Fatal("unable to obtain forecast from weather api")
return
}

defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&weatherResponse); err != nil {
log.Fatal(err)
return
}

temp := template.Must(template.ParseFiles("./src/pages/city.html"))

temp.Execute(w, weatherResponse)

http.Redirect(w, r, "./src/pages/city.html", http.StatusOK)

}
ErickO
ErickO14mo ago
temp.Execute(w, weatherResponse) Execute applies a parsed template to the specified data object, writing the output to wr
MD
MD14mo ago
ah ok
ErickO
ErickO14mo ago
when you execute, that writes to your response writer
MD
MD14mo ago
thing is though how do I get the redirect to trigger after their search input? http://localhost:8080/search?searchBox=Lexington that's what the URL does and the page stays same doesnt go to city.html do I need a route for it too?
MD
MD14mo ago
No description
MD
MD14mo ago
instead it's inserting the code into my index.html page
ErickO
ErickO14mo ago
🤔 I'm not sure what setup you have or what you're trying to do, but why not redirect before executing the template
MD
MD14mo ago
I had it like that before and it didnt work removing the redirect actually removed the previous error
ErickO
ErickO14mo ago
why doesn't it work? do you not have a handler for the results of the search? I just don't know what you're trying to do
MD
MD14mo ago
so my goal is this.... 1. user enters their search request and hits enter 2. The api call is made and gets the request 3. The user is redirected to the page that displays the results of the call which is the data parsed onto the page (city.html) I made the needed struct to handle the json conversion I made a template on the city.html to display it
ErickO
ErickO14mo ago
why is the call made outside of the page tho? it should redirect, the handler get the searched city, make the call, parse the template, boom
MD
MD14mo ago
I just had a separate page to display the data and hourly and such and then the url would change over to that city
ErickO
ErickO14mo ago
your page should be dynamic in the sense that if a person simply goes to yourpage.com/search=nyc that works in your setup only if they use the search bar it works because the search is the one doing the call as opposed to the page requested
MD
MD14mo ago
oh what should I change then? I was trying to make in style like common weather websites do where you get redirected after search inpout *input
MD
MD14mo ago
The Weather Channel
National and Local Weather Radar, Daily Forecast, Hurricane and inf...
The Weather Channel and weather.com provide a national and local weather forecast for cities, as well as weather radar, report and hurricane coverage
ErickO
ErickO14mo ago
yeah but if you share the resulting url it works in your case it wouldn't
ErickO
ErickO14mo ago
The Weather Channel
Beverly Hills, CA Weather Forecast and Conditions - The Weather Cha...
Today’s and tonight’s Beverly Hills, CA weather forecast, weather conditions and Doppler radar from The Weather Channel and Weather.com
MD
MD14mo ago
oh 😦 im trying to avoid js for this project
ErickO
ErickO14mo ago
you don't need js your search bar is just...alone? /search is just the searchbar?
MD
MD14mo ago
yeah being backend project I didnt wanna build a lot because it isnt a full stack project yes did I do too much for this level of project?
ErickO
ErickO14mo ago
nah you have a couple of options for this
MD
MD14mo ago
im just happy I got as far as I have with what little time ive gotten lately
ErickO
ErickO14mo ago
you can dooooo hmmm well looking at what weather.com does you could prolly setup 2 handlers
MD
MD14mo ago
does my code look sloppy or more readable this time?
ErickO
ErickO14mo ago
one for /search and one for /search/{city} so the search handler renders the search bar and redirect to whatever search was done by the user and /search/nyc renders the page for new york city
MD
MD14mo ago
yeah that was my original goal but didnt know how to do it
ErickO
ErickO14mo ago
it looks fine,tho you're not always looking for errors
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
pretty sure this would work and from r.URL.Path you get the last bit of the url which should be the city
MD
MD14mo ago
hmm ok so I cut out code from the search
ErickO
ErickO14mo ago
🤔
MD
MD14mo ago
like the redirect and such
func searchHandler(w http.ResponseWriter, r *http.Request) {

weatherResponse := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

formattedCall := formatinput.FormatWeatherApiCall(userInput.UserInput)

resp, err := http.Get(formattedCall)

if err != nil {
log.Fatal(err)
return
}

if resp.StatusCode != 200 {
log.Fatal("unable to obtain forecast from weather api")
return
}

defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&weatherResponse); err != nil {
log.Fatal(err)
return
}

temp := template.Must(template.ParseFiles("./src/pages/city.html"))

temp.Execute(w, weatherResponse)

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

weatherResponse := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

formattedCall := formatinput.FormatWeatherApiCall(userInput.UserInput)

resp, err := http.Get(formattedCall)

if err != nil {
log.Fatal(err)
return
}

if resp.StatusCode != 200 {
log.Fatal("unable to obtain forecast from weather api")
return
}

defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&weatherResponse); err != nil {
log.Fatal(err)
return
}

temp := template.Must(template.ParseFiles("./src/pages/city.html"))

temp.Execute(w, weatherResponse)

}
ErickO
ErickO14mo ago
I have your gh repo no need to send code again
MD
MD14mo ago
my guess is return the weatherResponse to pass into the searchCityHandler
ErickO
ErickO14mo ago
the /search page only renders the searchbar and the searchbar redirects to the /search/los-angeles url no
MD
MD14mo ago
well in this case err
ErickO
ErickO14mo ago
your city handler makes the call, you do not get the api call from anywhere else all your searchbar should do is redirect to the correct page that is their whole job
MD
MD14mo ago
ah ok so take out that api call then
ErickO
ErickO14mo ago
yes and when the city page is requested it makes the call and renders the page with the data that's it
MD
MD14mo ago
ah so like this
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

http.Redirect(w, r, "./src/pages/city.html", http.StatusOK)

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

http.Redirect(w, r, "./src/pages/city.html", http.StatusOK)

}
ErickO
ErickO14mo ago
yeah, not sure about the url tho also the redirect func can only have 3xx codes so not statusok
The provided code should be in the 3xx range and is usually StatusMovedPermanently, StatusFound or StatusSeeOther.
MD
MD14mo ago
weird vscode shows 4 on hover over code int
MD
MD14mo ago
No description
ErickO
ErickO14mo ago
yes that's fine I didn't say remove it entirely just not the ok status code like... another code a 3xx code the ones that are for redirects you can't redirect and say "ok" that's not what that is for
MD
MD14mo ago
like 302 "found"
ErickO
ErickO14mo ago
you prolly want the "statusFound" yes
MD
MD14mo ago
sadly not sure how I handle the passing of the search bar input to the next route
ErickO
ErickO14mo ago
you grab the input redirect to search/{input} that's why I said I wasn't sure about the url
b1mind
b1mind14mo ago
URL === best state management
ErickO
ErickO14mo ago
nerd came in here just to say that
MD
MD14mo ago
hmm ok ill have to see but my go knowledge is limited so
b1mind
b1mind14mo ago
I did xD cause its important 😄
ErickO
ErickO14mo ago
pretty sure you just gotta http.Redirect(w, r, "/search/nyc", http.StatusFound) ofc the string gotta be dynamic but u get the point
MD
MD14mo ago
ah so in my case the "userinput.UserInput"
ErickO
ErickO14mo ago
ye
MD
MD14mo ago
might have to use fmt Sprintf that should do it
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)
}
now the challenge is getting that "city" result to the searchcityHandler this is how it looks so far
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/{city}", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

formattedCall := formatinput.FormatWeatherApiCall()

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)
}
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/{city}", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

formattedCall := formatinput.FormatWeatherApiCall()

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

tmpl.Execute(w, nil)

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)
}
just not sure how the searchBox input is going to the api call from /search to /search/{city} doesn't this code look fun B1? xD
b1mind
b1mind14mo ago
no and its why I pref file/folder based routing xD
MD
MD14mo ago
crap same issues are arising
2023/10/01 18:00:10 http: superfluous response.WriteHeader call from main.searchHandler (main.go:78)
2023/10/01 18:01:02 http: superfluous response.WriteHeader call from main.searchHandler (main.go:78)
2023/10/01 18:00:10 http: superfluous response.WriteHeader call from main.searchHandler (main.go:78)
2023/10/01 18:01:02 http: superfluous response.WriteHeader call from main.searchHandler (main.go:78)
url never changed over localhost:8080/search?searchBox=Lexington imagine your routing being messed up so the page you're suppose to go never happens and you end up in the same page but the html code from that page your suppose to go to is showing up in your current page basically inserting code into it because it can 😄
ErickO
ErickO14mo ago
first of all "/search/{city}" I don't think that does what you think it does
MD
MD14mo ago
yeah it's not
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/{city}", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "./src/pages/city.html", http.StatusFound)
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

fmt.Println(r.URL.Path)

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)

tmpl.Execute(w, nil)
}
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/{city}", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, "./src/pages/city.html", http.StatusFound)
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

fmt.Println(r.URL.Path)

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, city, http.StatusFound)

tmpl.Execute(w, nil)
}
ErickO
ErickO14mo ago
dat succs and also different usecase
MD
MD14mo ago
the other issue is the "/" route
ErickO
ErickO14mo ago
why would that be an issue
MD
MD14mo ago
because it's doing template processing too
b1mind
b1mind14mo ago
It's easy to know what does what where, also you can always hijack it in middleware to do hacky stuffs.
MD
MD14mo ago
2 routes doing same "execute" I thought the url redirection would trigger the "/search/{city}" search City Handler guess not 😄 it's probably something stupid it always is I guess the searchCityHandler route isn't triggering
b1mind
b1mind14mo ago
could it be because you are using the same route? both main and it or start rather?
MD
MD14mo ago
it probably doesn't know what {city} is in main
ErickO
ErickO14mo ago
first of all you need to understand how the pattern match works https://pkg.go.dev/net/http#ServeMux
MD
MD14mo ago
this is why I study languages and such in more depth so I understand the concepts more
ErickO
ErickO14mo ago
and again, /search/{city} doesn't do what you think it does you're matching the literal url page.com/search/{city} that is not a variable
MD
MD14mo ago
that's where im confused how to trigger the routes correctly and how they work main probably doesnt know what "city" is
ErickO
ErickO14mo ago
read
MD
MD14mo ago
ah r.URL.Path ?
ErickO
ErickO14mo ago
yes
MD
MD14mo ago
so this needs changed? http.HandleFunc("/search/{city}", searchCityHandler) I added this http.Redirect(w, r, r.URL.Path, http.StatusFound) so far the redirecting is failing
ErickO
ErickO14mo ago
what idk where or why you added this but no /search/ just that, that's your pattern
MD
MD14mo ago
so /search vs /search/
ErickO
ErickO14mo ago
you have a /search and a /search/ one goes to the main search page, the other goes to anything with a subpath AKA /search/nyc or /search/la
MD
MD14mo ago
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
ErickO
ErickO14mo ago
yes
MD
MD14mo ago
ok so when the user types enter after their input this is the route http://localhost:8080/search?searchBox=Lexington so this needs to become /search/Lexington but be city.html page
ErickO
ErickO14mo ago
I- I'm lost
MD
MD14mo ago
the redirect should happen as the last thing on the /search correct?
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

fmt.Println(r.URL.Path)

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
//r.URL.Path = "./src/pages/city.html"

http.Redirect(w, r, r.URL.Path, http.StatusFound)

tmpl.Execute(w, nil)
}
package main

import (
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"

"github.com/MD-2016/Weather-App/src/server/formatinput"
"github.com/MD-2016/Weather-App/src/server/model"
)

type FormInput struct {
UserInput string
}

func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

fmt.Println(r.URL.Path)

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("searchBox"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
//r.URL.Path = "./src/pages/city.html"

http.Redirect(w, r, r.URL.Path, http.StatusFound)

tmpl.Execute(w, nil)
}
there's just something here im not doing correctly I think searchCityHandler is ok it's searchHandler something isn't going right either I get errors about the redirect from firefox not working correctly or it doesnt happen sadly debugging tool on vscode isnt working properly sorry im not understanding well Erick. This is new territory for me
ErickO
ErickO14mo ago
hmmmm thinking
MD
MD14mo ago
StackHawk
Golang Open Redirect Guide: Examples and Prevention
An explanation of Golang open redirect vulnerabilities with a few examples of risky code and how to fix it.
ErickO
ErickO14mo ago
that's not relevant ok how about I make this easier what is your main page?
MD
MD14mo ago
the index.html was trying this too http.Redirect(w, r, "localhost:8080/search/", http.StatusFound)
ErickO
ErickO14mo ago
don't do absolute paths ok let's ditch the subpaths let's make it easier and use queries here's the basic idea read this carefully you will have one handler for the /search page, you are going to check for queries using the r.URL.Query().Get("city") method, IF there is no query that means it is either an invalid query or just the base page /search so all you need to do is render the input and absolutely nothing else, your input is going to make a GET request something like:
<h1>City Search</h1>
<form action="/search" method="GET">
<label for="city">Enter a city:</label>
<input type="text" id="city" name="city" placeholder="City" required />
<input type="submit" value="Search" />
</form>
<h1>City Search</h1>
<form action="/search" method="GET">
<label for="city">Enter a city:</label>
<input type="text" id="city" name="city" placeholder="City" required />
<input type="submit" value="Search" />
</form>
when the user submits this the form will make a GET request that looks like: /search?city=new+york, THEN the EXACT SAME handler will be called but this time using r.URL.Query().Get("city") you WILL have a valid query, at that point you make whatever API call you need to make and return the page that renders the results of said input.
MD
MD14mo ago
this makes me sad but ill try it
ErickO
ErickO14mo ago
huh but like...why
MD
MD14mo ago
yeah the searchBox is the name of the input on index.html
ErickO
ErickO14mo ago
what?
MD
MD14mo ago
<form action="/search" method="get" class="search">
<input type="search" name="searchBox" id="searchBox">
</form>
<form action="/search" method="get" class="search">
<input type="search" name="searchBox" id="searchBox">
</form>
ErickO
ErickO14mo ago
well that's a bad name cause it tells you nothing about what the input is for the a11y tree also takes this name into account if there's no label also I did type="text" but a type of search is better for this input
MD
MD14mo ago
this all ive done so far
func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
//http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}
func main() {

// get the user input

// validate the user input

// format the api request

// get return object

// display results on city page
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
//http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)
}

func start(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
tmpl.Execute(w, nil)
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, , http.StatusFound)

tmpl.Execute(w, nil)
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

http.Redirect(w, r, , http.StatusFound)

tmpl.Execute(w, nil)
}
so change the /search to r.URL.Query().Get("city") ?
ErickO
ErickO14mo ago
uh you don't have to parse the form only get the query on the url no redirect needed either
MD
MD14mo ago
so where does the data go? city.html is useless? at this point im just lost
ErickO
ErickO14mo ago
think what you get from the query?
MD
MD14mo ago
idk I havent figured out how to use the query yet googling it
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
//userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))
userInput.UserInput = template.HTMLEscapeString(r.URL.Query().Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
tmpl.Execute(w, nil)
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
//userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))
userInput.UserInput = template.HTMLEscapeString(r.URL.Query().Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
tmpl.Execute(w, nil)
}
might just write the function inside main
ErickO
ErickO14mo ago
what are you parsing the form for which form even I ask again, what info do you get from the query?
MD
MD14mo ago
idk anymore
ErickO
ErickO14mo ago
man go take a break
MD
MD14mo ago
I was confused with the routes now with the query im lost
b1mind
b1mind14mo ago
This is where I would just look at any tutorial that has routing and learn from it then put the logic in your project
MD
MD14mo ago
this is what im currently getting without the query http://localhost:8080/search?city=Lexington
ErickO
ErickO14mo ago
do you understand what a url query is?
MD
MD14mo ago
inserted elements into a url? to help filter and such
ErickO
ErickO14mo ago
ok show me a query
b1mind
b1mind14mo ago
https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams Its just a key:value pair MD ?key=value thats it
MD
MD14mo ago
sorry my mind is toast
b1mind
b1mind14mo ago
So in Go you should be able to use the r.URL.Query().Get("city") or what ever to get ?city=
MD
MD14mo ago
I get that but im not seeing where I put that code not in "/search" but I guess in searchHandler
b1mind
b1mind14mo ago
right but in /search/ cause you would have search/?city=value I don't like that mehtod but its what Erick was leading you to so I don't wanna deviate
ErickO
ErickO14mo ago
ofc in the handler
b1mind
b1mind14mo ago
typically I would have it without trailing slase
ErickO
ErickO14mo ago
what method would you use? oh no trailing slash needed
b1mind
b1mind14mo ago
but you would needf to havea different /search for home
ErickO
ErickO14mo ago
/search is fine
MD
MD14mo ago
sorry had to get bug spray some files are annoying me ok
ErickO
ErickO14mo ago
ok what md walk me through your ideas
MD
MD14mo ago
here's what i got so far in main.go in the main function
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)

}
http.HandleFunc("/", start)
styles := http.FileServer(http.Dir("./src/assets/styles"))
http.Handle("/styles/", http.StripPrefix("/styles/", styles))
http.HandleFunc("/search", searchHandler)
http.HandleFunc("/search/", searchCityHandler)
http.ListenAndServe(":8080", nil)

}
so as b1 stated the /search/ is dealing with r.URL.Query().Get() since the query is search?city="some city" so to start am i dumping the searchCityHandler? this is the code for the two handlers
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

//city := fmt.Sprintf("/search/%s", userInput.UserInput)
tmpl.Execute(w, nil)
}

func searchCityHandler(w http.ResponseWriter, r *http.Request) {
weatherRes := model.Weather{}
tmpl := template.Must(template.ParseFiles("./src/pages/city.html"))

formattedCall := formatinput.FormatWeatherApiCall(r.URL.Path)

res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}
so my questions are the following is the searchCityHandler inside the HandleFunc changing? is the r.Form.Get inside searchHandler changing?
ErickO
ErickO14mo ago
NOOOOOO read carefully for the love of god, you miss half my messages
b1mind
b1mind14mo ago
I didn't state that you did I just repeated it (from what you had in your code) xD which is also why I said I wouldn't do it that way with a trailing slash
ErickO
ErickO14mo ago
I said /search is fine, I stated already that we would have ONE handler and I told you what that handler would do so re-read you have 1 page, MD /search and there is 2 possible states... no query page.com/search and query page.com/search?city=new+york so you handle both cases in 1 handler if there's no query what is it then? just the search page! if there's a query what is it? the results (either good results or 404) but the results!
MD
MD14mo ago
ok
ErickO
ErickO14mo ago
so you need to check what to know which of the 2 states it is in?
MD
MD14mo ago
so empty or non empty query would it be empty string or nil?
ErickO
ErickO14mo ago
empty string
MD
MD14mo ago
so this?
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

if r.URL.Query().Get("city") == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(r.URL.Query().Get("city"))
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

r.ParseForm()
var userInput FormInput
userInput.UserInput = template.HTMLEscapeString(r.Form.Get("city"))

if r.URL.Query().Get("city") == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(r.URL.Query().Get("city"))
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

tmpl.Execute(w, weatherRes)
}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
ErickO
ErickO14mo ago
only errors and pointers can be nil and since it returns a string it'll be empty if nothing is found you're still parsing the form for no reason, what is that parse for?
MD
MD14mo ago
it was the only code parsing before sorry
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

if r.URL.Query().Get("city") == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(r.URL.Query().Get("city"))
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))

if r.URL.Query().Get("city") == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(r.URL.Query().Get("city"))
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
ErickO
ErickO14mo ago
if r.URL.Query().Get("city") == "" formatinput.FormatWeatherApiCall(r.URL.Query().Get("city")) just save that in a variable don't check twice anyway yes
MD
MD14mo ago
could you please explain that again sorry
ErickO
ErickO14mo ago
you are calling the same method twice one for the if and another time for your FormatWeatherAPICall function just save it in a variable
func searchHandler(w http.ResponseWriter, r *http.Request) {
city := r.URL.Query().Get("city")

if city == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(city)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
city := r.URL.Query().Get("city")

if city == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(city)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

}
MD
MD14mo ago
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
inputToParse := r.URL.Query().Get("city")
if inputToParse == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(inputToParse)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
inputToParse := r.URL.Query().Get("city")
if inputToParse == "" {

} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(inputToParse)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
oh ok I wish I could redirect though because all my templating is on the city.html that's where I have the display setup for the response with tables and such I guess I could copy and paste into index should I do a 404 or something for empty? weird I got EOF this here hit EOF
if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}
if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}
looks like the url is formatted correctly but the response is EOF err is EOF
ErickO
ErickO14mo ago
EOF is end of function Check parentheses and stuff I come back to this later
MD
MD14mo ago
closing up for the night let's try this again tomorrow night or something been running checks on the request and it gets a status 200 not finding the EOF yet I did take a sample request from the website api explorer and took a json result and had a tool convert my json to the appropriate go struct to handle it and it matched according to my error checking with println's, the error is happening in the Decoder for the JSON
&{200 OK 200 HTTP/2.0 2 0 map[Age:[0] Cache-Control:[public, max-age=180] Cdn-Cache:[EXPIRED] Cdn-Cachedat:[10/02/2023 22:11:22] Cdn-Edgestorageid:[1070] Cdn-Proxyver:[1.04] Cdn-Pullzone:[93447] Cdn-Requestcountrycode:[US] Cdn-Requestid:[cce19e02e9132670a94c45b96b6586de] Cdn-Requestpullcode:[200] Cdn-Requestpullsuccess:[True] Cdn-Status:[200] Cdn-Uid:[8fa3a04a-75d9-4707-8056-b7b33c8ac7fe] Content-Type:[application/json] Date:[Mon, 02 Oct 2023 22:11:22 GMT] Server:[BunnyCDN-IL1-1069] Vary:[Accept-Encoding] Via:[1.1 varnish (Varnish/6.0)] X-Varnish:[963416183] X-Weatherapi-Qpm-Left:[999987]] 0xc0001ca0f0 -1 [] false true map[] 0xc0000ec100 0xc0000c6420}
<nil>
&{200 OK 200 HTTP/2.0 2 0 map[Age:[0] Cache-Control:[public, max-age=180] Cdn-Cache:[EXPIRED] Cdn-Cachedat:[10/02/2023 22:11:22] Cdn-Edgestorageid:[1070] Cdn-Proxyver:[1.04] Cdn-Pullzone:[93447] Cdn-Requestcountrycode:[US] Cdn-Requestid:[cce19e02e9132670a94c45b96b6586de] Cdn-Requestpullcode:[200] Cdn-Requestpullsuccess:[True] Cdn-Status:[200] Cdn-Uid:[8fa3a04a-75d9-4707-8056-b7b33c8ac7fe] Content-Type:[application/json] Date:[Mon, 02 Oct 2023 22:11:22 GMT] Server:[BunnyCDN-IL1-1069] Vary:[Accept-Encoding] Via:[1.1 varnish (Varnish/6.0)] X-Varnish:[963416183] X-Weatherapi-Qpm-Left:[999987]] 0xc0001ca0f0 -1 [] false true map[] 0xc0000ec100 0xc0000c6420}
<nil>
so im not sure what's going on here 🤷‍♂️ yep just did a a response check and it came back 200 as the status code
ErickO
ErickO14mo ago
wtf is this supposed to be
MD
MD14mo ago
so something isnt right either on the close or decoding but when I was doing the decoding and placed a print statement inside the if for decode, it came back as EOF that's a response print so my api call is correct getting a 200
ErickO
ErickO14mo ago
that is not json my brother in christ if you're trying to decode that it will fail
MD
MD14mo ago
ik it's the result of the http.Get call but the status code of 200 is a good sign
ErickO
ErickO14mo ago
no it isn't just like you tried to set a redirect to 200 because you don't know much about http codes, the same can happen with anyone for all you know the code 200 and the returned json is {error: "bad response} because people make shitty APIs check the payload no the response
MD
MD14mo ago
so how do find where the EOF is happening
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
inputToParse := r.URL.Query().Get("city")
if inputToParse == "" {
return
} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(inputToParse)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

fmt.Println(res.StatusCode)
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

//fmt.Print(err)

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
func searchHandler(w http.ResponseWriter, r *http.Request) {
//tmpl := template.Must(template.ParseFiles("./src/pages/index.html"))
inputToParse := r.URL.Query().Get("city")
if inputToParse == "" {
return
} else {
weatherRes := model.Weather{}
formattedCall := formatinput.FormatWeatherApiCall(inputToParse)
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}

fmt.Println(res.StatusCode)
defer res.Body.Close()

if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
log.Fatal(err)
return
}

//fmt.Print(err)

}

//city := fmt.Sprintf("/search/%s", userInput.UserInput)

}
couldnt get debug to work on the searchHandler function only on main
ErickO
ErickO14mo ago
ok there's a few things wrong here
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
res, err := http.Get(formattedCall)

if res.StatusCode != 200 {
log.Fatal(err)
return
}
this makes 0 sense how are you gonna check for res and not err but log err? for all you know err is empty and you will log nothing
MD
MD14mo ago
just change to err != nil?
ErickO
ErickO14mo ago
ideally check both err and status code and I told you this yesterday, don't use numbers for the status codes there are constants for that if res.StatusCode != 200 { bad
MD
MD14mo ago
StatusAccepted?
ErickO
ErickO14mo ago
if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil { if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil { this is your issue no statusok learn http codes
if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
if err := json.NewDecoder(r.Body).Decode(&weatherRes); err != nil {
take a look at this slowly what are you decoding here?
MD
MD14mo ago
my goal is to decode the returned json into my struct
ErickO
ErickO14mo ago
and what are you actually decoding here? look at it carefully
MD
MD14mo ago
empty body?
ErickO
ErickO14mo ago
nope what variable is that? where is r coming from?
MD
MD14mo ago
😄 should be res
ErickO
ErickO14mo ago
yup
MD
MD14mo ago
res.Body ok now I need to display that on the page or trigger a route since page went blank after got a return
29.4
84.9
//cdn.weatherapi.com/weather/64x64/day/113.png
Sunny
29.4
84.9
//cdn.weatherapi.com/weather/64x64/day/113.png
Sunny
ErickO
ErickO14mo ago
and that's uh... expected? idk what the response should look like
MD
MD14mo ago
yeah for my api call
ErickO
ErickO14mo ago
ok
MD
MD14mo ago
I just need to parse that into the webpage
ErickO
ErickO14mo ago
then all you have left is actually rendering stuff to the screen yup
MD
MD14mo ago
so after my input, the screen goes blank so I need to do another route?
ErickO
ErickO14mo ago
you just need to parse a template same as with the other routes but passing your data
MD
MD14mo ago
MD
MD14mo ago
so does the /search need to change to /search/
ErickO
ErickO14mo ago
we've been over this no that handler will parse both templates just a matter of which part of the if you're in
MD
MD14mo ago
yeah but im not sure about something
ErickO
ErickO14mo ago
which is...
MD
MD14mo ago
No description
MD
MD14mo ago
im not sure how to bring back the page to display the data since this a blank page on the route already have rendering setup in the html
ErickO
ErickO14mo ago
exact same thing you were doing already you parse and execute a template
MD
MD14mo ago
ill see how it goes
Want results from more Discord servers?
Add your server