It seems like there are three classes of "web problems" to solve:
(1) The absolute basic "hello world" stuff at the outset. How to route URL's to their handlers, how to render dynamic templates, how to map data structures to and from JSON, etc.
(2) The problems that are one level up in sophistication, but still common to nearly all web apps. How to handle authentication (username/pass, OAuth/JWT, etc), how to manage session state or the lack thereof, juggling synchronous blocking operations with async background ones, etc.
(3) Really advanced issues that are probably specific to your industry domain or specific application, and aren't necessarily common to others (e.g. how to isolate this medical data for HIPPA compliance).
I don't want to poo-poo this website, it's nice. But in my mind, the world is already flooded with Category #1 examples. At the same time, Category #3 doesn't really lend itself to this sort of thing at all. So what the world really needs is more Category #2 stuff.
Example: What are the patterns available for authentication, including their advantages and drawbacks?
If you do your own authentication with usernames and passwords... then you have to either have to pass them every time and re-auth every request, or else store a session cookie on the client side and find some way share it across all your server-side instances (or use a load balancer with sticky sessions). That's material for 3 or 4 patterns right there!
If you use OAuth with JWT tokens, then you can (maybe) avoid the need to store any session state on the server side. But how do you explicitly "logout" prior to the JWT expiration? Another 3 or 4 patterns down this route!
Category #1 is fun and easy to write about, and a lot af that material comes from newbies who are writing in order to teach themselves. But Category #2 is the brick wall that people always run into in the real world... and because you need a lot of real experience to write about that class of problems, there's a vacuum of available material out there.
That's why this Category #2 stuff is so important. People can agree without much controversy what "best practice" is for the Category #1 stuff, but at the next level it's just blog posts and discussion thread comments passionately arguing opposite statements.
I'm curious... if not JWT, then how would you approach the problem of authenticated sessions without server-side state? (assuming you aren't rejecting the overall premise entirely)
If you track authentication with a server-side session, then you have to either:
(1) Setup a backing store for your session state (e.g. Redis, relational database, proprietary app server solution, etc). Share the backing store across all instance nodes in your server-side cluster. Tune the inevitable performance issues and point-of-failure risks, and expect the worst if you're using a proprietary thing (they're all terrible).
(2) Use a hardware solution. Have the load balancer always route a given client's requests to the same server-side instance. Deal with failover scenarios when that instance goes down, have to drain traffic every time you want to do a deployment, etc.
JWT's ugly, but no uglier than either of those! Always on the lookout for other recipes...
The choice isn't "JWT" or "server-side sessions". It's client-side sessions versus server-side sessions, and JWT is just one (bad) option among many for client-side sessions.
'lvh and I are working on a piece about this for our clients, so I want to be careful not to write a crappy version of it in an HN comment first. But I think you'll find something close to a consensus on JWT/JWS/JWE/JWK among crypto engineers of our ilk.
I guess I'd close by saying: if you were writing a Rails app, it's almost certainly the case that you'd be better off just using ActiveSupport::MessageEncryptor to create an encrypted token than you would be building a shambolic equivalent of MessageEncryptor in JWT.
You didn't actually answer the why not JWT question there.
We're pretty heavily invested with using JWT wrapped inside OpenID Connect, and given you garner a lot of respect on such topics, I'd really be appreciate if you cited a source or gave us a reason. Anything would be better rather than just appealing to a vague consensus.
Why would my advice change because you're building something that uses JWT?
This thread, though, is about Go web applications. So I guess apropos this thread, I'd just say we probably don't need an example of how to use JWTs in Go. But session management, yes!
> Why would my advice change because you're building something that uses JWT?
I never said it would, I was simply stating my interest in your opinion on the topic. It seems a shame that you don't seem to be willing to expand though.
The equivalent of ActiveSupport::MessageEncryptor. Virtually every platform has something. Go has crypto/cipher.AEAD. Python has fernet. Most platforms have access to Nacl's "secretbox". All of these things are simpler, safer, and just as effective as JWT.
And even that presumes you want to actually encrypt data to the client: many (most) JWT users are just signing tokens, which makes an alternative to JWTs even simpler.
token = data:expiry:hmac(key, data+expiry) is super simple in most languages, is robust, and nacl provides useful helpers for doing this as well.
Nope. If there was, virtually every Rails app would be doomed.
There's a sort of intuitive insecurity quotient for things that goes something like C/W_s where C is complexity and W_s is the number of people in the world who would be screwed if something was totally broken.
Encrypted session cookies have, as a design, relatively modest C and very, very high W_s.
JWT has extraordinarily high C and, at present, modest W_s (relative to session cookies).
(They also have a bunch of design flaws that amplify their complexity).
Yep. I was brought on to a project where the JWT secret was a 6 letter band name. It's the hotness newness in the JS community and there's a lot of tutorials out there that show how easy it is to set up without explaining the risks/trade-offs.
That recommendation is due to JWT not taking revocation into account at all, if I remember tptacek's stance correctly. Personally, I agree.
This has been discussed on HN before and I remember talk about using "fancy" stuff like Bloom filters but as far as I know, no library offers anything for this out of the box and this is not something you want to roll yourself.
The recommendation seems to be using an encrypted cookie, with some format other than JWT.
Which is fine and well. But how does that take revocation into account?
You can store a token on the client side, in ANY format. The problem remains that you're either storing some server-side state about that token, or you aren't. If you are, then you're not really using client-side sessions. If you aren't, then you still don't have a good way to revoke. Because you can't really control the client-side after you've issued a token, and you can't revoke it from the server-side without state.
I'm sure there are good arguments to be made against the use of JWT. But their simply aren't any to be found in this thread, and no alternative client-side proposal that solves the revocation problem.
Lack of revocation is actually pretty far down my list of reasons, but it's a very common complaint other people have about JWT that I also agree with.
Revocation was something I did consider, but I am just using a users password hash as the token key, that way when the user changes his password, all previous tokens are invalidated.
Can you remember where this was discussed? I was under the impression that JWT was becoming a new standard for many people. I guess that's not mutually exclusive to it being bad, but I would like to read more.
JWT is popular with application developers. I think that's because it's cross-stack. Rails developers already have solutions for 95% of the problems JWT solves in the real world. So do Django developers, and so do Go developers, and so do PHP developers. But there's no lingua franca for this problem.
Developers would like there to be one. Unfortunately, they've chosen a terrible standard --- just really, really bad --- to run with. You are better off doing something by hand than using JWT. If you're at all familiar with my ouvre on HN: that's how bad JWT is. I think you might seriously be better off DIY.
Sort of funny, that is more or less exactly the stuff we needed for our internal candidate assessment app built on go/http. It just makes sense and is stuff you will want in any app, even a mostly CRUD one.
FWIW, gophish is a very clean app built using Gorilla packages that implements these patterns in a comprehensible way and I found it very helpful as I was implementing things.
Your first request is tricky because it can lead to issues down the road if done poorly, so it is hard to just give a quick example of it. I wrote about this subject recently (see https://www.calhoun.io/pitfalls-of-context-values-and-how-to... ) and there is a lot of info to cover. That said I could see value in doing an example and referencing a more in depth overview from the example.
Once you cover (1) most of the others fall into line. There is little reason to use context values outside of MW from my experience.
Re (3) - can you provide a link or example of what you mean?
(5) - again, can you elaborate? Are you referring to error types? Or just how the errors are rendered?
I ask all these questions because I write a lot about Go and I am interested in trying to make examples of these available, but I want to understand what you are asking for first.
Could you be a bit clearer about the "issues down the road" we're concerned about with overuse of context, or with use of context for non-request-scoped dependencies?
The end of your article advocates a little bit for just accepting code reuse, and the getter/setter/subfunction thing comes perilously close to GoF Java style for my taste. Further: I have seen, routinely, on pretty much every project I've worked on, serious production faults from errors and omissions in duplicated code. I'm not sure I've seen equivalently serious production faults (really: any faults) in overuse of things like "context".
Totally agree. It's because of stuff like this that I find Go to be fairly tedious for full stack web. JSON microservice that's blazing fast is great. High concurrency workload, great.
Full stack website that reuses template parts with live data, manages sessions and logins, images, JavaScript and CSS...not so much.
Just curious, what were the worst gaps in functionality and have you looked at it recently? I'm pretty happy with Go for full stack web apps, but it did take a little while to get up to speed and a few years ago there were fewer solutions for common problems available. A few areas where it required some more work:
Authentication - there are a few good examples out there, I think gorilla secure cookie is good, CSRF protection too.
Authorisation - had to write my own version of the ruby lib cancan, am now happy with the solution
Images - stdlib is pretty good but it'd be nice if it handled resizing images and exif orientation tags.
Javascript and CSS - there are some ports of minifiers in go so an asset pipeline is pretty easy.
ORM - I use a query builder and use the map columns->fields in code, not keen on the orms using reflection and/or struct tags to do so. This doesn't have to be complex though.
Migrations - there are a few libraries out there now, so this isn't bad, I prefer sql migrations.
Templates - love the context-sensitive escaping, would be nice if it handled layout/partial but this is doable with some tweaks.
Forms - generation of views with text/template is pretty handy to handle things like CRUD forms for models.
This is where frameworks are useful - they present best-practices for the above details and more that you have to handle in a full-scale webapp.
I think those are the areas I'd like to see more tutorials on for beginners coming to Go, but there are solutions out there nowadays (far more than even a few years ago).Most of the things you mention are not in the std library so I guess people feel a little lost when they first arrive in Go land, but there are a few libraries out there like gorilla which cover most of this stuff or you can write your own, and once you have it's a really pleasant language to write traditional server-side apps with.
So with the above caveats I'm really happy with it for full stack web development.
I'd love to see some blog posts about this. The lack of any good resources on full-stack web frameworks is what has kept me from really diving deep into Go. I still believe (pretty strongly) in traditional, server-rendered, low JS overhead websites / app.
My biggest issue was with server rendered applications. I think it's a good fit for SPA's where each piece is rendered to the browser independently.
Just as an example, my go to test for most programming languages is to rebuild my personal site with it (http://brightball.com/). Just provides me with a good exercise in running through a simple project that I've done in multiple languages and provides a good basis for comparison without getting too fancy.
If you'll look at the page layout, you'll see the main content area with a list of articles, some sidebar elements that are loaded from the database and a list of primary tags in the footer (also pulled from the database).
The biggest pain point was the reusable elements (sidebar and footer) with the template system. In most other template systems it's pretty trivial to write parts that have code attached to them and tell a layout to call those pieces with some arguments. With Go, that was a bit of a pain requiring all of the data that that would appear on the page to be retrieved before starting the rendering process. That led to a lot of repetition to pull in that data on every path to the layout.
So the layout/partial system would be my biggest pain point. My first instinct was to go and reach for a framework but so much stuff that I read on Go boards gave the impression that the community seemed to have a very negative impression there.
Additionally, there wasn't a clear winner among frameworks which made me hesitate. That's a problem you see in languages that have so much stuff for the web built in like PHP and Javascript. It becomes so easy to do-it-yourself on the framework front that there are a million different flavors and no clear path.
With Ruby, Python, Elixir, Groovy, etc there are clear and dominant frameworks for the language. If you learn this language, you should know framework "X". When there isn't that clear winner, it's hard to justify investing in developing around it.
To try to get around that issue and the sense that with Go you were supposed to sort of assemble your own parts, not commit to a framework, etc I tried https://github.com/runemadsen/ok-go since it's basically a framework of assembled and replaceable parts.
Most of the issues I describe are non-issues if Go is backing a React/Angular app instead. I just found it to be a huge pain for entirely server side applications.
My biggest issue was with server rendered applications.
Thanks, this is what I'm talking about too (server-side web apps), I've found it a good fit, but do understand the initial difficulties with html/template - it is not very user friendly and was not designed for the sort of layout/partial arrangement that almost every web framework uses, however it can be used in that way with a little tweaking. That data has to be retrieved somehow though for the sidebar say, so I don't mind having to pass it in explicitly - it at least makes all the work being done explicit.
Agreed on the frameworks issue, frankly I find the hostility to frameworks on places like /r/golang tiresome and cultish - there is the kernel of a good idea in rejecting frameworks (they can after all straightjacket your code and invert control), but there can be many benefits to them and they provide essential pointers for those new to the language. I think for Go to grow it does need people to start to coalesce around solutions so that beginners don't have to reinvent rails again for every app or (worse IMO) start using JS for frontend and Go for backend - then you have two problems (or 400,000 if you use npm). I prefer server-side only and am happy with Go for that.
Elixir is on my list to check out, thanks for the link.
The templating is fast and safe but a pain to use. For example, an HTML Select needs a 3-value list: id,text,selected bool. You can't evaluate a comparison (if...) or call a function in the template. It's unpleasant.
You can call functions and methods in templates, and you can use if else, they actually have all the tools you need to do things like provide helper functions and produce a full html select with something like:
{{ select "Order" "form_name" .value .options }}
Granted those helper functions don't exist in the base templates, but the tools are there to build them.
I am currently searching for an example / skeleton in Go where I can upload a file via the browser to the server (drag and drop added bonus). Any examples?
Something like this will hopefully get the point across on how to handle "multipart/form-data" forms. It will print the content of the upload to the server's stdout.
I actually wrote an extremely shonky/basic file upload thing and contributed it to the weird 'illacceptanything' repository, while that was a thing, about a year and a half ago.
Maybe you'll find it helpful, maybe not. Ignore the bindata.go stuff and look at main.go (inc. file accepting) & the file upload control (w/Bootstrap fileinput.min.js) & the braindead simple HTML templating stuff.
I don't know much about Go so can't speak to the server-side handling of file uploads. The drag/drop side of things is server agnostic - I strongly recommend http://www.dropzonejs.com
This might be more of a complete app than you need, but https://transfer.sh is open source and it looks fairly compact. Could be some interesting examples in there?
Work through those followed by a few project Euler challenges then implement something simple in the domain that you normally work in. For me that's web so I implemented a little HipChat bot.
The Go Programming Language (https://gopl.io) is what I've had at my desk the past few weeks while learning. Also whenever I get stuck I search Github code for a term like "json.Unmarshal" to find how others have done something. And otherwise just duckduckgo'ing "golang <search term>". Also you'll hear a million times to check out Effective Go and The Go Tour (on the official Golang site). Those are good but I appreciate them more now that I've got a good foundation
This is one of the things that most stood out with me while I was learning Go, it's just so easy to read other people's examples and just understand it without too much hard thought
Also check out usage examples on Sourcegraph (disclaimer: I'm the CTO). We sell our tool to companies to use on their private code, but a side effect is that we've indexed usage examples for just about every popular Go open-source library. For example,
I would replace gorp with https://github.com/vattle/sqlboiler. Granted, I've not used either, but I like the philosophy behind sqlboiler. I feel it is more in line with Go principles. I also believe gorp will have issues with the new DB context stuff (though I'm not positive on that).
If you want to ping me with what you are looking to build and your programming experience level I can recommend more specific resources. jon [at] calhoun.io
Many resources (like my book) are targeting absolute beginners so they are a bit lengthier to read if you are experienced, whereas other great books and whatnot are really hard for beginners to follow so at least expressing your skill level would help me recommend specific resources.
I know this isn't a book but if you need a go development environment, cloud9 (https://c9.io) ended up being a surprisingly productive environment. Like for go development, it's been better than anything I've tried to setup locally and the IDE even has go autocomplete.
Along the same tone, httprouter doesn't allow defining these routes simultaneously
users/:id
users/watching
Was kind of surprised as we have many routes like that. Like gorilla/mux, I think it was just first (trie-based mux). Isn't gin based on httprouter?
There are even better muxes now. `pressly/chi` is used by heavy hitters in production and takes advantage of Go 1.7 HTTP context. `labstack/echo` is another highly recommended by others but I don't like the non-idiomatic echo.Context in handler signatures.
Back on topic, I hope the go web examples only imports built-in packages. The gorilla/mux example could easily be written to use built-in packages.
I avoid httprouter because it doesn't adhere to the standard library interface for http handlers. I've not used gin, but it looks to also not follow the standard library interface here. Also, it does not appear to make use of newer developments in Go such as the context package (it imports the x/pkg version but does nothing with it I think).
I believe gorilla mux came out years before the others, so it's not really shocking that it is used more. I personally have never had any issues with it but to each there own.
Has anyone of you experience with the fasthttp Go library[0]?
Does it keep its promise in terms of speed? (I assume real world code would spend much more time in actual business logic than their examples/benchmarks so I guess there wouldn't be as much a difference as they claim, but the idea of zero allocations intrigues me)
These look great, thanks. I'm currently learning Go and find this kind of example much easier to follow than documentation.
I'd like to see an example for embedding HTML templates properly. It took me an embarrassing amount of time to get beyond 'header.html' and 'footer.html' being separate, and I'm sure my solution isn't as elegant as it could be.
I need to do a follow-up to that with the type I use to wrap that logic, but I am curious if this is inline with what you are looking for in the examples.
Yes, thank you. My solution was similar but less elegant; I plan on going through your post in more depth and attempt to reimplement my code with what I've learned.
I haven't tried Go in a while but I see a lack of error handling in the code examples. Is that just to keep the code simple? I'd rather see examples with best practice handling of errors. Maybe show both versions so readers can see the difference?
These guides go into the right direction. I solved many things for myself but it would be nice to collect good practices. I had to come up with go style design patterns for:
- Middlewares
- Authentication
- Authorization
- Database Access
- JSON APIs
- Template organization
- Migrations
- i18n
- Crypted Cookies
- Image uploading
- Form validation
- Asset Pipeline
- API Versioning
- Writing libs for 3rd party services
Where is the best place to share my best practices and to discuss them with others? Via a pull request to that repo? You know of other good sources?
> Just looking at the syntax it strikes me how inconcise and it is.
And you recommend Javascript instead? Interesting.
> Why would I want use Go for the backend
Fast, built-in concurrency, enough high level concepts and structures to support fast development, and really easy to deploy.
The last part is probably the greatest. It supports simple host-based deploys, tiny docker container deploys, and eliminates the typical dependency conflict problems of Python and Node.
It's also pragmatic enough to make it easy to develop in for developers across the skill bell curve.
In general: more performant, much better at threading through goroutines. It's worth noting go is compiled, so it's more comparable to a language like C++ than a dynamic language like python or JS.
What kind of validation are you looking for? Simple things like "is not empty", "maximum 8 characters"...?
Most libraries I've seen which try to do form validation always lack in certain areas or force you to define your own validation, so I simply ended up adding an `isValid` method to my structs.
In web examples HTML is "not really the point"? Ok. I can actually accept that as reasonable. But isn't the style of this example to abstract static HTML out of the HTML file and generate it dynamically as needed? I'll grant that it's a rather small issue; nonetheless, I do think the author would be best served by said abstraction for style and consistency (to the last detail).
(1) The absolute basic "hello world" stuff at the outset. How to route URL's to their handlers, how to render dynamic templates, how to map data structures to and from JSON, etc.
(2) The problems that are one level up in sophistication, but still common to nearly all web apps. How to handle authentication (username/pass, OAuth/JWT, etc), how to manage session state or the lack thereof, juggling synchronous blocking operations with async background ones, etc.
(3) Really advanced issues that are probably specific to your industry domain or specific application, and aren't necessarily common to others (e.g. how to isolate this medical data for HIPPA compliance).
I don't want to poo-poo this website, it's nice. But in my mind, the world is already flooded with Category #1 examples. At the same time, Category #3 doesn't really lend itself to this sort of thing at all. So what the world really needs is more Category #2 stuff.
Example: What are the patterns available for authentication, including their advantages and drawbacks?
If you do your own authentication with usernames and passwords... then you have to either have to pass them every time and re-auth every request, or else store a session cookie on the client side and find some way share it across all your server-side instances (or use a load balancer with sticky sessions). That's material for 3 or 4 patterns right there!
If you use OAuth with JWT tokens, then you can (maybe) avoid the need to store any session state on the server side. But how do you explicitly "logout" prior to the JWT expiration? Another 3 or 4 patterns down this route!
Category #1 is fun and easy to write about, and a lot af that material comes from newbies who are writing in order to teach themselves. But Category #2 is the brick wall that people always run into in the real world... and because you need a lot of real experience to write about that class of problems, there's a vacuum of available material out there.