Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

This is funny, but it's also a real world example of the kind of encoding nightmare that made SOAP RPC encoding really awkward. Various SOAP toolkits used to serialize a missing value as the empty string, or a literal value like "null" or 0, or all sorts of awfulness. I think the correct thing for the spec is to set xsi:nil="true" as an attribute on the XML tag in question, but IIRC about half the toolkits didn't understand that.

(I speak in the past tense of SOAP because I am an optimist.)



I worked at a company where we were replacing the user-facing component of our giant, ugly PHP storefront with a Rails version; in doing so, our developers implemented a JSON bridge between the two, allowing the frontend and backend to operate separately, using separate databases (and actually, they were in separate data centres).

As we were testing, we found that some products in our database would cause a JSON decoding error on the Rails side. After a few minutes, we realized the problem. We had a string field for something (product IDs, manufacturer SKU, etc). On the PHP side, the JSON encoder was using PHP's is_numeric() for each field to see if the field was a number (to determine how to encode it). Some of the SKUs, however, happened to be composed entirely of digits, and for those, PHP encoded them into the JSON as integer values. This, of course, broke on the Rails end, because Rails was expecting a string value and got an integer value.

In the end, we had to write a surprising amount of code to work around the brain damage involved, since regardless of what we tried to do PHP wanted, by default, to send things as integers whenever possible. I believe the final fix was to actually patch the JSON encoder library and special-case that field.


Heh. I recently had a password reset function break. Problem not reproducible on the test system. Turns out the reset email is produced by a Freemarker template engine, which is "smart" about datatypes: "oh, a number! I need to Format that nicely with commas to separate the thousands!" Too bad that number was the user ID - Not a problem on the test system with its 300 users, but in production...


Your test system has 300 users? Thanks for depressing me...


That's 300 user accounts, created by testers over the course of several releases.


Next time use is_int() instead of is_numeric().

is_int() checks the type of the field, while is_numeric() looks for strings that look like numbers.

You will also need to use settype() when getting your data from the database since integers from the database will pass through as strings (since the database range and PHP range aren't necessarily the same, use a float if you need unsigned ints).

Or just use the built in json_encode().


> use a float if you need unsigned ints

what.


(I assume that "what." is a request for an explanation.)

A float can store an exact integer of up to 53 bits even on a 32 bit machine.

PHP only has signed ints. If you need to store an unsigned int you can either store it internally as signed and only convert it to unsigned with printf() when you output it (and deal with the complexity of comparisons), or use a float and limit yourself to 53 bits.

If you have a 64 bit machine then of course you can easily fit an unsigned 32 bit int in that range. But it's wise not to rely on that at least for another few years.

In short, if you need more than 32 signed bits of range, and you want to make sure your code will run on any machine, then use a float. If you know you only use 64 bit machines then you have more flexibility. (You can use PHP_INT_SIZE and PHP_INT_MAX to check.)

If you need even more range than that then use the built in GMP library.

Also, PHP will automatically convert numbers that are too large from ints to float, so normally you don't see any of this. It's only if you use settype() to force an int that you have to pay attention to this.


Did you homebrew your own JSON encoder in PHP? Sounds that way. The standard encoder respects types.


could you have added some text at the end of the id before sending it and then removed the extra bits from the end on recieving side? something like a parity value.


Or just call String#to_s on the Rails side.


That would probably work, but it means that the problem + workaround is spread out across two systems rather than being contained in just one. Also, working around it on the consumer side means that any new consumers (or any new string fields!) will need to use the workaround too, further spreading out the problem. Better to keep it encapsulated in one system if possible.


If you have a method that breaks when an int is passed in, just seems like good defensive programming to call to_s in Ruby. Any other caller could make the same mistake. But, I also understand/agree with fixing the root issue for the sake of other clients.


This is really a fundamental problem: how do you indicate operation failure? This relies on two things: the range (the valid output values) of the operation itself, and the range of the datatype you're mapping the operation's result to.

If the operation and the datatype's range are not equal, then you can indicate failure inside the return value by applying special meaning to invalid values. But if the operation and the datatype's range are equal, then you need another distinct value to indicate failure. The difficulty is in recognizing which situation you're in, and as you point out, this is one where, effectively, the operation and the datatype have the same range.


Wow. I love that the S stands for Simple. "You keep using that word. I do not think it means what you think it means."



God, I love that rant.

"I trust that the guys who wrote this have been shot." :-)

People who all run the same version of Visual Studio think SOAP is awesome. Get handed somebody else's "whiz-dull" a few times, and see how much fun it is to generate a working client using a different brand/version client stack.


I had the pleasure of writing a client for a SOAP service in a Titanium/JavaScript app not too long ago. If you don't have visual studio generating those proxy classes for you then indeed it's a huge pain.


Well, at least SOAP uses XML which has defined the basic formats. I hate that there are at least three different datetime formats in JSON and they are all used. WTF! SOAP isn't that bad if you stay away from WS- extensions


A lot of protocols and standards containing the word 'simple; aren't. Most of them, in fact! I have a suspicion that this is because these designs start as antitheses to existing complex designs. 'Aha!' say the designers. 'We won't repeat those mistakes!' But because they proceed from the same basic assumptions as the complex designs they try to replace, they always produce something complex in the end, because they never really understood simplicity.


SMTP is pretty simple I would say


Depends how many of the encoding options you want to support. http://fanf.livejournal.com/64533.html


The S in SOAP is for Simple as the L in LDAP is for lightweight


People who mock LDAP for not being lightweight have obviously never dealt with DAP.


The existence of a worse thing does not justify a bad thing.


What makes it so bad? I haven't looked at it in a while, but I don't remember having a beef with the original LDAP:

http://www.ietf.org/rfc/rfc1777.txt


I think while LDAP may qualify as "lightweight" the fact it uses ASN.1 BER does, in my opinion, make it fail the "simple" test.


For what it's worth, the "lightweight" here is not an assertion that it is lightweight in an absolute sense. It's a modifier on OSI's Directory Access Protocol: http://en.wikipedia.org/wiki/Directory_Access_Protocol

It's hard for people to imagine now, but at the time the Internet was just one of many competing network standards. Had this been developed after the rise of the web, I'm sure it would have been a very different protocol.


LDAP was, in fact, developed after the rise of the Web. By Netscape!

(And SMTP, gopher, and finger were developed before the rise of the Web.)


Definitely not true. The first LDAP implementation was published in 1993, and was worked on for a while before that internally at the University of Michigan:

http://en.wikipedia.org/wiki/Tim_Howes

The first real browser, Mosaic, was released the same year.

Eventually Howes went to Netscape, but Netscape didn't exist until 1994, and Howes didn't join them until 1996


It started out that way, but then they made all of CORBA's mistakes.


Yeah -- before the enterprise types got a hold of it, SOAP was actually fairly pleasant to work with. Sigh. Oh well.

You can kind of get a flavor of what pre-enterprise-jackassery SOAP was like to work with by looking at Dave Winer's XML-RPC (spec: http://xmlrpc.scripting.com/spec.html), which was one of the precursors of SOAP.


That's a good point - didn't CORBA also start fairly straightforward (I can't believe I said that) but then grew extra layers of mind numbing complexity for transactions, security etc. - pretty much like the various weird WS-* specifications that most people seem to ignore?


S for simple really comes apart in "SNMP".


Hmph. Having tried to use SNMP on occasion, I always assumed S was for Sinister. Or perhaps Special.


I just figured the 'S' was a shortened form of "WTF?!?"

I'll admit I can't figure how they got to 'S' from there, however.


They must have got the absolutely brilliant idea of conflating null with the empty string from Oracle.


Ran into this with a REST XML API recently where someone was trying to do some reflection-type serialization of XML. The API had longitude and latitude of all train stations, and some genious decided to call the tags 'lat' and 'long'. 'long' conflicted with the datatype Long and it wasn't fun. Version 2 of the API has fixed this issue luckily.


"Lat" and "Long" seem like great tag names for this purpose. It sounds like the problem wasn't this guy, but the "reflection-type serialization of XML".


Sure, it's partly both, but 'lat' and 'lon' are used almost universally across Geo-related APIs. See Google Maps for instance.


I think the absence of the element/attribute is the best way to define null assuming your XSD is set up properly. Many XML marshalling libraries work well with this approach.

(note, I too have long since abandoned SOAP)


I've had the joy of working with a SOAP endpoint that doesn't recognise <element /> syntax, which left me having to create attributes assigned to '' in my Python code, so SUDS would generate the <element></element> syntax for me.

They also massively over-engineered the endpoint, constantly wrapping elements within elements, for no real reason.


That's always annoyed me: sure, XML can be heavyweight but if we're going to use it we should at least get the benefits.

Naturally that line of reasoning didn't get very far with the “maintainers” of an internal purported-SSO system with a SOAP endpoint which crashed on non-ASCII data or SQL special characters in the submitted username / password values.




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

Search: