RESTful APIs in Go, I need some opinions

blov · · 488 次点击    
这是一个分享于 的资源,其中的信息可能已经有所发展或是发生改变。
<p>I am new to Go, and have been reading up a lot on different approaches to take to creating RESTful APIs in Go, and notice that there are many different ways to go about it, although they are all quite similar.</p> <p>I am starting a project to rewrite my MVP into a more stable and scalable product and have decided to move away from Ruby Grape framework to Go. However, with deciding this I realised there are quite a few things which I am still trying to figure out the best way to do in Go and that is where I turn to you for comments.</p> <p>The API I am rewriting is a fairly simple JSON CRUD API, but I am stuck with how to handle a few pieces of it: - I need the API to be multi-tenant, and was wondering what the best way to do this is and if there are any go packages which make this easier to implement. - I need to validate the JSON post data before pushing it to a DB, I know how to create structs for decoding the data into the struct but is there an easy way to add regex validation to those structs too? Any well supported libraries to do this? - I need to connect to a DB, is the only way to expose this DB to my handlers through a global variable? or is there a better design pattern to follow?</p> <hr/>**评论:**<br/><br/>quiI: <pre><p>Use dependency injection to pass a reference of your DB to your handler</p> <pre><code>type FooHandler struct{ db DB } func(f *FooHandler)ServeHTTP(w http.ResponseWriter, r *http.Request) { f.db.Save(&#34;hello, world&#34;) } </code></pre></pre>MEAT_FIST: <pre><p>I would do this, but I would expand on the example to implement a Services layer to live between your DB and your handlers.</p> <p>Handler - Understands HTTP, POST body/Query parameters. Anything network related</p> <p>Service - Understands business logic. Doesn&#39;t care about HTTP. Returns structs/slices of structs</p> <p>DB - Used by services to interract with your database.</p> <p>Both DB and Services should be interfaces injected into their implementers. AKA create a DB interface, build a reference to the DB to use to create a service, and then pass that service reference to the handler.</p></pre>thewhitetulip: <pre><p>Welcome to the world of frameworkless webdev!</p> <p>You can read this: <a href="https://github.com/thewhitetulip/web-dev-golang-anti-textbook/blob/master/manuscript/8.0buildingAPI.md" rel="nofollow">https://github.com/thewhitetulip/web-dev-golang-anti-textbook/blob/master/manuscript/8.0buildingAPI.md</a></p> <p>If you want to use Vue as the front end, <a href="https://github.com/thewhitetulip/intro-to-vuejs/blob/master/5_interacting_with_backend.md" rel="nofollow">https://github.com/thewhitetulip/intro-to-vuejs/blob/master/5_interacting_with_backend.md</a></p> <p>Enjoy!! (Do let me know what you think of these)</p></pre>Asti_: <pre><p>This is awesome! I&#39;ve been looking for a really detailed explaination of the interactions of Go code and a modern web frontend. Thank you!</p></pre>burn_in_flames: <pre><p>These are great! Thank you so much, it gives me a much deeper understanding of Go.</p></pre>thewhitetulip: <pre><p>You are welcome! to show appreciation any FOSS tutorial, you can buy it :)</p></pre>PsyWolf: <pre><p>There are packages that can help out with some of these things, but the advice we generally give to new gophers is to start with the standard library and see how far it gets you before you go looking for 3rd party packages. For example, the standard library has a perfectly good regex lib that you can use to write your own validation.</p> <p>As for multi-tennant, I don&#39;t know exactly what you mean by that. The standard net/http lib already serves multiple requests concurrently. What more do you want go to do here? </p></pre>bboozzoo: <pre><blockquote> <p>is there an easy way to add regex validation to those structs too</p> </blockquote> <p>We&#39;re using <a href="https://github.com/asaskevich/govalidator" rel="nofollow">govalidator</a>, seems to work quite well.</p> <p>For instance:</p> <pre><code>type Foo struct { Email string `valid:&#34;email,optional&#34;` Name string `valid:&#34;-&#34; ID string `valid:&#34;uuidv4&#34; } ... f := Foo{ Email: &#34;foo@bar.com&#34;, Name: &#34;ignored by validator&#34;, ID: &#34;123131-1312-123131-1313&#34;, } if _, err := govalidator.ValidateStruct(&amp;f); err != nil { // invalid } ... </code></pre> <blockquote> <p>is the only way to expose this DB to my handlers through a global variable</p> </blockquote> <p>use dependency injection just like in any other language</p></pre>mgutz: <pre><p>There are several struct tag validation packages. We use </p> <p><a href="https://github.com/go-validator/validator" rel="nofollow">https://github.com/go-validator/validator</a></p> <p>As for DB, I advise having 2 tiers except for trivial projects. Our API has models, controllers subpackages:</p> <p><em>controllers</em> convert to/from HTTP headers/querystring/body. Calls to the models are something like this:</p> <pre><code>func (uc UsersController) Update(w http.ResponseWriter, r *http.Request) { // parse body into your struct var args YourStruct err := api.Parse(r, &amp;args) // If your needs are simple, you could omit models.DB to simplify things and reference // it directly in UpdateByID. Our methods are flexible and can accept a transaction // OR one-off connection and must be passed in. result, err := models.Users.UpdateByID(models.DB, id, args) // reply with result or error } </code></pre> <p><em>model</em> - DB is configured in <code>init</code></p></pre>alioygur: <pre><p>It may be useful for you</p> <p><a href="https://github.com/alioygur/gocart" rel="nofollow">https://github.com/alioygur/gocart</a> </p></pre>

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

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