Does Order Of Twitter API Parameters Make A Difference?

Posted January 30, 2009 at 9:04 AM by Ben Nadel

Tags: ColdFusion

I've been having a hell of a time trying to clean up KinkyTwits - my ColdFusion powered Twitter client - for release. One big problem that I've been having is that the API seems to suddenly stop working. It will be chugging along fine and then all of a sudden, I get nothing but the following errors:

Twitter / Over capacity - Too many tweets! Please wait a moment and try again.

This error will keep coming back for hours. Then, completely randomly, it will work for a moment, and then stop again for hours.

Now, I know it can't be that the API is over capacity because when this starts to happen, I'll jump on TweetDeck and it's fine. I've been banging my head against the wall for many hours on this problem and I think I might have finally gotten to the bottom of the issue. I don't see this mentioned anywhere in the API documentation, but it seems as if the order of the Parameters passed in the GET request makes a difference. To see what I'm saying, take a look at this test code:

  • <!---
  • Make the first API request putting the SINCE_ID paramter
  • followed by the COUNT parameter.
  • --->
  • <cfhttp
  • method="get"
  • url="http://www.twitter.com/statuses/friends_timeline.json"
  • useragent="KinkyTwitsTwitterBot"
  • username="bennadel"
  • password="123xyz"
  • result="objTwitterRequest">
  •  
  • <cfhttpparam
  • type="url"
  • name="since_id"
  • value="1158700580"
  • />
  •  
  • <cfhttpparam
  • type="url"
  • name="count"
  • value="200"
  • />
  •  
  • </cfhttp>
  •  
  • <!--- Output response. --->
  • <cfdump
  • var="#ToString( objTwitterRequest.FileContent )#"
  • label="Request With SINCE_ID First."
  • />
  •  
  •  
  • <!---
  • Make the second API request putting the COUNT paramter
  • followed by the SINCE_ID parameter (the rest of the code
  • is exactly the same as the first API request).
  • --->
  • <cfhttp
  • method="get"
  • url="http://www.twitter.com/statuses/friends_timeline.json"
  • useragent="KinkyTwitsTwitterBot"
  • username="bennadel"
  • password="123xyz"
  • result="objTwitterRequest">
  •  
  • <cfhttpparam
  • type="url"
  • name="count"
  • value="200"
  • />
  •  
  • <cfhttpparam
  • type="url"
  • name="since_id"
  • value="1158700580"
  • />
  •  
  • </cfhttp>
  •  
  • <!--- Output response. --->
  • <cfdump
  • var="#ToString( objTwitterRequest.FileContent )#"
  • label="Request With COUNT First."
  • />

Notice that in the first request, I am sending the SINCE_ID followed by the COUNT parameter. This is the same order as it is listed in the API documentation (although no mention of order specification could be found). In the second request, I am then just switching the order of the parameters. Now, when I run this, very consistently, the first request returns JSON-formatted statuses and the second request returns the "Too many tweets! Please wait a moment and try again" error.

If you are thinking that this is happening because I am following one API request with another immediately after it, don't worry - I thought of that. If I run the code above, with the CFHttp tags reversed, I get the same, consistent outcome but in the reverse order (first request fails, second one succeeds).

Could it be that the order of the URL parameters in the Twitter API requests actually makes a difference? Is that possible? I can't see how that could be true in any sort of name-keyed system. Has anyone else had any experience with this?

So, why does this work sometimes for a while and then start failing all of a sudden? I assume it's because I am passing my Parameters collection through to my Twitter API execution method as a ColdFusion struct. I am then looping over that struct and creating CFHttpParam tags:

  • <!--- Make URL parameters for GET method. --->
  • <cfloop
  • item="LOCAL.Key"
  • collection="#ARGUMENTS.Parameters#">
  •  
  • <cfhttpparam
  • type="url"
  • name="#LCase( LOCAL.Key )#"
  • value="#ARGUMENTS.Parameters[ LOCAL.Key ]#"
  • />
  •  
  • </cfloop>

Because ColdFusion has no inherent order for structs, the order of the CFHttpParams is generated randomly. Of course, from CFDump experience, we know that this order is not totally random - it does get stuck in a rut (or perhaps comes out alphabetical). Either way, if we need ordering to be specific, we simply cannot rely on ColdFusion structs. Looks like I'm gonna have to go back and start passing my parameters through using an array of name-value pairs.




Reader Comments

Jan 30, 2009 at 9:14 AM // reply »
2 Comments

Could it be the API Limit being reached you can only make 100 requets in one hour? Not sure but that could be the reason?


Jan 30, 2009 at 9:17 AM // reply »
11,238 Comments

@BigMadKev,

I thought that, but if I reverse the order of the CFHTTP tests above, they fail in reverse order. If it was an API request limit, they would both have to fail on repeated requests. But, the once with "since_id" first always works, regardless of test placement.


Jan 30, 2009 at 9:18 AM // reply »
11,238 Comments

@BigMadKev,

Plus and API limit issue would return with a 400 status code - these are returning with a 200 OK status code.


Jan 30, 2009 at 9:24 AM // reply »
2 Comments

In that case then it's time to blame the technology behind twitter ;)

As it's not the developers fault is it :)

Same as MySpace.com was the Technologies fault not the devleopers.

:p hehe


Jan 30, 2009 at 9:34 AM // reply »
11,238 Comments

@BigMadKev,

I just switched from using Structs to using Arrays for my Parameters collection and its working :) Crazy stuff!


Jan 30, 2009 at 11:11 AM // reply »
25 Comments

The only thing I can see is that they're using index-based arguments, rather than the actual argument key.

ie: count = arguments[ 1 ].

Then again, if that's whay they're doing the order would impact the actual values assigned.


Jan 30, 2009 at 11:54 AM // reply »
42 Comments

Ben,

I am using the twitter api cfc from Ria Forge and I just looked at the internals and here is what I found-

<cfhttp
url="http://twitter.com/#arguments.resource#.#returnFormat#?#queryString#"
method="#arguments.method#"
username="#variables.username#"
password="#variables.password#"
useragent="ColdFusion/8.0">

<cfif arguments.method eq "post">
<cfloop collection="#arguments.params#" item="key">
<!--- Deal with nulls so passing the arguments scope works properly. --->
<cfif structKeyExists(arguments.params,key)>
<cfhttpparam name="#lCase(key)#" value="#arguments.params[key]#" type="formfield">
</cfif>
</cfloop>
</cfif>
</cfhttp>

That appears to be doing about the same thing that you are doing. I haven't had any problems whatsoever.


Jan 30, 2009 at 11:58 AM // reply »
11,238 Comments

@Brandon,

I have no idea :) Like I said, mine was working for a long time and then stopped. Maybe ColdFusion started sorting the params differently? Now that I have switched to an array, its all good. Depending on what params you have, CF might just be ordering them correctly.


Jan 30, 2009 at 12:03 PM // reply »
48 Comments

I'm throwing a hail mary here, but could it be that they're using some sort of hash for the requests you are sending as a key to throttle you and the order of the parameters results in a different hash?


Jan 30, 2009 at 12:11 PM // reply »
11,238 Comments

@Todd,

I am not sure what you mean.


Jan 30, 2009 at 1:10 PM // reply »
48 Comments

Check this:

<cfset a = createObject("java", "java.util.HashMap") />
<cfset a.put("keyOne", "valOne") />
<cfset a.put("keyTwo", "valTwo") />

<cfset b = createObject("java", "java.util.HashMap") />
<cfset a.put("keyTwo", "valTwo") />
<cfset a.put("keyOne", "valOne") />

<cfset c = createObject("java", "java.util.HashMap") />
<cfset c.put("keyOne", "valOne") />
<cfset c.put("keyTwo", "valTwo") />

<cfdump var="#a#">
<cfdump var="#b#">

A = B?<br />
<cfdump var="#a.equals(b)#">
<br />
A = C?<br />
<cfdump var="#a.equals(c)#">


Jan 30, 2009 at 1:15 PM // reply »
48 Comments

DAMN! I got all excited thinking that was correct (that A != B but A=C), until I saw my copy paste error. Here is the correct code:

<cfset a = createObject("java", "java.util.HashMap") />
<cfset a.put("keyOne", "valOne") />
<cfset a.put("keyTwo", "valTwo") />

<cfset b = createObject("java", "java.util.HashMap") />
<cfset b.put("keyTwo", "valTwo") />
<cfset b.put("keyOne", "valOne") />

<cfset c = createObject("java", "java.util.HashMap") />
<cfset c.put("keyOne", "valOne") />
<cfset c.put("keyTwo", "valTwo") />

<cfdump var="#a.hashCode()#"><br />
<cfdump var="#b.hashCode()#"><br />
<cfdump var="#c.hashCode()#"><br />

A = B?<br />
<cfdump var="#a.equals(b)#">
<br />
A = C?<br />
<cfdump var="#a.equals(c)#">

A == B == C

So, at least in Java the order of the keys in a map does not result in a different hashcode for a hashmap. But do you see where I was going with it?


Jan 30, 2009 at 1:22 PM // reply »
11,238 Comments

@Todd,

I am not sure I follow?? We are not passing the hash map to Twitter. The Struct is merely used as a collection over which we iterate to write out the CFHttpParam tags. So, collection-aside, the values are passed individually.


Jan 30, 2009 at 1:37 PM // reply »
48 Comments

Right, but, my skewed thinking was that somehow on Twitter's side of the API they are taking the arguments that you are passing in and creating a hash of that argument structure as a key to identify your requests. My thought was that they use that key to throttle you if you send too many requests within a specified time period. If the order in which you passed the args (or, the order in which they received the args) resulted in a different hash code then theoretically your requests would appear to be from a different source if you passed them in a different order.

Crazy theory - just disregard me ;)


Jan 30, 2009 at 1:40 PM // reply »
11,238 Comments

@Todd,

Thanks for getting creative with your thinking! :)


Feb 1, 2009 at 11:51 PM // reply »
63 Comments

Ben ...

Have you increased your limits with twitter?

http://twitter.com/help/request_whitelisting



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools