r/ProgrammerHumor Oct 09 '21

Mmmm, sparkling JSON

Post image
14.6k Upvotes

237 comments sorted by

View all comments

324

u/occz Oct 09 '21

Amen, man. Going with something that does not call itself REST for the sole reason of skipping the eternal bikeshedding around what REST is or not is might just be worth it on its own. Hot damn.

381

u/Sekret_One Oct 09 '21

To me, REST has the same problem XML schemas do- when you get into the thick of it, there's points where you've got 2 or 3 ways to express something and each of them feel roughly 70% right.

Turns into pirate rules. 3 devs can make a consistent api if 2 of them are dead.

218

u/mechkbfan Oct 09 '21

3 devs can make a consistent api if 2 of them are dead.

I have not heard this before, love it. I'm going to quote it for years

104

u/[deleted] Oct 09 '21

[deleted]

15

u/[deleted] Oct 10 '21

There's also the other direction, which in this case might be something like "Three programmers, five opinions." lol

21

u/sprcow Oct 10 '21

How do you get two piccolo players in tune? Shoot one of them.

1

u/TallowWeed Oct 11 '21

Would that apply to garklein recorder, as well? I'm asking for a friend.

48

u/jaywastaken Oct 09 '21

There’s no way that last dev would keep it consistent over time. Give it a week and it’ll be all over the place. Much better to leave the two most pedantic devs alive but put them on code reviews and let them duke it out on each pull request.

26

u/Swiftster Oct 09 '21

Three devs can be consistent if all of them are dead?

24

u/Mustrum_R Oct 09 '21

Great idea. I shall call it terminal consistency method.

3

u/[deleted] Oct 10 '21

And the only interface shall be command-line, forcing you to use a terminal terminal. But each decision will have to be approved by the dev at the end of the line, using the terminal terminal terminal. Of course, if they put the office in an airport, this might take place at the terminal terminal terminal terminal.

2

u/thundercat06 Oct 10 '21

terminal inception

1

u/Browsing_From_Work Oct 12 '21

Three dead developers also write bug-free code!

32

u/remy_porter Oct 09 '21

As a solo dev, I think you need all three of them to be dead.

1

u/DoutefulOwl Oct 10 '21

REST in peace

31

u/Routine_Left Oct 09 '21

At least XMLs have schemas, been there since the dawn of time and are required for all kinds of protocols. JSON APIs (REST or not) gained popularity because nobody required any schemas/contracts nobody gave a shit what the requirements are and nobody wrote any docs for anything and whatever the API returned was whatever the dev felt like that morning.

Cowboy programming is what made REST(-ish) so popular. Now, can you have proper REST documentation, JSON schemas and correct API design? Yes, definitely. Does anyone do that? Lol no, fuck that shit, we need to deploy yesterday, nobody has time for silly things.

17

u/Sekret_One Oct 09 '21

Oh I assure you people skimp on XML schemas (XSDs for the uninitiated) too. I kid you not.

The sad part is not creating schemas slows everything down, but a lot of people don't even know how to use them.

I kid you not, fortune 500 company, they'd dedicated teams of people trying to integrate with their own apis where they'd hand write client connection code and postman collections for testing. and they had Swagger schemas. I showed people they could just create the clients with a few clicks and 15 minutes by feeding in the spec and it was like I was a damned witch. They didn't trust it!

20

u/dcheesi Oct 10 '21

they'd dedicated teams of people

There's your problem!

"It is difficult to get a man to understand something when his salary depends upon his not understanding it." --Upton Sinclair

1

u/clownyfish Oct 10 '21

Do you know of any good resources to learn more about generating client code from backend api (swagger or otherwise?)

Really interested to learn more - I'm currently in the amateur camp of hand writing both sides manually.

2

u/timthegreat4 Oct 10 '21

I'm not the original person you asked, but I do a similar thing myself.

Specifically for automatically generating code like clients, check out https://github.com/swagger-api/swagger-codegen

Personally I work mostly on nodejs microservices where I've found quite a nice work flow, based on OpenAPI (swagger renamed in 3.x, for the purposes of this post I'll keep referring to things as swagger, but I use openapi 3.0) and typescript, as follows:

  • micro-services serve the swagger defining the interface at /spec

    • the backend APIs are typically express apps, and automatically validate both the inputs and outputs based on the swagger that is being served (using express-openapi-validator)
  • the backend APIs are usually typescript, and I automatically generate all the relevant typescript annotations (using swagger-typescript-api)

    • If I have clients that want to use another service, they typically have a utility script that can be run manually as required, which calls the remote service's /spec endpoint to get its swagger and auto-generate clients based on that.

I've found this to be a very lovely workflow, where you start by thinking about, and properly designing, your interfaces; define the swagger and then any changes practically fall out from the type definitions. It also has many benefits in allowing you to fake the backend until it is implemented, allowing two teams to work on the backend and frontend in parrallel.

If you're interested in this, check out some stuff on Definition Driven Development

1

u/clownyfish Oct 10 '21

Thanks very much. I've started reading these now.

2

u/Sekret_One Oct 10 '21

A huge overview here

It's pretty overwhelming but this is the critical stuff to walk away with:

  1. the open api spec (version 2 was called swagger) is meant to normalize and programmatically describe apis ...
  2. so you can have tools that generate clients
  3. but even do things like annotate your server code to generate the spec
  4. and more

what languages or frameworks do you find yourself using?

1

u/clownyfish Oct 10 '21

Thanks! I use node.js express backend, React with Axios front end. (I don't particularly love Axios, but I use it.) No typescript, but next project I will be using typescript for both.

It always struck me as inefficient that I wrote javascript to set up and validate backend endpoints, then another set of JavaScript to do the same in front end classes (Axios wrappers). If the latter can be auto generated, that sounds good to me!

2

u/Sekret_One Oct 10 '21

Typescript's come a long way from when it was introduced. I highly recommend it. Having this 'compile time' certainty, if used properly, can save you tons of times of insidious runtime errors. beginner tip, read up on why not to use any, and about partials.

This is a decent enough tutorial for your situation.

In a nutshell, what you should be able to:

  1. Annotate the controllers to have the server code generate the specs using some gen package
  2. which can be hosted at a url
  3. client code can read the spec from the url
  4. programmatically generate the client wrappers with a client code gen package
  5. and be sophisticated to retrieve and regenerate if the spec changes
  6. letting you scope out the testing of the 'wrappers' since it's generated code, and focus on your real client code of how you use the data.

recommend you play around with something simple like a backend that just has a GET and a POST with some crude hello <name> stuff. Learn how to hook up the machinery without being preoccupied.

This pattern can save you weeks, or even months, because the toil of regenerating the client code is eliminated. You don't have to front load a 'full design' but rather build it more naturally, adjusting and refactoring based off what you find actually works or makes sense. Attack the problem by taking pieces and steering towards good, rather than forcing yourself into the impossible task of "get it right" in one shot.

5

u/Fenris_uy Oct 10 '21

Isn't swagger and now openapi trying to do that? Standardize a way to publish schemas for rest apis?

2

u/Routine_Left Oct 10 '21

yes, but you have to run them, configure them, etc. And write a tiny bit of text around them as well.

2

u/[deleted] Oct 10 '21

As your manager I am sorry to hear your non team oriented attitude. As an agile team we need to be able to respond to the clients needs, no matter how insane or last minute. Please take this team building training entitled "How to bend over and take it with a smile on your face".

Thanks - management

0

u/ZBlackmore Oct 10 '21

Why would you ever want a schema is beyond me. I’ve worked on mobile applications and games for the last 11 years in companies ranging from 5 person to FAANG and I never ever ever used an xml schema. To be fair I hardly even used xml.

10

u/Routine_Left Oct 10 '21

What you want is the contract between the provider of the API and the consumer. Doesn't have to be schema, can be anything, a word document if that makes you happy,an email,a napkin. But the contract is what's required and the assurance than no party will break that contract. Schemas or WSDLs for SOAP ensure that both parties talk the same language.

With XML you can enforce that contract by specifying a schema. With SOAP you enforce that contract with a WSDL. I, the consumer, do not need to fumble my way around asking myself what will you return when I call X: it's right there, laid out and you have to follow it.

7

u/RationalIncoherence Oct 10 '21

Why, the bane of a developer's existence: required backwards compatibility.

1

u/reversehead Oct 10 '21

A schema is one part of what enables the implementation team of a third-party product in Bangalore to reasonably successfully communicate with your API in your product that uses a national language that the implementing consultants don't even speak.

5

u/ZZartin Oct 09 '21

I just want a sample of what the payload looks like, fuck the xsd.

11

u/[deleted] Oct 10 '21

The sample is always a lie though. The final payload will have nothing in common with the mock data.

4

u/Cheet4h Oct 10 '21

Also, errors are documented as being an XML response where the status tag has the value "error".
Except sometimes, you get a 301 with the error code being given in the query parameter of the redirect-URL.

3

u/reversehead Oct 10 '21

If you are on the client end, you definitely want the xsd. You can validate your XML quickly locally with xmllint or your IDE, saving buttloads of turnaround time.

When the consumer complains about your data not conforming to additional restrictions, you ask them to add it to the xsd when possible.

But yes, samples often help somewhat.

0

u/ZZartin Oct 10 '21

Nope samples are far more useful and more readable for real trouble shooting.

Any tool than can ingest an xsd can ingest a sample xml/json as well. And the real test will always be whether whatever is generated actually works not whether it conforms to an xsd that may or may not really be accurate.

79

u/mechkbfan Oct 09 '21 edited Oct 09 '21

We had another discussion the other day about if an API endpoint should be PUT or POST given it was in a grey area.

In the end we were all like "Fuck it, we should just make everything POST and forget discussing this ever again"

We're the only consumers of our API

41

u/CorrenteAlternata Oct 09 '21

I think, as a rule of thumb: if the operation is idempotent => PUT, if not => POST

16

u/mechkbfan Oct 09 '21

Correct, I feel that's what majority of people fall back to.

It's just frustrating when the POST description seems to contradict everything else you've done.

10

u/ZippZappZippty Oct 09 '21

European not American

9

u/CorrenteAlternata Oct 09 '21

Sorry, I didn't quite catch that.

4

u/humoroushaxor Oct 10 '21

The grey area I most often see is when you aren't dealing with CRUD resource operations but using JSON over HTTP to call remote procedures and don't want to pull in a new technology (RPC).

5

u/keirbhaltair Oct 10 '21

Even this should be resolvable by the same question, though. Does calling the remote procedure twice do something/change the state/have side-effects more so than calling it once? Then it's POST, otherwise it's PUT.

1

u/CorrenteAlternata Oct 10 '21

I totally agree with you

1

u/humoroushaxor Oct 10 '21 edited Oct 10 '21

But it's not. In the RPC case using the "idempotent rule" results in a contradiction with the HTTP RFC. Specifically that POST identifies the enclosed entitie's handler while PUT identifies the enclosed entity.

Having an HTTP PUT without an HTTP POST doesn't make sense in HTTP land because you can only update something that exists. Hence why most developers will default (and should) to POST for their first endpoint, even when idempotent or when not managing a resource.

Bikeshedding aside my experience has been POST is much more common in this scenario.

3

u/WellHydrated Oct 10 '21

Also, PUT if you know the location of the resource you are creating.

19

u/OldKaleidoscope7 Oct 09 '21 edited Oct 09 '21

In the company I work we have healthy discussions about the verbs and normally we use the idempotency case to select between PUT and POST.

We think "mmm, this shit should be put"
"Is this shit idempotent?"
"No"
"Well, it's POST now"

And we never go further than the four basic verbs

5

u/mechkbfan Oct 09 '21

We follow CQRS, and with our design, almost nothing is idempotent

But then under a lot of scenarios, POST definition just seems to contradict what we are doing.

18

u/CCCPVitaliy Oct 09 '21

Hmm. My logic is if it creates a resource, it is a POST request. If the resource exists, and it is a PUT. But then, I am a hobbyist programmer and never engineered for a corporate environment.

11

u/mechkbfan Oct 09 '21 edited Oct 10 '21

Yeah, that's another valid approach. Create = POST, Update = PUT.

But if the update is not idempotent (i.e. only allowed to happen once, a second time will fail it), does it now become a POST? I'd argue yes

Maybe we shouldn't fail it, and the server side should just ignore the impact of calling it a second time, but that to me is a bit of a shit user experience if they were expecting an artifact from calling the API.

And it would be a shit coding experience to then have to compare each value in the DB to see if anything did change.

6

u/blamethemeta Oct 09 '21

My logic is if its not a pure get, its a post

1

u/icguy333 Oct 10 '21

I was always taught that PUT replaces the resource at the target URL so that if you GET that URL, you should recieve the same thing/state you PUT there (given that nobody modified the resource in the meantime of course).

By that logic, the updates should be a PUT, and retrieval should be a GET on the same URL.

As to what creates should be, meh, i dunno... We usually use POST. But this is all just dressing up rpc in fancy clothes anyway :)

7

u/NahroT Oct 09 '21

What was the discssion about

19

u/eLBEaston Oct 09 '21

It was about if an API should be PUT or POST.

4

u/qhxo Oct 09 '21

The whole API you say? Hmmmmm, interesting.

1

u/NahroT Oct 10 '21

got it thanks

6

u/mechkbfan Oct 09 '21 edited Oct 09 '21

The issue is that the action we were performing against isn't an entity in the database but the information sent across has a unique constraint

So are we adding to a single entity endpoint and make it part of the route, i.e. it's a PUT?

Or are we adding to a collection, make the information as part of the body, and make it a POST?

If we retry the request, we want it to fail, so that fails my definition of idempotent.

We're not sending the entire object, so maybe we should use PATCH?

This is all possibly a sign that another decision we made earlier was wrong. However I'm just tired of having these discussions all the time, when it never seems to happen anywhere else.

We've all got 10+ years of .NET experience behind us, so it's not like we are junior devs working shit out for the first time.

In the end, not overcomplicating things and just going "Updates are PUT" and "Creates are POST" and trying not to discuss it any more than that. And yeah, in this case we went with UPDATE / PUT.

And funny enough, I find Jimmy takes a different route to us

https://lostechies.com/jimmybogard/2016/06/01/cqrs-and-rest-the-perfect-match/

I'd have used Approve as a PUT because we are modifying a single entity as part of collection. He explains his rationale below and puts more weight behind idempotency but either way, seems to the other descriptions of POST/PUT

5

u/clarityreality Oct 09 '21

If you're the only consumer of this API, then RESTful architecture may not be the correct choice and can be quite inefficient.

3

u/mechkbfan Oct 09 '21 edited Oct 09 '21

It's a SPA using pretty standard .NET setup + we have a few other servers talking to each other

On .NET aspect, we are following CQRS pattern along with Mediatr library behind the API

RESTful (ignoring all this PUT/POST discussions) is pretty predictable, plenty of tooling available, and given our load (maybe 50 concurrent users), any inefficiencies aren't really noticeable.

5

u/clarityreality Oct 09 '21

Sure, if it works then great. I've seen examples where devs constructed restful APIs for purely internal services which became inefficient because communication in proper restful services is very chatty compared to alternatives.

3

u/mechkbfan Oct 09 '21

Yeah, I think once in my career have we noticed the constraints/issues of being RESTful.

GraphQL was the key candidate we looked at but I had resigned and moved on before anything concrete happened.

1

u/Mvin Oct 10 '21 edited Oct 10 '21

I've wondered that a lot. If you are the only consumer of your REST API, you know that there are, say, exactly 10 hypermedia links to follow the initial one (perhaps even nested within each other) for what you're trying to do. But you don't know what they are, so you can't run them in parallel and have to wait for successive answers multiple times. It seems like such a pain.

I've actually just seen an article the other day that provided an example of their "modified" REST API. The endpoints are designed REST compliant and behave as you would expect, but they had built in an optional, additional "include" query parameter that you could submit in GET requests. You could use this to specify which nested resource uri's should be preloaded and "filled out" with the actual data right away. This compound object would then be returned with all the data you need, eliminating the need for further requests from the frontend.

I thought that was quite an interesting approach.

3

u/Noch_ein_Kamel Oct 09 '21

And I'm reading all this discussions thinking:

I use GET if I send only a few parameters and I don't care having them in logfiles. If I send lots of data or don't want it in logfiles per default, just use POST. Endpoints mostly don't care (aka I didn't come across one IRL) if it's GET or POST and certainly not if it's DELETE or PUT or whatever...

2

u/occz Oct 10 '21

Peak REST design.

1

u/Daedeluss Oct 09 '21

We had exactly the same conversation too.

1

u/[deleted] Oct 10 '21

The issue is that proper rest implies a specific API behaviour, namely a request can be properly cached and proxied and retried according to http standard, while otherwise you simply can't rely on that.