<p>Hey folks! New to <a href="/r/golang" rel="nofollow">r/golang</a> and wanted to share a small library I wrote called <a href="https://github.com/jeffbmartinez/respond" rel="nofollow">respond</a> to help myself handle common responses to http requests:</p>
<ul>
<li><a href="https://github.com/jeffbmartinez/respond" rel="nofollow">respond on github</a></li>
<li><a href="https://godoc.org/github.com/jeffbmartinez/respond" rel="nofollow">respond on godoc.org</a></li>
</ul>
<p>Happy to hear comments and feedback :)</p>
<hr/>**评论:**<br/><br/>gogroob: <pre><p>Hi Jeff, </p>
<p>Welcome to Go! I hope my comment is not in poor taste, but here's my feedback:</p>
<ul>
<li><p>I wouldn't use a library like this. I've written convenience functions like this many times, and don't see a reason to import an external dependency just to wrap an http.ResponseWriter. <em>"A little copying is better than a little dependency."</em>
<a href="https://www.youtube.com/watch?v=yi5A3cK1LNA" rel="nofollow">https://www.youtube.com/watch?v=yi5A3cK1LNA</a></p>
<p>There's little point in calling to an external library when you can just do <code>w.Write([]byte("some response"))</code>
I ran across this when looking at the gin framework the other day. </p>
<p>```</p>
<pre><code>c.JSON(200, gin.H{
"status": "posted",
"message": message,
"nick": nick,
})
</code></pre>
<p>```</p>
<p>So I looked up to see what this mysterious <code>H</code> type is. <a href="https://godoc.org/github.com/gin-gonic/gin#H" rel="nofollow">https://godoc.org/github.com/gin-gonic/gin#H</a>
Turns out it's just <code>map[string]interface{}</code>. </p>
<p>There's a certain level of functionality that external libraries provide over standard library functions/types but whenever we import one, there's a cost associated with it, and many times that cost is not justified. </p></li>
<li><p><a href="https://github.com/jeffbmartinez/respond/blob/master/respond.go#L47" rel="nofollow">https://github.com/jeffbmartinez/respond/blob/master/respond.go#L47</a> the json function would be more useful if it used <code>json.MarshalIndent</code>.
If you want to marshal without indenting, the more idiomatic way to do that is to use json.NewEncoder:
<code>
if err := json.NewEncoder(w).Encode(myType); err != nil {
// handle err
}</code></p>
<p>Because <code>http.ResponseWriter</code> is an <code>io.Writer</code> and json.NewEncoder accepts the io.Writer, there's no need to <code>json.Marshal</code> first. </p>
<p><a href="https://www.datadoghq.com/blog/crossing-streams-love-letter-gos-io-reader/" rel="nofollow">https://www.datadoghq.com/blog/crossing-streams-love-letter-gos-io-reader/</a></p></li>
</ul></pre>jeffbmartinez: <pre><p>Not in poor taste at all! Really, I appreciate you taking the time. I originally wrote this as a small part of a bigger ongoing (private repository) project. Since I kept using the same pattern(s) over and over again I wrapped them into this thing.</p>
<p>By chance I happen to have seen the talk you linked to and this certainly seems like one of the libraries the speaker would avoid using. I happen to also use a few gorilla libraries as well, which he might avoid lol.</p>
<p>That being said... I just disagree with the opinion that using external dependencies necessarily increases complexity when compared to writing the same functionality yourself. I agree that most code doesn't <em>require</em> external dependencies, but if someone already did some work that saves me a bit of time in short run (easy to learn and easy to write) and the long run (easier maintainability).</p>
<p>Consider the gorilla context library as an example. Fairly simple coming in at less than 150 lines. A similar idea is now added to the go standard library. Where different developers draw the line of pulling something external in vs writing themselves is obviously a personal thing.</p>
<p>I avoided <code>MarshalIndent</code> since this is mainly for a backend project, but I'll definitely look into the <code>json.NewEncoder</code> stuff you mentioned, seems useful :)</p></pre>gnagatomo: <pre><p>I agree. The deciding factor between copying and adding dependencies is how much work will be saved and how many corner cases would be avoided vs the ability to understand/know 100% of the code that goes in your software. The npm fiasco shows a perfect case of when one should copy code. Always writing the same code for handling http can be a case for using a library, even if is relatively small because with time it can grow in size and functionality. The hipster motto "you don't need a http framework/library in go" goes too far with this and makes people forget why we create libraries.</p></pre>sheenobu: <pre><p>I was just thinking about this actually. Some sort of no-dependency library to use alongside httprouter as opposed to pulling down a full framework like gin or echo.</p>
<p>SO PICKY: I don't like statusCode being the last parameter. Is there a reason for this?</p>
<p>I would give 'gometalinter' a try. The only thing that is showing up is that you are ignoring certain errors:</p>
<pre><code>$ gometalinter
respond.go:15:9:warning: error return value not checked (w.Write(message)) (errcheck)
</code></pre></pre>jeffbmartinez: <pre><p>Thanks for the <code>gometalinter</code> tip! Installed and started using it :)</p>
<p>I updated the functions to return <code>(int, error)</code> same as <code>w.Write</code> to let the developer choose what to do with it.</p>
<p>As far as why <code>statusCode</code> is last, there's no strong reason. It came from 2 seconds of thought. Since the pattern in go is to return errors last, I figured the idea somewhat worked with the http status code ultimately being a form of error/success reporting as well, so it's passed in last.</p>
<p>Where would you have placed it?</p></pre>tmornini: <pre><p>Some status codes indicate an error condition. (4xx and 5xx) but not all status codes indicate errors. :-)</p>
<p>I'm with <a href="/u/sheenobu" rel="nofollow">/u/sheenobu</a>, at the end is icky.</p>
<p>Status code is the MOST import part of HTTP response!</p></pre>sheenobu: <pre><p>Previous to last. This is a good example:</p>
<pre><code>respond.JSON(w, http.StatusOK, map[string]interface{}{
"status": "posted",
"message": message,
"nick": nick,
})
</code></pre></pre>dinkumator: <pre><p>Your <code>String</code> method is just like <code>http.Error</code> which I use all the time for validation/error responses on APIs.</p>
<p><a href="/u/gogroob" rel="nofollow">/u/gogroob</a> mentioned this, but for json responses, it's more much efficient to use <code>json.NewEncoder(w).Encode(data)</code> than allocating a byte slice and ByteSlice and then serializing that.</p>
<p>In general, I'm accessing headers and responding to different errors differently, so it'd be hard to justify an extra package for what are essentially one-liners.</p></pre>
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码`
- 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传