Common http response library

agolangf · · 887 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<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&#39;s my feedback:</p> <ul> <li><p>I wouldn&#39;t use a library like this. I&#39;ve written convenience functions like this many times, and don&#39;t see a reason to import an external dependency just to wrap an http.ResponseWriter. <em>&#34;A little copying is better than a little dependency.&#34;</em> <a href="https://www.youtube.com/watch?v=yi5A3cK1LNA" rel="nofollow">https://www.youtube.com/watch?v=yi5A3cK1LNA</a></p> <p>There&#39;s little point in calling to an external library when you can just do <code>w.Write([]byte(&#34;some response&#34;))</code> I ran across this when looking at the gin framework the other day. </p> <p>```</p> <pre><code>c.JSON(200, gin.H{ &#34;status&#34;: &#34;posted&#34;, &#34;message&#34;: message, &#34;nick&#34;: 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&#39;s just <code>map[string]interface{}</code>. </p> <p>There&#39;s a certain level of functionality that external libraries provide over standard library functions/types but whenever we import one, there&#39;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&#39;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&#39;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&#39;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 &#34;you don&#39;t need a http framework/library in go&#34; 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&#39;t like statusCode being the last parameter. Is there a reason for this?</p> <p>I would give &#39;gometalinter&#39; 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&#39;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&#39;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&#39;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{}{ &#34;status&#34;: &#34;posted&#34;, &#34;message&#34;: message, &#34;nick&#34;: 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&#39;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&#39;m accessing headers and responding to different errors differently, so it&#39;d be hard to justify an extra package for what are essentially one-liners.</p></pre>

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

887 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传