Live data from Hacker News

How I write HTTP services in Go after 13 years

grafana.com

61–70 of 259 posts

Re: How I write HTTP services in Go after 13 years

#61
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

Just do

    type Username string
And replace

      return Username{username}
with

      return Username(username)

Re: How I write HTTP services in Go after 13 years

#62
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

> and a human-readable explanation of the issue is set as the value.

This is annoying to translate later. At least also include some error code string that is documented somewhere and isn't prone to change randomly.

Re: How I write HTTP services in Go after 13 years

#63

Earlier quoted context omitted.

DRY is just "Do not repeat yourself". And a LOT of devs take that literally. It's not "Do not repeat concepts" (which is what it SHOULD be but DRC isn't a fun acronym). Unfortunately "This is the same character string" is all a DRY purist needs to start messing up the code base. I honestly believe that "DRY" is an anti-pattern because of how often I see this exact behavior trotted out or espoused. It's a cargo cult t…

This seems less about DRY and more a story about a hypothetical junior dev making a dumb mistake masquerading as commentary about “DRY purism”.

Man I wish it was just jr devs. I cut jrs a ton of slack, they don't know any better. However, it's the seniors with the quick quips that are the biggest issue I run into. Or perhaps senior devs with jr mentalities

Re: How I write HTTP services in Go after 13 years

#64
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

> and a human-readable explanation of the issue is set as the value. This is annoying to translate later. At least also include some error code string that is documented somewhere and isn't prone to change randomly.

I mean, you may end up just wanting something like,

    type UsernameError struct {
      name   string
      reason string
    }
    func (e *UsernameError) Error() string { 
      return fmt.Errorf("invalid username %q: %s", e.name, e.reason)
    }
And reason can be "username cannot be empty" or "username may not contain 'This is fine for lots of different cases, because it’s likely that your code wants to know how to handle “username is invalid”, but only humans care about why.

I have personally never seen a Go codebase where you parse error strings. I know that people keep complaining about it so it must be happening out there—but every codebase I’ve worked with either has error constants (an exported var set to some errors.New() value) or some kind of custom error type you can check. Or if it doesn’t have those things, I had no interest in parsing the errors.

Re: How I write HTTP services in Go after 13 years

#65
post #19

I really like Mat Ryer's work, and I've applied most of the ideas in the 2018 version of this article to all of my Go projects since then. The one weak spot for me is this aspect: > NewServer is a big constructor that takes in all dependencies as arguments... In test cases that don’t need all of the dependencies, I pass in nil as a signal that it won’t be used. This has always felt wrong to me, but I've never been ab…

[deleted]

Re: How I write HTTP services in Go after 13 years

#66
post #23

I've recently been playing with ogen: https://github.com/ogen-go/ogen Write openapi definition, it'll do routing, definition of structs, validation of JSON schemas, etc. All I need to do is implement the service. Validating an integer range for a querystring parameter is just too boring. And too easy to mistype when writing it manually. Anyways, so far only been playing, so haven't found the bad parts yet.

The problem with this approach is writing openapi by hand from scratch is incredibly tedious process. Writing Protobufs, capnproto or any such similar idl feels much more productive

Re: How I write HTTP services in Go after 13 years

#67
post #61
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

Just do type Username string And replace return Username{username} with return Username(username)

If you do that, people outside the package can also do Username(x) conversions instead of calling NewUsername. Making value package private means that you can only set it from outside the package using provided functionality.

Re: How I write HTTP services in Go after 13 years

#68

Earlier quoted context omitted.

This seems less about DRY and more a story about a hypothetical junior dev making a dumb mistake masquerading as commentary about “DRY purism”.

Man I wish it was just jr devs. I cut jrs a ton of slack, they don't know any better. However, it's the seniors with the quick quips that are the biggest issue I run into. Or perhaps senior devs with jr mentalities

most srs are just jrs with inflated egos and titles

Re: How I write HTTP services in Go after 13 years

#69
post #61
post #25

> The Valid method takes a context (which is optional but has been useful for me in the past) and returns a map. If there is a problem with a field, its name is used as the key, and a human-readable explanation of the issue is set as the value. I used to do this, but ever since reading Lexi Lambda's "Parse, Don't Validate," [0] I've found validators to be much more error-prone than leveraging Go's built-in type check…

Just do type Username string And replace return Username{username} with return Username(username)

The problem there is that you lose the guarantee that the parser validated the string value.

A caller can just say:

    // This is returning an error for some reason, so let's do it directly.
    // username, err := parsers.NewUsername(raw)
    username := parsers.Username(raw)
You also get implicit conversions in ways you probably don't want:

    var u Username
    u = "" // Implicitly converts from string to Username

Re: How I write HTTP services in Go after 13 years

#70
post #38

Earlier quoted context omitted.

Now what? the username is in an unexported field and unusable? I can kind of see what its going for but it seems like a way just to add another layer of wrapping and indirection.

It would need a getter here. Probably good to keep it immutable, if you want guarantees that it will never be changed to something that violates the username rules.

> need a getter

Yeah, thats what I figured. Im not sure if I want the tradeoff of calling .GetValue in multiple places just to save calling validate in maybe 2 or 3 places.

Not to mention I cant easily marshal/unmarshal into it and next week valid username is a username that doesnt already exist in the database.

Maybe this approach appeals to people and Im hesitant to say “that’s not how Go is supposed to be written” but for me this feels like “clever over clear”.

Post reply on HN