Live data from Hacker News

REST Servers in Go: Part 1 – standard library

eli.thegreenplace.net

41–50 of 149 posts

Re: REST Servers in Go: Part 1 – standard library

#41
post #31
post #27

Earlier quoted context omitted.

> I don't think there's been a single instance where I've thought "why can't stdlib do this?" I've had this a few times, most recently with "how do I add this data file to my binary". At least that one made it to master now, and will be in 1.16! Another gripe is the lack of a proper parallel safe map (no, map[interface{}]interface{} like sync.Map is just not acceptable) which would be a godsend and should honestly ju…

>I've had this a few times, most recently with "how do I add this data file to my binary". At least that one made it to master now, and will be in 1.16! Wait, how?? I've done some unholy things.

The best example for the new '//go:embed' directive I've seen so far is this:

  package main
  
  import (
      "embed"
      "net/http"
  )
  
  //go:embed assets/*
  var assets embed.FS
  
  func main() {
      fs := http.FileServer(http.FS(assets))
      http.ListenAndServe(":8080", fs)
  }
For the next month, the list of options here [0] will have to suffice.

0: https://go.googlesource.com/proposal/+/master/design/draft-e...

Re: REST Servers in Go: Part 1 – standard library

#42

Earlier quoted context omitted.

I've never understood the value proposition of a DI framework. Why would I want one when I can initialize my objects in main()? Is XML or JSON or whatever really that much more pleasant than wiring together Go objects?

The purpose of DI is to allow the use of a DSL to instantiate and connect objects, with configuration for those objects embedded into the DSL so that the setup and the way things work can be changed quickly without altering code. Mocking objects for testing purposes and swapping them for the real objects is also something commonly done that is helpful. There is no "real" DI for Golang as far as I've seen. The only DI…

The things you describe are pretty strongly understood as antipatterns in Go.

Re: REST Servers in Go: Part 1 – standard library

#43
post #24

Earlier quoted context omitted.

By DSL...you mean XML/JSON? Because that's literally the only thing I've ever seen used for DI purposes. And then invariably there's still just two versions of any given injectable interface; the one used in production, and the one used in testing.

DI is a decoupling technique. You might only have two interfaces to begin with, but the rough idea is that writing to interfaces and using IoC allows you to make many changes by adding code without having to change old code.

Sure, but you don't need a framework or DSL for this in Go.

Re: REST Servers in Go: Part 1 – standard library

#44
post #27

Earlier quoted context omitted.

> I don't think there's been a single instance where I've thought "why can't stdlib do this?" I've had this a few times, most recently with "how do I add this data file to my binary". At least that one made it to master now, and will be in 1.16! Another gripe is the lack of a proper parallel safe map (no, map[interface{}]interface{} like sync.Map is just not acceptable) which would be a godsend and should honestly ju…

> I've had this a few times, most recently with "how do I add this data file to my binary". At least that one made it to master now, and will be in 1.16! And before 1.16, there is statik: https://github.com/rakyll/statik . Creates an embeddable file system from files or directories. It’s awesome for packaging web front ends into binaries.

Before 1.16, there's a whole list [0], though I've personally used go-bindata the most. I've yet to try statik, though I doubt I'll ever have a reason to now!

0: https://go.googlesource.com/proposal/+/master/design/draft-e...

Re: REST Servers in Go: Part 1 – standard library

#45

Earlier quoted context omitted.

In the latter example, the question is really one of how tightly you wish to couple the application layer to that of the infrastructure (controller). Should the application logic be coupled to a http REST API (and thus map application errors to status codes etc), or does that belong in the controller? I don't disagree that it's more practical, initially, as you've described it. However, I think it's important to poin…

I don't think it's the worst thing in the world if you test your http.Handler implementation: w := httptest.NewRecorder() req := httptest.NewRequest("GET", "/foo", nil) ServeHTTP(w, req) if got, want := w.Code, http.StatusOK; got != want { t.Errorf("get /foo: status:\n got: %v\n want: %v", got, want) } if got, want := w.Body.String(), "it worked"; got != want { t.Errorf("get /foo: body:\n got: %v\n want: %v", got, wa…

I don't think it's poor to test http handling either, as a coarse grained integration test.

The problem I've seen is over-dependence on writing unit tests with mocks instead of biting the bullet and properly testing all the boundaries. I have seen folk end up with 1000+ tests, of which most are useless because the mocks make far too many assumptions, but are necessary because of the layer coupling.

This was mostly in Node though, where mocking the request/response gets done inconsistently, per framework. Go might have better tooling in that regard, and maybe that sways the equation a bit. IMO there's still merit to decoupling if there's any feasibility of e.g. migrating to GraphQL or another protocol without having to undergo an entire re-write.

Re: REST Servers in Go: Part 1 – standard library

#46

I'm an API developer working with Python and Django. I did dabble with Golang for quite some time, but I just can't seem to justify the effort (in terms of lines of codes and static typing) of writing a ReST API with Go when I can build a similar one with Django and co (DRF, Swagger, etc). Can someone chime in? There must be an obvious advantage that I might be missing.

Static typing buys you correctness now. Go isn't really a poster child of language design, to be blunt - but it's better to find out now rather than in production.

Compiled code is also significantly faster in many cases.

Re: REST Servers in Go: Part 1 – standard library

#47

Earlier quoted context omitted.

The purpose of DI is to allow the use of a DSL to instantiate and connect objects, with configuration for those objects embedded into the DSL so that the setup and the way things work can be changed quickly without altering code. Mocking objects for testing purposes and swapping them for the real objects is also something commonly done that is helpful. There is no "real" DI for Golang as far as I've seen. The only DI…

The things you describe are pretty strongly understood as antipatterns in Go.

I hope to spur conversation on this. I've seen many in the Go community argue against abstractions. Many say, "Pass the database connection in the params." Or "make the DB pool a global variable". How can you write tests for logic without having to instantiate a DB? Many gophers appear to say I should have essentially a giant transaction script for each handler (https://martinfowler.com/eaaCatalog/transactionScript.html). The handler opens the DB, makes it at least function scoped, and all my business logic goes in the handler, or some similar method where the DB connection is passed. Now my tests are functionally integration testings. This makes them both slow, and hard to test for proper error handling.

When I write code in most OOP like languages, I follow the Clean Architecture model. The use case is an actual struct with the interfaces defining the repositories/services as members. I am now free to test the use case in isolation. I can test failure cases to since I return an error, which can be easily mocked. I write a factory to create my use cases. The handlers get the factory passed in as an argument to the constructor for server. I can now test handlers in isolation by passing a factor with mocks.

Re: REST Servers in Go: Part 1 – standard library

#48
post #24

Earlier quoted context omitted.

DI is a decoupling technique. You might only have two interfaces to begin with, but the rough idea is that writing to interfaces and using IoC allows you to make many changes by adding code without having to change old code.

Sure, but you don't need a framework or DSL for this in Go.

I don't need them in Java or Typescript. The benefit is that I don't have to write these boring, but necessary pieces. As applications grow larger, especially with Go's desire to have an interface with only one method/function, DI requires a lot of boilerplate.

If there was a DI for go that used generate, then I would have compile time checking of dependencies. This would satisfy the community's sense of purity while satisfying my sense of annoyance at having to write this same process for every project.

Re: REST Servers in Go: Part 1 – standard library

#49
post #33

Defining them all on a single server struct means once you're past a handful you start having a hard-as-heck to organize folder of handlers (or a bunch of massive code files). How are folk managing Go endpoint as apps scale across number of endpoints? I'm skeptical that one struct in one folder leads to good app structure, and have seen this start to break down in a few cases in practice

It depends on what the struct contains. I have developed many Go API's professionally at several companies since Go 1.1, and all my servers and up looking like a server struct with only a few fields - a database, AWS client object, and some prometheus metrics. The logic is typically split among many files, all implementing receivers on that struct.

If you have independent, different elements in that API, you break them out into separate "servers" but still register the endpoints on the same HTTP handler.

I know that people don't like external libraries too much, but I'd like to plug my own here. You declare your API in OpenAPI 3.0 (aka, Swagger) and it generates your server and models for you, so all you need to do is write the business logic. (https://github.com/deepmap/oapi-codegen)

Re: REST Servers in Go: Part 1 – standard library

#50
post #35

Looking at such articles makes me feel we are going back in time rather than improving efficiencies for developers to build RESTful server. If you look at Ruby on Rails you can build the server shown here in one min that is scalable and backed with database. I know people will complain about speed of execution of language and framework but do you really care if you are not expecting Google like traffic.

Some prefer clear, flexible easy to debug code instead of coding to 15 layers of abstraction. For an HTTP API you have to discard more than half of Rails anyway.

I agree so hard on this. Anyone recommending rails as some sort of elevation of a restful API is puzzling to me. It’s easy to get started for people that don’t want to code. Instead they want to spend all of their time memorizing the cascade of configuration objects where you have to learn the exact phrase to get rails to do what you want it to.

I know this is all opinion and I have colleagues who are excellent engineers that prefer rails, but it goes against everything I enjoy about software development.

Post reply on HN