I'm new to Go. I'm trying to build a simple app that lets users get photos from flickr by keying in a tag in a form. I'm stuck at my current code (pasted below) as nothing appears on the page /showimage when I click on the submit button. What am I doing wrong in the code?
package main
import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
)
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/showimage", showimage)
fmt.Println("listening...")
err := http.ListenAndServe(GetPort(), nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func GetPort() string {
var port = os.Getenv("PORT")
if port == "" {
port = "4747"
fmt.Println("INFO: No PORT environment variable detected, defaulting to " + port)
}
return ":" + port
}
func handler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, rootForm)
}
const rootForm =
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Flickr photos</title>
</head>
<body>
<h1>Flickr photos</h1>
<p>Find photos by tags!</p>
<form action="/showimage" method="post" accept-charset="utf-8">
<input type="text" name="str" value="Type Tags..." id="str">
<input type="submit" value=".. and see the images!">
</form>
</body>
</html>`
var upperTemplate = template.Must(template.New("showimage").Parse(upperTemplateHTML))
func showimage(w http.ResponseWriter, r *http.Request) {
tag := r.FormValue("str")
safeTag := url.QueryEscape(tag)
apiKey := "MYAPIKEY"
fullUrl := fmt.Sprintf("https://api.flickr.com/services/rest/?method=flickr.people.getPhotos&api_key=%s&tags=%s", apiKey, safeTag)
client := &http.Client{}
req, err := http.NewRequest("GET", fullUrl, nil)
if err != nil {
log.Fatal("NewRequest: ", err)
return
}
resp, requestErr := client.Do(req)
if requestErr != nil {
log.Fatal("Do: ", requestErr)
return
}
defer resp.Body.Close()
body, dataReadErr := ioutil.ReadAll(resp.Body)
if dataReadErr != nil {
log.Fatal("ReadAll: ", dataReadErr)
return
}
res := make(map[string]map[string]map[string]interface{}, 0)
json.Unmarshal(body, &res)
owner, _ := res["photos"]["photo"]["owner"]
id, _ := res["photos"]["photo"]["id"]
queryUrl := fmt.Sprintf("http://flickr.com/photos/%s/%s", owner, id)
tempErr := upperTemplate.Execute(w, queryUrl)
if tempErr != nil {
http.Error(w, tempErr.Error(), http.StatusInternalServerError)
}
}
const upperTemplateHTML =
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Display images</title>
</head>
<body>
<h3>Images</h3>
<img src="{{html .}}" alt="Image" />
</body>
</html>`
Two things:
1) http.HandleFunc("showimage", showimage) should be http.HandleFunc("/showimage", showimage)
2) MYAPIKEY is probably not a valid api key.
Related
I wrote code in golango to connect to the database on the server and output the contents of the tables to the website. I also wrote code for the html output of the table. There are no problems and it connects, but the error "404 page not found" lights up on the web page. What is this error and what is the reason? This is the first time I've seen this
package main
import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"html/template"
_ "log"
"net/http"
)
type Жанр struct {
idЖанр int
Название_жанра string
}
var database *sql.DB
func home_db(w http.ResponseWriter, r *http.Request) {
rows, err := database.Query("select * from newbd.Жанр")
if err != nil {
panic(err)
}
defer rows.Close()
ganr := []Жанр{}
for rows.Next() {
p := Жанр{}
err = rows.Scan(&p.idЖанр, &p.Название_жанра)
if err != nil {
panic(err)
continue
}
ganr = append(ganr, p)
}
tmpl, _ := template.ParseFiles("home.html")
tmpl.Execute(w, ganr)
}
func main() {
db, err := sql.Open("mysql", "xxxxx:xxxxxx#tcp(xx.xx.xxx.xxx:xx)/xxxxx")
if err != nil {
panic(err)
}
defer db.Close()
fmt.Println("OK")
http.HandleFunc("/dat/", home_db)
http.ListenAndServe(":8100", nil)
}
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RUMP</title>
</head>
<body>
<table>
<thead>
<th>idЖанр</th>
<th>Название_жанра</th>
</thead>
{{range . }}
<li>
<td>{{.idЖанр}}</td>
<td>{{.Название_жанра}}</td>
</li>
{{.end}}
</table>
</body>
</html>
I have created a simple scraper that takes the top 10 news from a website and returns a JSON with the title and the score. I want to pass the title and the score as HTML template so I can generate a webpage. I'm not familiar with the templating Go language and I don't know how to pass the values for each of the links. Here is the HTML code that I should use and my implementation for now:
<!DOCTYPE html>
<html>
<head><linkrel="stylesheet" href="https://unpkg.com/mvp.css"
/>
</head>
<body>
<h1>{{.PageTitle}}</h1>
<ul>
{{range .Links}}
<li>{{.Title}}: {{.Score}}</li>
{{end}}
</ul>
</body>
</html>
My code:
package main
import (
"encoding/json"
"html/template"
"log"
"net/http"
"strconv"
)
type TopStories struct {
Title string `json:"title"`
Score int `json:"score"`
}
type TopStoriesPayload struct {
TopStories []TopStories
}
type NewsScraper struct {
url string
Data []TopStories
}
type templateData struct {
PageTitle string
Data []TopStories
}
func NewNewsScraper(url string) *NewsScraper {
return &NewsScraper{url: url}
}
func Top10Stories() []string {
req, err := http.NewRequest("GET", "https://hacker-news.firebaseio.com/v0/topstories.json", nil)
if err != nil {
log.Fatal(err)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
var IDs []int
json.NewDecoder(resp.Body).Decode(&IDs)
IDs = IDs[:10]
var IDsString []string
for _, id := range IDs {
IDsString = append(IDsString, strconv.Itoa(id))
}
return IDsString
}
func (n *NewsScraper) GetTopStories() {
req, err := http.NewRequest("GET", n.url, nil)
if err != nil {
log.Fatal(err)
}
for _, id := range Top10Stories() {
req.URL.Path = "/v0/item/" + id + ".json"
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
var topStory TopStories
json.NewDecoder(resp.Body).Decode(&topStory)
n.Data = append(n.Data, topStory)
}
}
//create html template handler for top stories
func HTMLHandler(w http.ResponseWriter, r *http.Request) {
scraper := NewNewsScraper("https://hacker-news.firebaseio.com")
scraper.GetTopStories()
tmpl:= template.Must(template.ParseFiles("template.html"))
data := templateData{
PageTitle: "Top Stories",
Data :[]TopStories{
//what should I put here?
},
}
tmpl.Execute(w, data)
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/top", HTMLHandler)
http.ListenAndServe(":8080", mux)
}
I see three issues with your code:
a) The template.html file should have space between link & rel
<linkrel="stylesheet" href="https://unpkg.com/mvp.css"/>
to
<link rel="stylesheet" href="https://unpkg.com/mvp.css"/>
b) The template.html file should contain .Data instead of .Links.
c) The go code should be replaced from the below
Data :[]TopStories{
//what should I put here?
},
to
Data : scraper.Data,
Guys I am making a create your own adventure type book in which the user has options to select events. I am taking the story data from a json file. I have created two files named story.go and main.go where story.go handles all the functions and main.go has only the server. Look at the following codes
story.go
package gyg
import (
"encoding/json"
"io"
"net/http"
"text/template"
)
var defaultHandlerTemplate = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Give Yourself Goosebumps</title>
</head>
<body>
<h1>{{.Title}}</h1>
{{range .Paragraphs}}
<p>{{.}}</p>
{{end}}
<ul>
{{range .Options}}
<li> {{.Text}} </li>
{{end}}
</ul>
</body>
</html>
`
var tpl *template.Template
type Story map[string]Chapter
type Chapter struct {
Title string `json:"title"`
Paragraphs []string `json:"story"`
Options []Option `json:"options"`
}
type Option struct {
Text string `json:"text"`
Arc string `json:"arc"`
}
type handler struct {
s Story
}
func init() {
tpl = template.Must(template.New("").Parse("defaultHandlerTemplate"))
}
func JsonStory(r io.Reader) (Story, error) {
d := json.NewDecoder(r)
var story Story
if err := d.Decode(&story); err != nil {
return nil, err
}
return story, nil
}
func NewHandler(s Story) http.Handler {
return handler{s}
}
func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := tpl.Execute(w, h.s["intro"])
if err != nil {
panic(err)
}
}
main.go
package main
import (
"flag"
"fmt"
"go-projects/gyg"
"log"
"net/http"
"os"
)
func main() {
filename := flag.String("file", "gopher.json", "the file with GYG story.")
flag.Parse()
f, err := os.Open(*filename)
if err != nil {
panic(err)
}
story, err := gyg.JsonStory(f)
if err != nil {
panic(err)
}
server := http.Server{
Addr: "127.0.0.1:3000",
}
h := gyg.NewHandler(story)
fmt.Printf("Startin the server on port %s\n", server.Addr)
log.Fatal(http.ListenAndServe(server.Addr, h))
}
On running main.go the server is listening on port 3000 but when opening port 3000 on browser, it's displaying
defaultHandlerTemplate
I'm writing a parser HTML in Go. I need to get HTML and pass it to another function.
I did it so:
Can`t pass "doc" to another function
receivedURL, err := http.Get("http://lavillitacafe.com/")
doc, err := goquery.NewDocumentFromReader(receivedURL.Body)
//"linkScrape" this is another function
contactURL := linkScrape(doc)
and
HTML is transferred in parts to another function.
resp, err := http.Get("http://lavillitacafe.com/")
if err != nil {
fmt.Println(err)
return
}
defer resp.Body.Close()
for true {
bs := make([]byte, 1014)
n, err := resp.Body.Read(bs)
contactURL := linkScrape(bs[:n])
if n == 0 || err != nil{
break
}
}
How do I do it right?
Here's the basic goquery example adjusted to your use case:
package main
import (
"fmt"
"log"
"strings"
"github.com/PuerkitoBio/goquery"
)
func findHeader(d *goquery.Document) string {
header := d.Find("h1").Text()
return header
}
func main() {
// create from a string
data := `
<html>
<head>
<title>My document</title>
</head>
<body>
<h1>Header</h1>
</body>
</html>`
doc, err := goquery.NewDocumentFromReader(strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
fmt.Println(findHeader(doc))
}
I'm rather new to Stackoverflow. I'm stuck at this problem. I'm trying to make a map.
package main
import (
"encoding/json"
"fmt"
"html/template"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
)
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/showimage", showimage)
fmt.Println("listening...")
err := http.ListenAndServe(GetPort(), nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
func GetPort() string {
var port = os.Getenv("PORT")
if port == "" {
port = "4747"
fmt.Println("INFO: No PORT environment variable detected, defaulting to " + port)
}
return ":" + port
}
func handler (w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, rootForm)
}
const rootForm =
`<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Flickr photos</title>
</head>
<body>
<h1>Flickr photos</h1>
<p>Find photos by tags!</p>
<form action="/showimage" method="post" accept-charset="utf-8">
<input type="text" name="str" value="Type Tags..." id="str">
<input type="submit" value=".. and see the images!">
</form>
</body>
</html>`
var upperTemplate = template.Must(template.New("showimage").Parse(upperTemplateHTML)) //irrelevant to issue here
func showimage(w http.ResponseWriter, r *http.Request) {
tag := r.FormValue("str")
safeTag := url.QueryEscape(tag)
fullUrl := fmt.Sprintf("https://api.instagram.com/v1/users/search?q=%s&access_token=ACCESS-TOKEN&count=1", safeTag)
client := &http.Client{}
req, err := http.NewRequest("GET", fullUrl, nil)
if err != nil {
log.Fatal("NewRequest: ", err)
return
}
resp, requestErr := client.Do(req)
if requestErr != nil {
log.Fatal("Do: ", requestErr)
return
}
defer resp.Body.Close()
body, dataReadErr := ioutil.ReadAll(resp.Body)
if dataReadErr != nil {
log.Fatal("ReadAll: ", dataReadErr)
return
}
res := make(map[string][]map[string]interface{})
However, when I try to put data into the interface
json.Unmarshal(body, &res)
userid, _ := res["data"][0]["username"]
queryUrl := fmt.Sprintf("http://instagram.com/%s", userid)
I get the error
http: panic serving [::1]:63089: runtime error: index out of range
goroutine 28 [running]:
any idea why? This error is resolved if I remove the [] in res:= and userid :=, but I won't be able to access the data I want.
It is wrong with "res"'s using. "res" is a map(key is string, value is a slice),so res["data"] may be a nil in your code, and it will panic when you use res["data"][0] .You should do like this:
json.Unmarshal(body, &res)
s, ok := res["data"]
if ok {
if len(s)>0{
userid , ok := s[0]["username"]
if ok{
queryUrl := fmt.Sprintf("http://instagram.com/%s", userid)
}
}
}