5 ms·
> Isn’t it pathetic that so many allegedly-mainstream languages don’t have HTTP libraries that are this natural and idiomatic? But at every point where Tim the
by buro9 13y ago
> Isn’t it pathetic that so many allegedly-mainstream languages don’t have HTTP libraries that are this natural and idiomatic?
But at every point where Tim then returns a failure we lose insight as to why something failed.
My preferred idiom for handling all errors when it comes to web requests or responses is to return both the error (as it has the detailed message of what happened) and the http status code that matches the error (as it has translated the message into a code that describes the type of error).
This bit would change:
if !strings.HasPrefix(mediaType, "application/json") {
// bogus media type, deal
return failure
}
to:
if !strings.HasPrefix(mediaType, "application/json") {
// bogus media type, deal
return HttpErr{Err: errors.New(""), Status: http.StatusUnsupportedMediaType}
}
Whatever receives that knows there has been an error, and has the code available to do tell the developer or end user something meaningful without relying on the error message.
I'm sure others are also creating their own http error as well, so whilst Go does http really well it seems in practise that there are still a few places where it could benefit from a little extra to help standardise the code we write.
All of those Http codes are here: http://golang.org/pkg/net/http/#pkg-constants http://golang.org/pkg/net/http/#pkg-constants
Regarding the map stuff, the only other place the lack of generics has stood out has been within slices of a type of thing.
The scenario is: I have a slice of identifiers in an order important to me, for each of these concurrently fetch the record being identified and create a slice of those records ordered as per the initial slice.
We've ended up using this type of thing:
// Envelope for making sorted concurrent requests for Comment
type CommentRequest struct {
Comment Comment
Err error
Seq int
}
type CommentRequestBySeq []CommentRequest
func (v CommentRequestBySeq) Len() int { return len(v) }
func (v CommentRequestBySeq) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
func (v CommentRequestBySeq) Less(i, j int) bool { return v[i].Seq < v[j].Seq }
// Much later in the code...
// Make a request for each id
req := make(chan CommentRequest)
defer close(req)
for seq, id := range ids {
go HandleCommentRequest(id, seq, req)
}
resps := []CommentRequest{}
for i := 0; i < len(ids); i++ {
resp := <-req
if resp.Err != nil {
return resp.Err
}
resps = append(resps, resp)
}
// Sort them
sort.Sort(CommentRequestBySeq(resps))
// Extract the values
ems := []Comment{}
for _, resp := range resps {
ems = append(ems, resp.Item)
}
In that example a Comment is a comment made on a forum web page and we're fetching lots concurrently, but needing to return them in the order that they will be displayed.
The problem stems from that envelope, and the need to implement that sort function for every type that we ever want to concurrently fetch and sort.
It's the only place where I think, if we just had generics this could be a lot better.
- jalfresi 13y agoif !strings.HasPrefix(mediaType, "application/json") { // bogus media type, deal return HttpErr{Err: errors.New(""), Status: http.StatusUnsupportedMediaType} } Sorry, but having dealt with a HTTP library in PHP that did something similar, I would have to hunt you down and kill you. The HTTP response status code from the original request was NOT 415 Unsupported Media Type. Do you have any idea how misleading this error is to the developer? The error you SHOULD be returning is an Application error code "Unexpected Media Type", NOT a HTTP error code. It's the application that has a problem with the returned media type.
- buro9 13y ago> I would have to hunt you down and kill you Attempts at off-the-cuff witty death threats don't tend to work too well online. I truly hope you were jesting.
- jacques_chester 13y agoOff-the-cuff witty death threats are a long-standing tradition of internet debate amongst programmers. Not for nothing do we repeat the unknown wit who observed that one should: Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
- jalfresi 13y agoApologies, yes it was an attempt at humor. I was hoping for more of a discussion on the two approaches though if your still game.
- buro9 13y agoSure. My scenario is a web service, that calls other web services. It throws an error and then has to return something meaningful to the callee, which is usually both a message that tells the developer calling the web service how to fix it (if it's something that they can fix) as well as the relevant response code. The advantage from assigning the code at the earliest point the error is detected is that one avoids any later text parsing of the error message to figure out the right code to return. It also allows general switching on the error code range to see whether you really need to throw the error or whether there is some other branch of logic that could be done instead.