How to process GET operation (CRUD) in go lang via Postman? - http

I want to perform a get operation. I am passng name as a resource to the URL.
The URL I am hitting in Postman is : localhost:8080/location/{titan rolex} ( I chose the GET method in the dropdown list)
On the URL hit in Postman, I am executing the GetUser func() with body as:
func GetUser(rw http.ResponseWriter, req *http.Request) {
}
Now I wish to get the resource value i.e 'titan rolex' in the GetUser method.
How can I achieve this in golang?
In main(), I have this :
http.HandleFunc("/location/{titan rolex}", GetUser)
Thanks in advance.

What you are doing is binding the complete path /location/{titan rolex} to be handled by GetUser.
What you really want is to bind /location/<every possible string> to be handled by one handler (e.g. LocationHandler).
You can do that with either the standard library or another router. I will present both ways:
Standard lib:
import (
"fmt"
"net/http"
"log"
)
func locationHandler(w http.ResponseWriter, r *http.Request) {
name := r.URL.Path[len("/location/"):]
fmt.Fprintf(w, "Location: %s\n", name)
}
func main() {
http.HandleFunc("/location/", locationHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
Note however, more complex paths (such as /location/<every possible string>/<some int>/<another string>) will be tedious to implement this way.
The other way is to use github.com/julienschmidt/httprouter, especially if you encounter these situations more often (and have more complex paths).
Here's an example for your use case:
import (
"fmt"
"github.com/julienschmidt/httprouter"
"net/http"
"log"
)
func LocationHandler(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
fmt.Fprintf(w, "Location: %s\n", ps.ByName("loc"))
}
func main() {
router := httprouter.New()
router.GET("/location/:loc", LocationHandler)
log.Fatal(http.ListenAndServe(":8080", router))
}
Note that httprouter uses a slightly different signature for handlers. This is because, as you can see, it passes these parameters to the functions as well.
Oh and another note, you can just hit http://localhost:8080/location/titan rolex with your browser (or something else) - if that something else is decent enough, it will URLEncode that to be http://localhost:8080/location/titan%20rolex.

Related

Handling custom 404 pages with http.FileServer

I'm currently using a basic http.FileServer setup to serve a simple static site. I need to handle 404 errors with a custom not found page. I've been looking into this issue quite a bit, and I cannot determine what the best solution is.
I've seen several responses on GitHub issues along the lines of:
You can implement your own ResponseWriter which writes a custom message after WriteHeader.
It seems like this is the best approach but I'm a bit unsure of how this would actually be implemented. If there are any simple examples of this implementation, it'd be greatly appreciated!
I think this can be solved with your own middleware. You can try to open the file first and if it doesn't exist, call your own 404 handler. Otherwise just dispatch the call to the static file server in the standard library.
Here is how that could look:
package main
import (
"fmt"
"net/http"
"os"
"path"
)
func notFound(w http.ResponseWriter, r *http.Request) {
// Here you can send your custom 404 back.
fmt.Fprintf(w, "404")
}
func customNotFound(fs http.FileSystem) http.Handler {
fileServer := http.FileServer(fs)
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := fs.Open(path.Clean(r.URL.Path)) // Do not allow path traversals.
if os.IsNotExist(err) {
notFound(w, r)
return
}
fileServer.ServeHTTP(w, r)
})
}
func main() {
http.ListenAndServe(":8080", customNotFound(http.Dir("/path/to/files")))
}

HTTP response is always empty

How do I pass http.ResponseWriter in a parameter?
I'm coming from nodejs and would really like to learn Go.
Here is the main file:
import (
"net/http"
"./libs/database"
)
func bla (w http.ResponseWriter, r *http.Request) {
go database.AddFriend("bob", w)
}
Here is database file:
import (
"net/http"
)
func AddFriend (friendName string, w http.ResponseWriter){
fmt.Println(friendName)
w.Write([]byte("Yoooooooo"))
}
Everything works but the w.Write returns nothing to my ajax post.
I'm keep thinking its like nodejs where I can pass an
object then use it. I know its probably something simple but I just can't seem to figure it out.
Don't call database.AddFriend in a goroutine. This is most likely the cause of your problem. By using a goroutine, your connection is closed and response sent, before the output is written to the HTTP response.
func bla (w http.ResponseWriter, r *http.Request) {
database.AddFriend("bob", w)
}

How to access the net.conn from a http connection in Golang?

My code looks like this at the moment:
package main
import (
"io"
"net/http"
"fmt"
"net"
)
const (
PORT = ":443"
KEY = "./localhost.key"
CERT = "./localhost.crt"
)
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world! :)")
}
func main() {
http.HandleFunc("/", hello)
http.ListenAndServeTLS(PORT, CERT, KEY, nil)
}
What I would like to be able to do is to use the net.Conn that is created when a client reaches my host. The reason behind this is to use golang.org/x/net/http2 in order to create custom frames and edit the transmission of data at a lower level. And for example http2.NewFramer requires a writer and a reader, which I guess would be the actual net.Conn in both cases.
I am pretty to new to Golang so any advice on how to improve myself is well welcomed. Thank you in advance everyone! :)

Unable to read post form value in Golang with htprouter

I'm new to Golang and trying to get a basic http app running using the httprouter API. I've hit a wall with reading posted form data, despite following the advice given in another StackOverflow question.
Here's my code (minus irrelevancies):
import (
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
r := httprouter.New()
r.POST("/sub", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
r.Header.Set("content-type", "text/html")
err := r.ParseForm()
if err != nil {
fmt.Fprintf(w, "<h1>Error: %s</h1>\n", err)
}
fmt.Fprintf(w, "<h1>Submitted message!</h1>\n<p>-%s-</p>\n", r.PostFormValue("msg"))
})
http.ListenAndServe("localhost:3000", r)
}
In the output, where I should see -hello-, I just see --. When I inspect the http request in Firefox, in the Form Data panel, I see msg:"hello", so why is r.PostFormValue("msg") returning a blank string?
Thanks to Volker for pointing out an error. When I commented out the line r.Header.Set("content-type", "text/html"), the problem was resolved. Perhaps that was the issue, or perhaps there was some issue with the IDE (LiteIDE) caching an old version of the code. In any case, I can now read the posted value.

Serving a single page application with go net/http mux

I'm building an api that also serves my react front end app, but am having an issue serving my index.html
Given that it's not really a go template I'm not using html/template.
I'm not seeing a strait forward way to serve the static html root of my app on all pages that do not start /api in the route.
I'm purposely trying not to use any go frameworks beyond gorilla's mux
My handler.go:
func Index(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("./views"))
}
Routes.go:
type Route struct {
Name string
Method string
Pattern string
HandlerFunc http.HandlerFunc
}
type Routes []Route
var routes = Routes{
Route{
"Index",
"GET",
"/",
Index,
},
}
router.go
import (
"net/http"
"github.com/gorilla/mux"
)
func NewRouter() *mux.Router {
router := mux.NewRouter().StrictSlash(true)
for _, route := range routes {
var handler http.Handler
handler = route.HandlerFunc
handler = Logger(handler, route.Name)
router.
Methods(route.Method).
Path(route.Pattern).
Name(route.Name).
Handler(handler)
}
return router
}
main:
package main
import (
"./server"
"log"
"net/http"
)
func main() {
router := server.NewRouter()
log.Fatal(http.ListenAndServe(":8080", router))
}
Currently a blank page shows up, and thats it. My index.html is located in /views/index.html in relation to the executable (but I've tried it in relation to the handler as well)
Update
I was able to serve the html file using the method shown in this question: How do you serve a static html file using a go web server? However using mux and the more modularized file structure still yields a nice pretty, clean blank page.
In handler.go, your Index function is actually a no-op, since http.FileServer() returns a Handler, which is never passed the ResponseWriter or Request, hence the blank page.
Maybe try something like this to at least get past that:
func Index(w http.ResponseWriter, r *http.Request) {
http.FileServer(http.Dir("./views")).ServeHTTP(w, r)
}

Resources