Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: I made a simple persistent counting API (arbitrarycounter.com)
54 points by dustyreagan on July 15, 2013 | hide | past | favorite | 41 comments



Incrementing or decrementing a counter is neither side-effect-free nor idempotent, and GET should generally be both, so you really shouldn't use GET for those operations. [1]

POST would probably be the usual choice for these operations. (Though, since you aren't really creating a subresource but are instead performing a defined transformation on an existing resource, you could probably make a case for PATCH.)

Web APIs are protocols implemented on top of HTTP, and should respect the semantics of HTTP unless there is a clearly-identified compelling reason not to.

[1] http://tools.ietf.org/html/rfc2616#section-9.1


Yeah, ok. I agree with that. I changed incrementing and decrementing operations to POST requests only, and updated the documentation. Thanks for the feedback!


I believe most anayltics platforms use/support GET, e.g. google analytics, mixpanel etc. If you limit yourself to use only POST, you will limit users from using your tool in areas like email pixel tracking where only GET is allowed.


Doing a cross domain POST is a pain. Doing a cross domain GET is what you do everyday. If you want to increment a counter based on a user action on a web page, then a GET makes a lot of sense.


Yeah, see I'm kind of torn, because GET just makes it so dang simple. POST requests, though semantically correct, add a small amount of overhead to implementing the counter. I'm not really concerned with spiders, as the URLs are intended to be obscure + robots.txt. In addition, future versions could include simple basic auth for private URLs. Though I intend to keep public URLs around for fun and drive by counting.


Wouldn't you want to do a POST for creating the first counter and then a PUT for updates?


Yes ... And to address one of the comments above, PATCH is used to merge data into an existing record while PUT is used to replace the existing contents. This is a bit of an odd case since you wouldn't be sending data in either case.


why should they respect the semantics? Those were arbitrary and out dated. I don't see any need for that.


Web crawlers and web page views index using GET; if GET affects your server state, so do page views and indexing.

GET is idempotent. That's not outdated, and it's not arbitrary: it is literally stated in the protocol specification. It's a useful distinction created and used by professionals to maintain sanity in complex schemes of communication.

Please do not ignore technical details because you think you're smarter than everyone else on the planet, or that the problems they solved a decade ago somehow went away in the face of node.js.

edit: Just in case you (or anyone reading this) is unaware of it,

http://www.ietf.org/rfc/rfc2616.txt (or pretty: http://pretty-rfc.herokuapp.com/RFC2616)

Find Section '9.1 Safe and Idempotent Methods'.


Naturally, it is not possible to ensure that the server does not generate side-effects as a result of performing a GET request; in fact, some dynamic resources consider that a feature. The important distinction here is that the user did not request the side-effects, so therefore cannot be held accountable for them.

I think that, depending on what his API is trying to do, GETing a counter URL to increment it could be acceptable if his service's main purpose is to be accessible via client-side javascript.

That being said, once you go down that road you have to begin taking into account everything that may depend on GET idempotence: send back proper caching headers as well as busting caches from the client side, decide whether or not you want to block javascript-parsing web crawlers, etc.


> why should they respect the semantics?

Because they are going to be used in an environment where there are lots of other things built based on the specifications and which are likely to rely on (or, in some cases, have inspired) the semantics described in the HTTP spec -- including lots of the infrastructure of the web.

> Those were arbitrary and out dated.

There may be some issues with them, but those would fall under the umbrella of "clearly-identified compelling reasons".


They were arbitrarily decided a long time ago by people who put much more thought into it than you or I, most likely.


Especially in the case of HTTP/1.1, it wasn't "arbitrary", it was based on quite a bit of experience with HTTP in the wild.


(I don't actually believe near any of these things are "arbitrary"--was being facetious in response to tone of the poster.)


I was doing some usability testing in one of my webapps and needed a simple way to count conversions. There are lots of A/B testing solutions out there, but I just wanted a persistent count I could increment on specific user actions. So I created the ArbitraryCounter.com.

I find it useful, but I'm wondering if anyone else might. What do y'all think?

PS. This is WAY beta, and mainly a proof-of-concept. But I'll continue developing it if there's an interest it.


Perhaps POST requests would be more appropriate for incrementing/decrementing?

GET's may be either cached(skipped) or duplicated for various reasons, resulting in incorrect counts.


Can someone explain how counters can be so hard to implement ourselves that we need to use this?


It's probably not that they're hard, but rather that they might require some boilerplate code and bloat that somebody might want to offload to an external service like this one.


The idea was to make something easier than booting up a database. Personally, I just needed a semi-persistent count that I could discard later. This fit the bill for me, and being able to retrieve the counts via JSON, I can easily add them to my Geckoboard dashboard.


I think you should be able to incr/decr by more than 1. Maybe allow http://arbitrarycounter.com/vb/fruit/apples+N where N can be any integer > 0


I added an IncrementBy and DecrementBy variable you can pass in your POST request, and update the documentation. How's that work for ya'?


  X-Increment-Size: 10
Eh, eh?


Yeah, batching would be good to encourage.


GET should never modify data. I would recommend changing that to a POST before something indexes it and decides to crawl it every 5 minutes. See here for more reasons: http://stackoverflow.com/questions/705782/why-shouldnt-data-...

I realize this isn't supposed to be highly accurate, but it's something to keep in mind if it continues to grow.


Agreed. I updated the site and docs. Thanks! :)


I love simple api's like this. Its kind of the same mental model I keep around http://jsonip.com. A simple service that does one thing really well. Its been working well and has grown to millions of requests a day.

Keep working on this, I can see several uses already.


>millions of requests a day.

I'm interested to know how much it takes to run jsonip? Does it cost a lot?

Edit: I've just seen the Pro version. Are you turning jsonip into a freemium model?


It's a node.js app that has until recently been a single-process app. I just integrated clustering to take advantage of the extra cores Linode gave me. It's a simple but high traffic service and node has handled it like a champ. I have a relatively inexpensive account with Linode that so far has suited the site's traffic just fine.

I'm exploring the idea of offering a higher-tier service. The general feature list is outlined on getjsonip.com but pricing isn't finalized. I'm still collecting signups and feedback right now.


Thanks! I appreciate that! :)


> All URLs are public. We recommend using a unique group name to avoid collisions with other users.

So anyone can increment your counter without you knowing? Seems like this means you can never rely on the count being right.

As a side note, the link on the bottom is broken.


The idea was to launch the proof of concept with public URLs, then if I discovered people were interested, create private URLs. Thing is private URLs require an authentication system, which is fine, but I didn't want to overdevelop the proof-of-concept.

I fixed the link. Thanks! :)


You can just use a 128-bit random string as a group key. That's how "private" photos are implemented on most photo sites, for example.


I think that's the way to go for the public URLs. I'm going to leave it up to the user to come up with a unique group name though.


I like the flexibility, but I would suggest you add a "generate GUID" button when choosing the group name in case the user does want a random URL, which seems quite likely.


Unless they know what counter you're using or you make it public, it's unreasonable that anyone could mess with your counter.


> Unless they know what counter you're using or you make it public, it's unreasonable that anyone could mess with your counter.

...or you choose convenient, meaningful $group and $id names, which makes even unintentional collisions not at all unlikely.


This would be an example of security through obscurity.


Yes and no. You could argue that use of passwords or private keys is security through obscurity, but that definition is pretty meaningless. Security through obscurity doesn't really apply when you can make the search space arbitrarily (often exponentially) big very cheaply, as is the case of URLs here.


Manu times you need a counter just to get a unique id. If the counter is incremented by someone else it's not important. On the other hand if the counter can be reset because it hasn't been used for 48 hours it's a big problem...


"There's an API for that" is the new "there's an app for that".


Yep. I understand this is just a little toy thing, but people are really trying to start businesses off of "APIs" that do not much more than OP's.

The whole point of an API is that you defer a significant amount of serverside processing and logic to a remote host, and receive a nicely formatted and machine-readable response. You have to deal with the overhead of a TCP connection (handshaking / RTT), an HTTP request, and an HTTP response. If you're doing that every time a user visits your web page (or app view or whatever), especially multiple times, then you better have a good reason for doing so.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: