Meme transcription: Panel 1. Two images of JSON, one is the empty object, one is an object in which the key name
maps to the value null
. Caption: “Corporate needs you to find the difference between this picture and this picture”
Panel 2. The Java backend dev answers, “They’re the same picture.”
Post funny things about programming here! (Or just rant about your favourite programming language.)
I don’t get it. The key still gets declared, but it’s value is null. “name” in an empty object would return undefined, not null, correct?
(Yes, this joke whooshed, but I am curious now.)
Indeed, and that turns out to be a problem if the JavaScript expects the key not to be there, but instead it is there. And then you try to tell the backend dev that the key shouldn’t be there, but he’ll try to convince you that it’s the same whether the key is not there or whether it’s assigned
null
and then you wonder if he’s messing with you, but actually he isn’t and then the only thing keeping you sane is bitching about it in meme form on lemmy.deleted by creator
If I remember it correctly, per the JSON definition when a key is present but not expected it should be ignored.
The reason for that is to maintain compatibility between versions: it should be possible to add more entries to the data and yet old versions of the software that consumes that data should still continue to operate if all the data they’re designed to handle is still there and still in the correct format.
Sure, that’s not a problem in the blessed world of web-based frontends where the user browser just pulls the client code from the server so frontend and backend are always in synch, but is a problem for all other kinds of frontend out there where the life-cycle of the client application and the server one are different - good luck getting all your users to update their mobile apps or whatever whenever you want to add functionality (and hence data in client-server comms) to that system.
(Comms API compatibility is actually one of the big problems in client-server systems development)
So it sounds like an issue with the way your JavaScript library handles JSON or your own implementation not handling per-spec the presence of data which you don’t use.
Granted, if the server side dev only makes stuff for your frontend, then he or she needs not be an asshole about it and can be more accomodating. If however that data also has to serve other clients, then I’m afraid you’re the one in the wrong since you’re demanding that the backwards compatibility from the JSON spec itself is not used by anybody else - which as I pointed out is a massive problem when you can’t guarantee that all client apps get updated as soon as the server gets updated - because you couldn’t be arsed to do your implementation correctly.
The trouble is, in this specific use case, the data may either be there or it may not be, depending on authorization. I’m checking specifically if the key is present to determine whether the user has access to that data (and display a toggle for that data), or if the user mustn’t see it and thus doesn’t need the toggle.
The wrong assumption was that if the key is there, then the value is not null. That assumption was invalidated by an update on the server side. Of course I could’ve checked if the value of the key is nullish. But it’s still annoying to have a breaking frontend because the backend changed how it serves its data.
That sounds like an error in the specification of the client-server API or an erroneous implementation on the server side for the last version: nothing should be signaled via presence or absence of fields when using JSON exactly because, as I described in my last post, the standard with JSON is that stuff that is not present should be ignore (i.e. it has no meaning at all) for backwards compatibility, which breaks if all of the sudden presence or absence are treated as having meaning.
Frankly that there isn’t a specific field signalling authorized/not-authorized leads me to believe that whomever has designed that API isn’t exactly experienced at that level of software design: authorization information should be explicit, not implicit, otherwise you end up with people checking for not-in-spec side effects like you did exactly for that reason (i.e. “is the no data being returned because of user not authorized or because there was indeed no data to retunr?”), which is prone to break since not being properly part of the spec means any of the teams working on it might interpret things differently and/or change them at any moment.
The instance I was bitching about was this: There’s a lot of region-specific data coming from the backend. But the user is only authorized for certain regions. So for instance the North-American guy gets this object:
{ "CA": [/* list of stuff */], "US": [/* list of stuff */], "MX": [ /* list of stuff */ ]}
, while the US-only guy only gets{"US": [ /* list of stuff */] }
. Are you suggesting that the response should also include flagsisCaPresent
,isUsPresent
,isMxPresent
for every country?The issue with
null
vs not present surfaced because I, the frontend, checked if the returned object contained the key"CA"
and then tried to iterate over the list of stuff, which happened to be null, which is hard to iterate over. I agree that I could’ve checked if the key was present and not null.The meme, however, was lamenting that the backend developer, refuses to acknowledge that these two JSONs are different,since they only see their POJOs, where both map to
CA: null, US: [], MX: null
.If it’s part of the Requirements that the frontend should handle “No results found” differently from “Not authorized”, even if that’s just by showing an icon, then ach list of stuff which might or not be authorized should have a flag signalling that.
(This is simply data analysis - if certain information is supposed to be shown to the user it should come from somewhere and hence the frontend must get it from somewhere, and the frontend code trying to “deduce it” from data it gets is generally prone to the kind of problem you just got because unless explicitly agreed and documented, sooner or later some deduction done by one team is not going to match what the other team is doing. Generally it’s safer just to explicitly pass that info in a field for that purpose to avoid frontend-backend integration issues).
Authorization logic is almost always a responsibility of the backend (for various reasons, including proper security practices) and for the frontend it’s generally irrelevant why it’s authorized or not, unless you have to somehow display per-list the reason for a it being authorized or not, which would be a strange UI design IMHO - generally there’s but a flag in the main part of the UI and a separate page/screen with detailed authorization information - if the user really wants to dig down into the “why” - which would be using different API call just to fill in that page/screen.
So if indeed it is required that the frontend knows if an empty result is due to “Not Authorized” rather than “No results found” (a not uncommon design, though generally a good UI design practice is to simply not even give the user access to listing things the user is not authorized to see rather than let the user chose them and then telling them they’re not authorized to do it, as the latter design is more frustrating for users) that info should be an explicit entry in what comes from the backend.
The JSON is indeed different in both cases, but if handled correctly it shouldn’t matter.
That said, IMHO, if all those 3 fields in your example should be present, the backend should be putting a list on all 3 fields even if for some the list is empty, rather than a null in some - it doesn’t matter what the JSON is since even at the Java backend level, a List variable with a “null” is not the same as a List variable with a List of length 0 - null vs empty list is quite a common source of mistakes even within the code of just the one tier, though worse if it ends up in API data.
Who is wrong or right ultimately depends on the API design having marked those fields as mandatory or optional.
I’ve worked back and front end, and with a lot of developers, and I don’t think anyone would say they’re the same. Software devs are some of the most pedantic people out there.
For many uses it is semantically the same.
But for cases where you need to know if something was intentionally set to null or was simply not set, the difference is enormous.
there is no “undefined” in java. this would either be a map containing the key value pair (“name”, null) or it would be mapped to an object of some class with an attribute “name” which can hold a null value. in any case {} wont equal {“name”:null}.
There’s no “undefined” in JSON either
Yeah, I’m also confused. If an attribute is null, I would prefer to simply not serialize it.
I’m sure there are edge cases where someone might prefer to include null attributes, but generally they should be treated the same either way.
That’s interesting. I’m on the opposite team. If a customer model defines an optional birthday, for instance, I’d rather have it serialized as a null value if it’s not available for a specific customer.
The biggest reason for me is that it’s less data to send over a network. Especially when I’m working with lists of objects, including null fields can add a noticeable chunk to the payload.
There are some cases where it might be worth it to differentiate “No value” and “No attribute”, but in most cases they can be treated the same, since the data should really be validated against a schema anyway.
Depends on the application. When the user is able to set the schema via database, then you cannot assume the shape of the data.
I’m not sure I understand what you mean.
Yeah, nevermind, I didn’t know what I wrote either. I need my sleep lol.
Imagine you’re writing a CRUD API, which is pretty common.
If null attributes aren’t included in the payload, and someone does an update (typically a PATCH), how do you know which fields should be nulled out and which should be ignored?
I agree for many cases the two are semantically equivalent, but it’s common enough to not have them be equivalent that I’m surprised that it causes arguments
For an API there should always be a version parameter/endpoint, imho.
Edit for further context: Ideally, a parameter.
I wasn’t taking about new fields. I was talking about resource partial updates (eg PATCH, or commonly the U in CRUD).
If you just want to update a single field on a resource with 100 fields, rather than GETting the entire resource, updating the single field, and PUTting whole thing back, just do a PATCH with the single field.
Likewise if you’re POSTing a resource that has nullable fields, but the default value isn’t null, how do you indicate that you want the default value for a given field? Do you have to first query some metadata API? That doesn’t seem ideal, when this existing pattern exists
Those are two very fair points - I agree.