
A Go “clone” of the great and famous Requests library - agonzalezro
https://github.com/levigross/grequests
======
spenczar5
These ports from Python and Ruby (like Martini, for another example) are well-
intentioned, but I don't think they're a good idea to use. The original
libraries get a lot of their expressive power from polymorphism - Requests
gets a tremendous amount of mileage out of letting you pass in keyword
arguments to the `get` method, for example.

Go prefers that you be more explicit and use more function declarations, even
if it means repetition in the library code. When developers try to get around
this, you see awkward constructs like the pointer-to-a-config-struct used
here.

~~~
coldtea
I personally welcome those kind of ports and hate blind insistent on
"idiomatic" code.

Idiomatic Java, Perl and other languages were shit for a long time, they only
improved when some brave soulds fed up with it and explorer non-idiomatic
solutions (like the Play framework). And some things I see in "idiomatic" Go
make my hair crawl...

~~~
ORioN63
I'm going to disagree with you there.

Idiomatic code is so called, because people familiar with the language can
quickly read it. It makes reading code a much lighter task.

Frameworks are a different thing. Frameworks build around its host language,
but normally are meant to use in a specific way. In its own idiomatic way.

~~~
coldtea
> _Idiomatic code is so called, because people familiar with the language can
> quickly read it. It makes reading code a much lighter task._

In the case of Java circa 2000-2006 it needlessly messed up code, making it
more difficult and slow to read EVEN for people familiar with the language.

Following conventions doesn't make code better to read automatically just
because people are already familiar with them -- those conventions should be
good in the first place for that to happen.

Node has the callback hell "idiom" many are familiar with. And yet if somebody
rewrote the code with async, await, even the people "familiar" with callbacks
would be able to read it faster and understand it better.

~~~
mattkrea
I don't think this is universal as it hasn't applied where I work. Without
understanding how promises work they are no easier and it doesn't help that
many things exists that do not use the standard .then() and .catch().

~~~
coldtea
Async/await is not the same as bare promises though with then() and catch.

------
jkldotio
Very poorly named given Requests has a branch using Gevent that's already
called grequests.
[https://github.com/kennethreitz/grequests](https://github.com/kennethreitz/grequests)

~~~
Bedon292
I didn't even notice that part, very true. I think it should probably be
gorequests. Sounds better than grequests anyways.

~~~
mangeletti
I agree, gorequests is the obvious choice, and changing the name before it
becomes too popular would be a good idea.

~~~
pertsix
sounds like a great FPS title from the mid-90's. GoreQuests, Rated M for
Mature.

------
shawnps
Whenever I'm reading through Go code and come across something that uses this
sort of abstraction library, I usually just close it and move on. The stdlib
is really nice and I find code that stays as "vanilla" Go as possible to be
the easiest to read.

~~~
Rezo
It's not the first time I've heard this sentiment around Go. I find it a
fascinating difference in mindset to for example Node.js where in my
experience even the smallest application will pull in dozens of dependencies
and there's a package for absolutely everything imaginable. Because of the way
dependencies are hierarchically scoped, there's no version conflicts in Node
and a project may end up with 3 different Requests modules with only disk
space as the cost.

What do you consider to be the downsides to liberally using libraries that
reduce the amount of code by wrapping the standard lib or that build on top of
other libraries? Personally, and I may be wrong as someone still new to Go, it
seems to me that the single monolithic repository model that Google uses
permeates the whole community and has made adding an external dependency a Big
Deal and something you have to carefully consider instead of something you
instinctively do.

~~~
tedsuo
Simply put: dependencies are code, and code comes at a maintenance cost. Thin
abstractions, such as a this library, can be replaced by a function or two,
which is a lower maintenance overhead because there is less code, you wrote
the code, and all the code is being used.

IMHO, dependencies should be pulled in for things that would take you weeks to
do correctly. Avoid pulling in a dependency for something you can do yourself
in 5 minutes. So I would pull in an http library if it actually did the
mechanics of http better than the one in the stdlib, but not one that just
wrapped it up for me a bit.

For me, that's not a Go thing, that's just an I'm Older Now thing.

Also, snarkily, dependency management is a mess in Go right now; none of us
have any dependencies because we can't figure out how to do it. :P That is
definitely a hole right now (though it's starting to get plugged in 1.5 with
the /vendor directory) and is definitely exacerbated by the core team not
being able to use any solution they could provide for the community.

~~~
levigross
I agree with you.

I wrote this library because I didn't want to rewrite those functions every
time I started on a new project. I put it online because I figured that I
would be useful to others as well.

~~~
tedsuo
btw for the record I don't think there's something wrong with making small
packages like this, just that I'm more likely to copy over a function or
pattern that I like into my codebase, rather than bring in a dependency.

~~~
levigross
I know... But as you said (and I agreed) :) dependencies add complexity...

------
gghh
forgive my ignorance, is the original library [http://python-
requests.org](http://python-requests.org) ?

~~~
ionforce
If true, I don't think it's ignorance. Not everyone is a Pythonista.

Exactly how famous is this library?

~~~
Twirrim
About as famous as they come in the python community. It is the perfect
example of a library done right. I've yet to meet a developer who have used it
that dislike it.

It handles all of the low level stuff for you, such as sessions, cookies,
gzip, form encoding POSTs, composing URLs with arguments, thread safety etc.
etc. without you even having to be aware of them, all in a terse and more
readable format. It does it without taking the ability away to control those
if you really want to, not that you're likely to need to anyway.

Take a look at the two examples here, one using the standard library for http,
urllib2, and the other using requests:
[https://gist.github.com/kennethreitz/973705](https://gist.github.com/kennethreitz/973705)

I want requests to exist in pretty much every language. The API is clean and
simple and perfectly expressive.

~~~
IndianAstronaut
Kenneth Reitz needs to do something with datetime in Python.

------
tptacek
What's a use case in Go for an HTTP request library interface that returns a
new channel for each request? There's no good way to select on a slice of
channels, is there?

~~~
jerf
No _good_ way, no.

I consider this a Go anti-pattern. Without a good reason, do not try to
provide "asynchronousness" in a library. Go natively supports goroutines and
channels, and it's considered baseline skill in the language to be able to
fire something off in a goroutine (it's literally a two-character keyword) and
receive something on a channel, if you want to. It would be not only adequate
but _preferable_ to implement this library as a fully synchronous request
system and expect the user of the library to implement what asynchronousness
they may require. Your hardwiring of exactly how the "asynchronousness" works
may conflict with my own needs.

All the "asynchronousness" you need to provide is already hard-wired into the
Go runtime itself; what certain language communities have trained you to think
is "synchronous" code _already isn 't_. You don't have to super-duper-extra
make it even more asynchronous.

I won't quite call exposing channels in a library API a code smell, it's a
little too useful for that, but it's still something where you ought to pause
for a moment and really think about what it means, especially if you created
it rather than receiving it.

Oh, and let me be clear: Levigross, I'm seriously suggesting that you change
this library wholesale to be fully synchronous, and the fact that this will be
an API change is a feature, not a bug. You'll find it also simplifies the API
significantly, also a feature.

~~~
levigross
Jerf,

Thank you for the suggestion. I plan on adding some functionality to make
asynchronous APIs friendlier to use (like a `Do` or `Apply` function etc...).
But if you don't choose to use the asynchronous APIs everything still
functions the same (in fact the asynchronous APIs use the synchronous
functions and slap channels on them)

~~~
jerf
No, seriously, _just remove_ your "asynchronous APIs". You don't need them.
They aren't adding anything. Just remove them. Go already does all that.

Oh, what the heck, I'll name names. This is part of why I've been so pissy at
the Node community for the past few years. Their definition of synchronous is
_wrong_ , and it's really become quite popular. Synchronous does _not_ mean
"blocks the whole process". That is a _weakness of Node_ , not a universal
programming truth. From the Node perspective, _all Go code is always and
automatically asynchronous_. You don't have to add it. It already is. You're
not adding functionality by trying to "nicely" provide an asynchronous API,
you're simple redundantly adding what is already there, and what you're adding
is significantly less flexible than what Go already provides.

(Now with more correct definitions of the terms, it is meaningful to say that
Go code is synchronous within a goroutine. But Go already provides abundant
tools for dealing with that within its runtime. We can already compose these
tools together trivially to do whatever async patterns we want.)

Now, I suppose, standard disclaimer, this is your library, do as you like. I'm
not actually personally passionate about this like I'm yelling at my monitor
or anything. I'm trying to help you save time and effort. It's up to you what
you decide to do.

~~~
levigross
Jerf,

1\. Thank you for the feedback

As you have already seen, I submitted my library to /r/golang and have gotten
a lot of feedback – from which I modified the constructs (originally the
functions returned channels).

I want to write something that is useful to as many people as possible (all
while not alienating anyone) and therefore try not to force users (like I
originally did) to use the "asynchronous APIs".

I didn't expect this to end up on HN and was going to start a discussion on
golang-nuts on the pros and cons of this construct. Based on that, I was going
to remove or keep the APIs.

~~~
jaytaylor
+1 for removal, YAGNI.

------
fishnchips
As much as I love to see new things written in Go I am not a big fan of
directly porting libraries written in different languages. It's not even that
they're not idiomatic - I can live with that just fine. But the real power of
Go comes from interfaces - two great examples being `io.Reader` and
`io.Writer`. Once you can structure your library code so that it reasonably
implements these standard interfaces you can do complex stuff in a trivial
way. Say I want to get a file via HTTP, encrypt it while getting a hash of
plaintext and upload it to say Google Cloud. I can pretty trivially do it by
putting one `io.Writer` (Google Cloud) in another (encryption) and another
(hashing, via `io.MultiWriter`) and then perform the whole thing using a
simple `io.Copy`. This sort of expressive power can be achieved iff all
libraries you're using adhere to the same philosophy - which is not the case
with ports.

~~~
levigross
I agree with this sentiment and therefore my Response method is also an
`io.ReadCloser` (exposing the http.Response.Body io.ReadCloser that Go has to
offer).

------
domrdy
Would be cool if the examples showcased fetching a list of URL's in parallel
or something else that is a bit more complex.

~~~
levigross
I agree! The README is really sparse right now (I didn't expect so much
exposure right). It is just a matter of time before the README has more
information.

------
iqandjoke
After reading
[https://github.com/mozillazg/request](https://github.com/mozillazg/request),
I found yours looks a little bit better.

~~~
levigross
Thanks – I wrote this library because I like using requests when writing in
Python and wanted something similar when writing in Go.

------
hobarrera
Until go fixes it's issues with IPv6 (noticeably: it won't work on IPv6 out-
of-the-box), I can't really respect it or consider it "production ready" for
anything network related.

No, I'm not trolling. #8453 got closed, and immediately, #11081 was opened
since it re-broke this.

Original issue reported by myself:
[https://github.com/golang/go/issues/8124](https://github.com/golang/go/issues/8124)

------
nlake44
Go is great, its open source. I wish Hacker News open sourced their code so
that we knew what they are doing. Scared of having folks game the system? Why
not have the community make it the best algorithm possible. Why keep pushing
YC all the time? Do they not have enough already? Painters and hackers! ha!

~~~
coldtea
It's not an abstract community, much less one with some FOSS mission statement
or anything, it's a YC combinator site.

