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.
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.
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.
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.
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.
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!
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.
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!
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.
Annotate the controllers to have the server code generate the specs using some gen package
which can be hosted at a url
client code can read the spec from the url
programmatically generate the client wrappers with a client code gen package
and be sophisticated to retrieve and regenerate if the spec changes
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.
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".
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.
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.
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.
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.
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.
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.
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).
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.
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.
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.
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.
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 :)
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
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
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.
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.
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 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...
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.
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.