23 ms·
I was expecting to see two of my pet hates - returning a null array to represent no items, and returning a single object without an array to represent one item.
by gtsteve 7y ago
I was expecting to see two of my pet hates - returning a null array to represent no items, and returning a single object without an array to represent one item.
I also once worked with an API where you had to send the data in POST format - abc=123&def=456. After much pressure from their customers, they finally relented and added an XML version of their API... where your request could look like this: <request>abc=123&def=456</request>.
Even better, note the & is not an & - you can't even use a standard XML parser to interpret the result.
Also: APIs that have a mix of strongly and eventually consistent calls and no documentation about which is which. Or, an API that was at one point strongly consistent turns eventually consistent without warning.
- akurtzhs 7y agoreturning a null array to represent no items To be honest, that's what I'd expect. What do you dislike about that result, and what would you prefer to see returned? Jump straight to 404? returning a single object without an array to represent one item. So an array if there's multiple results, and a bare object for a single result? That's unpleasant.
- saagarjha 7y ago> What do you dislike about that result, and what would you prefer to see returned? It’s inconsistent and means I need to write special case code to check for it, when before I could choose to. It should return an empty array.
- irishsultan 7y agonull array sounds like it's an array (presumably an empty one), it would have been clearer if OP had said null instead.
- saw-lau 7y agoNot sure why you're getting downvoted - that was how I read it as well.
- bobbylarrybobby 7y agoPresumably they would prefer an array always be returned. If zero items, an empty array; if one item, an array of length one; if more items, a longer array.
- deleted 7y ago[deleted]
- Sohcahtoa82 7y agoIf an API is expected to return an array, but the data set is empty, I expect an empty array. I should be able to go straight from the request to a for-each loop without checking for null.
- ergothus 7y ago> Jump straight to 404? That's my pet peeve. I completely understand the logic - using the HTTP status code to show the result of interaction with the resource is very RESTful - but my complaint is that unless you provide more context, a 404 doesn't tell me if I'm getting a response of "that resource doesn't exist" vs "you're accessing a url pattern that will never work". So if you want this random internet user to be pleased, never return a 404 response unless the caller is able to see this difference. (Usually having SOME form of body unique to the API is sufficient to prove the 404 is not because of a bad API call). Giving me the HTML to your site 404 page when I called a non-HTML API is likewise sad-inducing.
- WrtCdEvrydy 7y agoWe have only one pattern like this... when there's a client resource (containing personal information for contacting them) that the client has asked to be private... we return an empty JSON object (versus an object with the contact information keys)
- thaumasiotes 7y ago>> returning a null array to represent no items > To be honest, that's what I'd expect. What do you dislike about that result, and what would you prefer to see returned? Jump straight to 404? I'd expect an empty array to represent no items. It's the difference between "" and "[]".
- ako 7y ago404 indicates an error, if the result is just empty but not erroneous 204 "no content" may be better.
- wwweston 7y ago+1, 204 is underutilized for no-result cases.
- jbverschoor 7y agoIn the browser it will also do no page refresh as there is nothing to render.
- jandrese 7y agoWhat would you suggest instead of an empty array for a 0 item return?
- chihuahua 7y agoThe person you replied to doesn't like returning "null". He/she would probably prefer returning an array that contains 0 items.
- compscistd 7y agoThis makes sense now. If I did a GET to posts and got a "null", I would think I made some kind of error. If I get an empty array, I would (correctly) assume there are no posts yet. Basically, GET to posts would always return an array of posts. Whether there are 0 (empty array), 1 (just one object in the array), or many (array with n length). This makes API logic way easier to handle without having to check what structure I received even with a 200 status code
- WrtCdEvrydy 7y agoAlso makes a lot of iteration easier... just a for loop over the array to dump something on the page with no edge cases. You can add a warning by just checking the length against that array blindly.
- jandrese 7y agoHe called it a "null array" which I interpret as an array containing zero items. If it was just a plain old null then yeah, that's super annoying.
- BurningFrog 7y agoIf you return an empty array, I can always process the result by looping through the array. If it's sometimes an array and sometimes null, I need branched logic for each call.
- hermitdev 7y ago> returning a null array to represent no items, and returning a single object without an array to represent one item. This just reminded me of a long ago incident at a former employer. I worked in back-office at a hedge fund and was responsible for maintaining several APIs & services written in C++. The APIs were pretty straight forward query for object(s), get back a vector of objects. If nothing was found, you'd get back an empty vector. The company also had a program where they'd hire grad students right out of school and immerse them in the trading desk, working on trading algorithms and such. One such kid sent in a "bug report" directly to me, CCing all of front office. The "bug"? We was querying for something that didn't exist, so he got back an empty vector. He didn't check that it wasn't empty, and immediately accessed the front of the vector. Boom, segfault. Normally, I would have been kind to such a junior dev, but their original email was very condescending and went to an unnecessarily large audience - like hundreds of people that didn't have time for this. His email read something to the effect of "Your API is crashing my code. Fix your API." Instead, this junior got a whole other lesson instead. I replied all, and included all of back-office on the email (so the rest of the team was aware to watch out for this clown). "The API is working perfectly fine and as designed. The fuck up is on your end. You queried for something that doesn't exist and proceeded to dereference and empty vector. Fix YOUR fucking code."
- sealthedeal 7y agoI would expect an empty array to always be returned regardless
- tbirdz 7y agoI really don't like your story. The junior is clearly behaving immaturely and inappropriately by CCing others and not using an appropriate tone, but your response is to... retaliate by doing the exact same thing to him? What lesson is the junior supposed to learn here? That acting that way is A-OK as long as you have seniority and are factually correct? At least the junior has the "excuse" of being a junior, but really as a more senior person you should have known better. Surely there must have been a better way for you to handle this situation.
- 7y ago
- omgtehlion 7y ago> returning a null array to represent no items, and returning a single object without an array to represent one item this happens when you add JSON version for old XML-based APIs (seen this multiple times)
- purple_ducks 7y ago> this happens when you add JSON version for old XML-based APIs (seen this multiple times) ...without using an XSD schema. With a schema,not an issue
- deleted 7y ago[deleted]
- favorited 7y agoThere's often a semantic difference between null and empty. Like, if I'm checking the result of a batch processing job, I want to know if the job finished & resulted in an empty set, or there is simply no result yet. It's "the thing you're looking for doesn't exist" vs. "the thing you're looking for exists, but is empty."
- gtsteve 7y agoThat's fair to say I guess - but it should be accompanied by some other property to indicate a condition like that. The API I'm thinking of though was effectively a wrapper around a database query which retrieved items. That's what gets me about that decision you see. When you get nothing from a database, you get an empty set. The runtime was some version of .NET Framework, which by default would write an empty set as an empty array. So it wasn't even an accident - someone actually had to add extra logic to make it return null.
- hnick 7y agoPerl's DBI module gets around this with a value "zero but true" aka 0E0. It is useful in cases such as indicating an operation was successful, but zero rows were affected. Using it as a number resolves to zero, using it as a boolean results in true. I think in the general sense under API though, a status flag is the best way to avoid confusion as you say. Null could just as easily mean 'error' as 'not yet finished'.
- sopooneo 7y agoI've seen this happen due to system evolution. At first some entity may have a parent record or not. So when you ask for the parent, you either get it, or null. But then the system evolves to not be many-to-one, but many-to-many. To avoid breaking old clients, they make it so the only difference is when they return multiple related records, in which case they're given in an array. Thus you now have: null for empty, the record it self if there is only one related, and an array of records if there are more than one related.
- 7y ago
- inputespresso 7y agoFor those Gophers reading this and sobbing silently, there may be hope: https://github.com/golang/go/issues/27589 https://github.com/golang/go/issues/27589
- lilyball 7y agoWhy would you want to marshal a nil slice to json as non-null? That just hides the fact that you had a nil slice. In fact, that's the exact opposite problem; representing nulls as empty arrays.
- simiones 7y agoAs explained in the thread, that is because Go best practice is to treat `nil` and `[]T{}` as the same thing in every API. If you want an explicit `null` in your JSON you can use `*[]T` as your field type, and then it makes more sense. The very idea of allowing the nil value for slices seems to be very strange and inconsistent, as slices are struct types, not pointer types in Go (they contain a pointer and other members). Just one of the many ways that builtin types in Go are fundamentally different from user-creatable types, I guess...
- lilyball 7y agoIt is admittedly very weird that Go supports nil slices/maps instead of just having the nil value be an empty slice/map that points to constant storage. But as long as Go has a semantic difference internally, representing that as null externally makes sense. Though I suppose as long as the conversion from null to empty array/object is opt-in it's fine. For context, we recently had a bug where backend forgot to initialize their map, so they were sending us a null where we expected an object, and it would have gone undetected for much longer if the JSON didn't contain a literal null there.
- yencabulator 7y agoThe nil value for a slice is an empty slice that points to constant storage: Data=0, Len=0, Cap=0. That's just not the same as Data=somethingelse, ... which you get if you allocate something. (And all Go zero values are exactly what you get with the relevant RAM filled with the zero byte.)
- Ididntdothis 7y ago“returning a single object without an array to represent one item.” I saw the same thing when working with PHP consuming data from a SOAP endpoint. First I thought PHP is stupid. But then I realized that XML can’t model single item arrays versus single objects. They look the same. JSON is better that way. You can model empty arrays and single item arrays.
- benoitg 7y agoYou can force PHP to handle sngle-element arrays consistently, with the SOAP_SINGLE_ELEMENT_ARRAYS option, the behaviour is much saner when enabled.
- Ididntdothis 7y agoGood to know! Unfortunately I have a call to a “FixSoapArray” all over the code already :(
- thaumasiotes 7y ago> XML can’t model single item arrays versus single objects. They look the same. <results> <result> <property>value</property> ... </result> </results> I don't really see the problem.
- Ididntdothis 7y agoYou need to know that “results” is an array so you need the schema. In JSON an array is an array without doubt.
- thaumasiotes 7y agoIf you don't know that "results" is an array... how do you handle the uncontroversial case of getting back an array of two results?
- Ididntdothis 7y ago
- jiggawatts 7y agoI had this happen with a vendor that was told that they needed to add REST support to their legacy Java app. They turned up with an API that encoded XML as base64 and put that in a POST variable on HTML page. Then they added their own crypto on top with hard-coded RSA keys. They helpfully included both the public and private keys in their documentation. When they turned up for a meeting to present the fruits of their labour they got patted on the back by all the managers for a job well done. Record time too! They faces fell when I told them that I'm flat out rejecting their API design and that they will have to start from the beginning. Their excuse for the design was that ampersands are too hard to process, so base64 encoding made them "safe" to include in the REST API. Sometimes you just have to put your foot down about this kind of idiocy.
- arethuza 7y agoUnfortunately I have vivid memories of one API I worked with (many years ago) that included entire encoded XML documents as attribute values within top level XML. At least there was only one level of recursion. Still, perhaps not as bad as using XML documents as database keys...
- tasogare 7y agoI saw that in HTML. Not from a professional developer but it still blow my mind. That was the final straw that made me quit the project.
- jefftk 7y agoI've needed to do that for HTML. If you need to put part of a document inside an iFrame (perhaps because you don't trust it) you have your backend generate <iframe sandbox srcdoc="..."> and nest it.
- perl4ever 7y agoA common misconception is that you can put anything in xml via CDATA so long as it doesn't have the ending delimiter embedded. https://stackoverflow.com/questions/21087648/xml-invalid-characters-when-creating-cdata-node-from-unicodestring https://stackoverflow.com/questions/21087648/xml-invalid-cha... I know about this because I received a file with illegal CDATA characters once.
- donkeyd 7y agoI worked with a product for natural language processing that wanted the text in a query string. This led to 100+ page documents begin sent as a string in the request. My usual REST testing app would freeze up if I wanted to test some of the largest documents in the data set.
- sangnoir 7y ago> This led to 100+ page documents begin sent as a string in the request How were you able to do this when the standard maximum length of a query string is 1024 bytes? I guess you could flaunt the standard as you were responsible for the backend
- Piskvorrr 7y agoExcept that standard...isn't. It's what some ancient version of MSIE did and that used to count for a standard in Triassic; nowadays, it gets passed around as cargo cult advice. (The relevant RFC recommends no more than 8000 bytes, sure.) https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers https://stackoverflow.com/questions/417142/what-is-the-maxim...
- sangnoir 7y agoIt's not cargo-cult: anyone who's worked on cross-browser front-end development probably encountered this at least once. I ran into this personally a few years back when I was trying to be too clever by half with base64-encoded queries. It's not just ancient IE that has limits - in my case it was a corporate proxy that was truncating the query (which is why only that customer was getting that bug). A year or 2 before that, I ran into the MSIE limit (must have been IE8 or 9: don't know if that counts as the Triassic period, because I don't know what we'd call the IE4-6 era)
- Piskvorrr 7y agoI did encounter this multiple times...not in the last decade though.
- bouke 7y agoI had the pleasure of working with the API of a customer that wanted to expose a JSON/REST API to their existing XML/SOAP backend. Instead of going the sane rout and re-use the XSDs to serve as the structure for the JSON, they just made the JSON structure up on the go. One child node? That would be one JSON object / value for you sir. Multiple child nodes? That would be on JSON array for you sir. No child node? No JSON type for you sir. So what happened when the amount of child nodes was dynamic? You would either get: nothing, an object, or an array of objects. Oh the fun times we had!
- leetrout 7y agoI bet $50 there was a junior dev promoted too high too fast proud of that technical feat.
- Xelbair 7y agoThat sounds like absolute nightmare - at least keep a convention.
- DCoder 7y agoThat reminds me of a vendor who wraps SAP Business One in their own webservice. This webservice has two business methods. The first one, ExecuteXML, takes an <XmlBody> representing a regular SAP B1 XML request and passes it on to one of the real SAP services. We have to find our own XSDs for the inner part, because they sure as hell don't have those. The second one is ExecuteSQL. It lets us run raw SQL against the SAP database. It doesn't have any support for prepared parameters. What it does have is a blacklist to prevent DDL and other funny business, such as semicolons. This blacklist runs on the raw string you send, and doesn't understand any escape characters. To send a string containing a literal semicolon, I had to turn it into CONVERT(VARCHAR(MAX), 0x...).
- deleted 7y ago[deleted]
- pbreit 7y agoI actually really like POST format. Very easy, very standard, very readily available. I also like that it encourages flatter data models.