my api is going to reply with "oopsie woopsie you made a mistakey" and you'll be happy
@VOXindie7 ай бұрын
hell yeah
@alexdarby93928 ай бұрын
In the enterprise corporate world, it is not as simple as using existing industry standards as business have their own set of requirements, for example, do not give detailed error messages in responses
@emmanuelrobles21248 ай бұрын
Exactly, we change base on the env, lower env we log and give error details, upper env we just log
@yurisich8 ай бұрын
I enforce unique error codes at the top of my handler, mapped to http response codes and a reason. When exceptions occur, a call to respond_with_error and the unique error code makes grep the best way to find out what caused the problem. In internal projects, having the source code is not uncommon, but if not support staff can always look it up before escalating it.
8 ай бұрын
Not returning details on 5xx codes is great, but not returning them on 4xx codes is one of the stupidest things one can do.
@emmanuelrobles21248 ай бұрын
@im going to disagree, there are some cases where that makes sense and some cases where too much info is bad
@somedooby8 ай бұрын
@ I think you might be misunderstanding 500 errors. They are supposed to indicate that you have fucked up, not the user. At the very least, you should have a debug mode that shows detailed errors, and you shouldn't reveal much in cryptographic errors (such as 403)... and you should categorize your errors so that 500 errors are not cryptographic errors. You can also provide an error code for 500 errors if you're really worried about leaking sensitive information
@olivier00038 ай бұрын
I am learning a new thing with your video. Never heard of that feature.
@XCanG8 ай бұрын
I didn't test it, but I don't like this suggestion. There are a lot of tools build around REST and some of them rely on MIME type, going to introduce more types would make those tools not recognize it as json, I believe even if I will look at response in devtools it wont parse it as JSON, but as a string and you couldn't interact with it the way you interact with JSON. You already have status codes. I would agree if you suggest instead of returning 200 Ok all the time, return like 400, 403, 409, 422, etc. But that's all that you need. There is 0 benefit for returning "409 application/problem+json" vs "409 application/json", because it's not 2xx/3xx, so there would be always the problem.
@stefanalecu95325 ай бұрын
If your application can't handle JSON under a different MIME type that clearly has JSON in its name, then that's a you problem, sorry, switch your tools. Any serious tool checks the input it receives
@XCanG5 ай бұрын
@@stefanalecu9532 bruh, I'm talking about browsers recognition and it is standard in any way. Using non-standart is smell of a code. You could use that in your own pet project, but don't bring something like that to masses.
@RushOrbit8 ай бұрын
Thanks for sharing this. Error messages are such an important part of a well designed API. I think the additional params being added with the balance and stuff are helpful. I would place them inside of a context object to separate domain data from the API error messaging. Lastly, error codes should not be done away with. Using error codes allows your frontend app to be localized so that the it can display the error message it wants to the user in that user’s language. Sure, you can return your error messages already localized, but making the API’s error handler aware of the user’s locale doesn’t sit right with me. Additionally, the interfaces may vary so the wording of the user message will differ (Tap to retry applies to mobile, but click to retry applies to a desktop app). I know a lot of this is preferential though. Many thanks! 👍🏼
@siya.abc1238 ай бұрын
68 and 421 were chosen at random I'm sure 😅
@agungokill8 ай бұрын
represent 69, 420 ? lmao
@zxenon_8 ай бұрын
Can you please enlighten me?
@u_long_u64_i647 ай бұрын
@@zxenon_ No need really, both are slangs
@zxenon_7 ай бұрын
@@u_long_u64_i64 🚶🚶
@martinaa5867 ай бұрын
Nice video!! Whats the program you use to made the draws while you explain, like the boxes and arrows. Thanks!!
@damongerman63767 ай бұрын
Recently, we introduced an aggregation service. The problem details contain the most significant error, and we add the other errors in the extensions as nested problem details.
@PatrickSteil8 ай бұрын
The spec needs a mandatory “resolution” field. Who cares what the error is. Tell the user how to fix it!
@billy65bob8 ай бұрын
In my API I had gone out of my way to wrap every single possible error I could into a single custom but consistent 'ErrorResult' object as application/json. Even went as far as registering custom filters and services just to ensure every single API source of 4xx/5xx errors would get caught too. A big motivation for me was that I had just dealt with a SOAP API that did error handling in about 20 different ways - it was infuriating. I guess I independently came to a very similar but more primitive solution than this standard. I'll have to keep this Problem stuff in mind for the future. That said, I'm not really too bothered with how APIs report their errors. I just ask that you *PLEASE* standardise on 1 method; not 2, not 5, not 1 per possible error condition, and most certainly do not extend that to be unique per API Call like that SOAP API did.
@Eirenarch8 ай бұрын
I am using problem details, not very happy about it. It is better than nothing but it is absurd that every attribute is optional according to the spec. In addition people tend to use the type as the equivalent of the status code just like you did in the video. This doesn't seem to be the original intent and even if it was it is useless. Unless you have the most generic bad request (i.e. the submitted data was not in the specified format) you want to have your own type on your own URL (you can skip actually having anything there if the consumer is your team). In your case where the bad request results from specific if branch in your business logic you need a separate URL. This lets the client handle the problem differently than regular bad request. You are putting these extensions, this number but how will the client know to look for it if your type is just like the type of any other bad request? P.S. just checked the newer spec. Well, at least now the type attribute is mandatory.
@amantinband8 ай бұрын
I tend to agree, especially around the previous spec not requiring any properties. The main difference in the new spec IMO is actually the registry though. Having standard error formats for common errors can be useful. In any case, even the old spec is better than nothing
@uuuummm98 ай бұрын
Well, at least we all can agree that if we need to put a text description of what happened this will be "details", not "error", "message" or "text". So it is very cool to know about such a standard. Many thanks for sharing to the author of this video.
@Eirenarch8 ай бұрын
@@uuuummm9 the most important thing is to agree on the discriminator, on the thing that says what the error is and indicates when one error is the same as the other error. They went half the way there in that there is the type property and thankfully they seem to have made it mandatory now (how the hell did they think it is OK to have it optional is beyond me) but it would be cool if they described in finer details that it is not OK to have 1 type per status code, it should be 1 type per error type and there are a lot more error types than status codes
@uuuummm98 ай бұрын
@@Eirenarch I agree that it would be ideal if api provided so detailed information about each type of the errors. But at the same time I understand that it is something that is never done. Even in libraries like SqlClient (if i remember correctly) you do not get a separate type of exception in case of foreign key or unique constraint fails. I had to always search inside the message for particular key words to provide a better error to the user. Same with python libraries i worked with (Django+postgres). So it is difficult to expect something different when you work with a web api. And I am glad that we have what we have here at least.
@tymekmajewski47187 ай бұрын
On first look, I think this only adds bloat without addressing *any* problems. Now you get the same info 4 times: 1. Status code, but also some json in the body: 2. link to a useless rfc; 3. the number 404 (again); 3. Text "Not found" All the examples show that "detail" field plus custom extension fields - which differ per endpoint - carry the useful error information. This different_data_per_endpoint was the problem we were suppose to solve :) The cherry on top is that this is *not* optimised for single line logging.
@Tidbit01238 ай бұрын
Hi, nice video :) What software are you using to draw on the screen?
@a.accioly8 ай бұрын
I would also like to know what software the OP us using to draw. It looks so smooth
@AnotherUTubeAccount8 ай бұрын
This is interesting, and might be a bit better than what i do now in my frontend api. One thing that i recommend is to use the instance property in the spec, and fill it in with a NanoID that you log on the server. That way you can pin a specific instance code to find related log messages. Thats similar to your request id, but i use a XXXX-XXXX format. And its much easier for people to read off than a UUID. And you can exclude vowels to make it easier.
@CarlosEstebanLopezJaramillo8 ай бұрын
I wonder how this plays with security, most people would say not to give too much info on errors, it could give away vulnerabilities and such.
@cat-.-8 ай бұрын
This really is a « There were 14 competing standards. There are 15 competing standards » type of standard
@fezhaez8 ай бұрын
Great Video! One question I have is about security. As far as I know usually if you are working on an API you want to obscure some of the errors to prevent misuse. Would giving out this detailed error be applicable only for internal APIs?
@amantinband8 ай бұрын
As a rule of thumb, the problem details specification should be used for error responses. What you decide to include/exclude will change based on the service, environment etc’
@VladPutin-f8m8 ай бұрын
When I worked at Atlassian I used to see Confluence 500 HTTP response had the full callstack lead all the way to ORM lib underneath, the callstack also include database credentials, all are laid on on the browser to end user. Pretty sure plenty of RETARDS are still doing similar things.
@adambickford87208 ай бұрын
@@amantinband I think he means the detail like the default 500. IME you use a more detailed version in sub-prod but strip this in prod (the custom sensitive properties).
@rbauer9618 ай бұрын
Correct. Never show clients stack trace. What you can do is log it server side and return an error ID to the client. The developer can look up the ID in logs for debugging
@evancombs51598 ай бұрын
I like it in theory, but I'm practice I've found very little use for it.
@shadowsir8 ай бұрын
We're using this kind of standard for our public API (the one we're exposing for other parties to consume). Our private API (the one we're using internally with our own clients) is less fixated on standards and uses whatever's best for the use-case. 😇
@handomize8 ай бұрын
Maybe this could be a benefit if its showing the error message to an ui, however i have serious doubts on the scalability of it. Because its a way more involved process to add and maintain across all of the project. I would wrap it in a data property so we could have a better type checking
@joe5head8 ай бұрын
Interesting, I'm curious about 2 scenarios. What would you return if the request is technically valid but it fails some business logic calculated on the backend? Also what would you return as a response if there are multiple objects sent in a request but there a mix of failures and successes?
@Rope2578 ай бұрын
I'd throw either a 406 or a 422 for the business logic failure. For the multiple objects simply rollback everything as soon you have 1 failure. If you're being sent batches then you should treat the end result as a batch and display which object in the request resulted in a failure.
@thegrumpydeveloper8 ай бұрын
Would be interested in a difference between this and the graphql error spec. Graphql is multi error by default which I like given that there could be more than one thing wrong or partial returns.
@charliecandimaunten16357 ай бұрын
I think the main difference is that this is for http apis, and graphql is not an http api. It's an api that happens to commonly use http as its transport, but there's absolutely nothing to stop you from serving graphql over protobuff, grpc, or a rawdog udp socket.
@Leonard0F41G8 ай бұрын
68.. 421.. I know what you did.
@TimvandenHof7 ай бұрын
Using these for a couple of years now. But curious how you all manages this towards an OpenApi specification. How do you document the responses? It is documented as that a HTTP400 Bad Request with ProblemDetails / ValidationProblemDetails is possible, but not the actual error a client might need to be aware of.
@ianklapouch7 ай бұрын
which extension are you using for vim motions? the default one that vscode has for me is slow from time to time
@MrAlkazam8 ай бұрын
Nice video, thank you for sharing these tips and tricks.
@TheSysmat8 ай бұрын
Extension should be a property and new object contained props
@darkmift8 ай бұрын
Great content! I would love to know which vscode plugin you use to make http calls
@amantinband8 ай бұрын
Rest client
@outrowed8 ай бұрын
There is a popular Rest client called Thunder Client for VSCode. It lets you do HTTP request and configure basically everything in it. And with it being VSCode plugin, you also get all the benefits of the text editor. Try it, I really recommend.
@necrotikS8 ай бұрын
Pretty recently I was thinking about how I could solve this problem and wondered if anyone had already found a solution because I think status codes can't translate everything, and it would be good to have a default way of solving it. I ended up creating an error object with some required properties which then are translated to a json response. If I had watched your video sooner, I'd probably have tried implementing the Problem Details Spec.
@ramireznoy8 ай бұрын
The biggest issue is that REST misuse and bad practices had made standard to embed transport level errors into app level. You must define your own app level protocol. In most web apps it is fine to start with something very basic. Because 99.99% of client request have one of two possible outcomes, it is successful or not. In this context success means the client request was resolved by the server following the ideal workflow (a login was good, an email was sent, a search was complete, a profile was updated). Any other condition just makes the app request fail. My starting point is always a DTO with this structure { success: boolean // false means the client must handle the non-ideal workflow. // a message was not sent, there is not enough disk quota, an exception was threw... // whatever cause the app to not to complete the use case. result: string // Default error message for human user if success is false. No implementation details // A custom type depending on the response type otherwise metadata: // A custom type depending on the response type, this is a message for the client, not the human user. debug: { error, stack } // Only available in dev environment. Very handy to locate errors quickly. // I also put metadata in the errors to have error context, very handy for integrations. } Sure, you still need to handle transport and network errors in the client side (timeouts, bad gateway, bad method, forbidden), but it is not your application responsibility to handle over those and they are the actual standard part that must be implemented across clients. For me this is way better than the RFC 9457 because it is simpler, flexible and have worked for me, the companies I have worked in and their clients for years now. The main disadvantage is you need to define specific Response types with their errors. But you still have to in any serious environment. And yes. MOST of the failed App responses are also 200. There is nothing wrong with it because it is the app responding. The resource is totally fine. The protocol defines enough information for the client to act accordingly unless it is an actual not 200 response from the platform. It makes the client implementation cleaner since all 200 are going through the app logic and anything outside it, means there is an infrastructure issue. So it is actually useful at the client side.
@necrotikS8 ай бұрын
@@ramireznoy ok, but why not use the standard? If there was a package that did all the heavy lifting for me, I'd definitely use it
@ramireznoy8 ай бұрын
@@necrotikSSure. I am not opposed to standards... As long as they make sense. In this case big red flags are the special response content type, the user centric response format and the lack of structure (meaning anyone will do whatever). Client friendliness is as important as server side aid in API development. The more I can help the client the better. Having extra content types, forcing or proposing error formats (in real life, there are many errors that are not meant for the end user) and having a lack of structure is not the best way to do it. In any case, this is no better than the one I use. Rest assured the moment something better shows up, I will switch happily
@thiagoconti50058 ай бұрын
off-topic: what tool do you use to draw on your screen?
@amantinband8 ай бұрын
Presentify (ZoomIt is a good alternative if you’re working on windows)
@matthiaskohler96158 ай бұрын
Don't get the benefit. The extensions are custom as well. It seems the initial problem of dealing with api error responses individually persists. Whats the benefit over http status codes and json response.
@Rope2578 ай бұрын
You still have the status-code, but the content of the response body is now guaranteed to both be JSON and have a type, title, detail and an instance property due to the RFC adherence. For API clients: If you're implementing a client that is dependent on APIs beyond your control all you have to do is request they adhere to the RFC and you're golden. You don't have to use the extensions nor should you when you do not control the API's. The benefit comes from a well-formed and well-defined response for every API that implements the RFC. Whereas now, most API's return a slightly different response body where you cannot count on any shared properties existing requiring you to handle errors differently for each API you depend upon. This is no longer necessary when they implement this RFC and shifts the maintenance "burden" from the client to the API. For API implementer: A well-defined and well-formed error-response aides an API implementer by removing some cognitive load concerning error structure. Meaning you're no longer per-occupied with what you should return, you already know, and you can extend it when you believe it is necessary to do so. If you're working contract-first (i.e. OpenAPI/Swagger spec.) then this is a godsend too. Since you can simply specify this content-type for the response body rather than some in-house JSON structure and you're done.
@nicholascopsey48078 ай бұрын
As an API implementer, if a client asked me to change the error handling to this I will tell them to kick rocks. In an enterprise environment needing to maintain a project having to implement this would take close to a year, while also needing to develop new features. Clients should only rely on the http status code, and any body is incidental and should be looked up in the API docs that you reference already when setting up the client.
@Suriprofz8 ай бұрын
What about localization, so multiple languages.
@OzzyTheGiant8 ай бұрын
Agreed, that's why I focus on http status code and custom "error codes", such as "not_found", "system_error", etc. Then I localize them on the front end.
@Ryan-gf1sz8 ай бұрын
wow that's pretty new spec
@drhdev8 ай бұрын
Don’t most clients use the error.message property? What do you think about mapping detail or title to message or would it be best to map on client side. Or should clients just start using detail and title?
@hernanar36478 ай бұрын
The users must use the specified error schema for errors, which must have how to interpret it, like this standard; if the users does not use the specified schema, is a user problem
@hernanar36478 ай бұрын
Also, the problem details standard is mostly used when a status code does not give enough information about the reasons behind the response. For example, a 403 when log in might not be enough if the app have many reasons of why forbid a user log in: maybe the user is not confirmed, maybe is not active (like in a soft delete case), perhaps is because the user tried to log in so many times that the app locks the log for 5 minutes, etc
@cat-.-8 ай бұрын
Error.message can expose server internal state if the thrower includes it in the error constructor. I never return error.message to the client.
@Rope2578 ай бұрын
They don't, for instance in Jakarta/Java EE, bad requests can be caused by the Bean Validation API. Which returns a ConstraintViolationException when a property of a request does not meet the constraints defined for it. The EE implementation you're using will serialize the exception and returns it as JSON in most cases. However, the way the EE implementation is not required to serialize a 400 and a 500 in the same manner. If you'd specify a content-type like this then frameworks can know how to format predefined exceptions/errors as a application/problem+json content-type. The only thing I do not like about this specification is that it appears to not factor in multiple error messages for a single request. Such as the constraint violations I mentioned above. The addition of a "details" property with an array of messages would have my preference. EDIT: I was just sifting through the RFC and Section 3 actually addresses my concern through extensions. Which is not what I was expecting, but they will probably have their reasons.
@matiaslauriti7 ай бұрын
In theory, any standarization is good, but only of EVERYONE follows it, in practice, you have requirements that, related to IT, the company or team do not care and you end up implementing what you need, not what one standarization tried to solve... 200, done, 4xx/5xx, send the correct status code, done... you are also exposing some data, that some companies do not want to, so? to hell this standarization... Just create your standard, stick to it, and make it as useful for you as possible, and document it, because it is going to be used by customers, period... There is no need to re-re-re-re-re-re-create the wheel, what software development sometimes is about... But, non-the-less, good video
@Azcane8 ай бұрын
I didn't know about AddProblemDetails. This seems pretty great to me, being able to just throw an Exception and have it automatically converted with metadata being added (headers etc.). This feels like a better way than using Problem() oneself. But just using an Exception, I can't specify an http error code. Is there a good way to combine both of those things?
@fortuneosho81378 ай бұрын
Different languages and framework has it own rules on handling http errors… fighting those framework just to get something like this might not be suitable for all applications
@gsilva8778 ай бұрын
Not that useful. You will define extensions for the real importante details, therefore you have to define your pattern anyway. That diminushes the value of stantard api since you are basically using your own pattern , the only things standardise are type, title, detail and instance which is kind of silly. I will probably use it with my custom defined schema, but I was expecting more standardization.
@devarshihazarika48717 ай бұрын
Its just Custom error with more headers
@RiversJ7 ай бұрын
It is sadly a heck of a lot more than one can expect from most APIs, also even this much is a godsend for anyone logging their Api calls. Adding things like requestIds or encoding sensitive route/header data to something only the Api service provider can decode is also quite useful if a specific call causes actual realworld consequences that need to be reverted/corrected.
@nothingisreal63458 ай бұрын
Is there a way to test this with Swagger? I'm using authentication and the HTTP tool in VS Code / VS does not really support this (it is very complicated).
@_OsamaAmir8 ай бұрын
Normally, at my company we also have stack trace, which you also had when you were throwing an exception without using Problem detail specification, but when you used the Spec, it didn't include the trace, is it a good or a bad thing, also if I do want the trace what should I do?
@darkr0astedblend8 ай бұрын
Stack traces as in java, may reveal data you don't want to expose to a client, such as secrets. Especially if it's served directly to a browser. You should only ship stack traces to a logging mechanism, not the browser. Even then, you need to filter out certain information, such as secrets or personal data for GDPR.
@RushOrbit8 ай бұрын
To add to the comment above ^, an error reporting tool like Sentry or Rollbar are also good options. Definitely don’t return your stack trace in the response.
@wh33lers7 ай бұрын
I am not a big fan of using status codes to encode business logic. In case the http request went trough ok, i prefer to handle errors on my own instead of mixing it up with any lower level issue that might occur.
@botondvasvari57588 ай бұрын
and how would swagger see this ?
@daleryanaldover65458 ай бұрын
swagger can accept any response schema, all that needs to be done is to define the schema and use it in swagger
@guai96328 ай бұрын
they should've standardized nested errors if my service fails to call another one and hence can't do its work, it can report that. and most error our apps report are some kind of data validation conflicts, it would be nice to have recommended way do describe those (multiple conflicts can occur in one input json)
@scuroguardiano97878 ай бұрын
This isn't something game changing, I mean standard is nice but it's not that hard to implement simple property reading. Most difficult part for me is giving proper handling for different errors on the client. For example let's say user clicked "Add to cart" on product that was bought just a second ago and is no longer in stock. We can show ugly error message that server returned "Sorry, item is not available anymore" or we can handle it in more user friendly way, showing them nice dialog "Oh sorry, someone just bought last piece of this product. Here's similar products you may be interested in". But for that we need to have some custom error codes that both client and server knows and we must implement handling them on every single client. So in the end we still must implement error parsing and handling on each client for each API.
@Dude298 ай бұрын
Whats the name of the extension for the HTTP requests?
@FatihIrmak8 ай бұрын
Application/problem+json is redundant as HTTP 403 already indicates a problem case. New mime type requires special handling as well, so I'd suggest sticking to HTTP status code rather than content type to indicate problem cases
@ccgarciab8 ай бұрын
problem+json doesn't indicate an error but how to parse the body. It is part of the error details spec.
@unhandledexception19484 ай бұрын
wondering why almost 8 years after formalizing this spec in 2016, it is still largely ignored
@tidenly8 ай бұрын
This is nice, but it doesn't escape the initial problem you set out in your video. "All clients need to know how to understand and handle the errors" - that's an inescapable problem in most JSON APIs, and even with your Problem implementation, it relies on the client knowing how to parse and handle these types of error responses. Nothing wrong with using this, but I think the strongest point here is "use a uniform interface for errors across your systems". I also like custom error definitions because we can more strongly define the response than the Problem spec does. Forcing required error code *and* error messages separately is nice too as the code gives the client something non-localized and guaranteed to be present to hook onto.
@felipecampelo5588 ай бұрын
Nice video. Thanks so much.
@ДмитрийКарпич6 ай бұрын
Aha! Actually, I feel something wrong about generic error message and this looks like cleverer than Idea to wrap any response as 200 with status inside answer. It's all about multi-used HTTP statuses - its pain in real infrastructure. We are get 400 on API request. Ok, why really return it? May be proxy, may be internal routers, cache server etc. But seems "problem"-way can fix it.
@daleryanaldover65458 ай бұрын
If frameworks adopt this internally then I would use it, but now there is really no need to follow such convention.
@Sam-rz5hw8 ай бұрын
brilliant
@jnicoulakos7 ай бұрын
I hate it when I see errors from postman like 8475309 or any other long strang numbers. Then we try to figure it out! lol
@bnssoftware32928 ай бұрын
Audio is really bad on this one
@denetralize8 ай бұрын
use grpc instead
@mojorochi7 ай бұрын
I'll return null or "" and you'll know what's going on
@fra48978 ай бұрын
amazing video! sub + like
@EduardoRodriguezRocks8 ай бұрын
Then you need error handlers for the error handlers heheh
@rikkitp7 ай бұрын
why do I hear "Suffer Engineer" 🙃
@tymekmajewski47187 ай бұрын
Using HTTP 403 for a custom "Out of credit" error is just incorrect and will lead to trouble. Don't do it :)
@Adrian-jj4xk8 ай бұрын
so... a useless content-type, and just repurpose http status codes however you want? thing about standards is they help people understand things.
@MartinPiper65027 ай бұрын
It's better to concentrate on showing the code. Remove the face and microphone as they do not add any value, actually they are removing value because a constantly gesticulating section of the screen is distracting.
@PaulMarangoni8 ай бұрын
This is new to me. But holy cow do you ever speak fast! Please slow down!
@amantinband8 ай бұрын
Yeah? Curios if others think so as well
@SanderDecleer8 ай бұрын
I don't find it too fast, but can understand someone might. One can always slow the video down in the settings.
@henrikskog28938 ай бұрын
Disagree, the pace is natural imo
@CRBarchager8 ай бұрын
It's the opposite of TimCorey. With Tim you need to speed up the vidoe to 1.5-2x. With Amichai you can slow it's down to 0.75x and still understand the video :D
@daleryanaldover65458 ай бұрын
As an Asian, I find his pace a bit slower than most channels I watch on KZbin. Unlike Indian channels, his pacing is better.
@ltxr99738 ай бұрын
That's dumb, how is that a HTTP error at all? Even sending a HTTP 200 saying "success: false" seems more logical. It's a business error, not a technical one. And if it was a techincal error you wouldn't want to tell the client about its details.
@zapfska73908 ай бұрын
Use a real language like javascript,typescript, or node for your example plz
@gto4338 ай бұрын
He's using c sharp, which is a better language.
@mme7258 ай бұрын
...is this supposed to be a troll comment? Lol "Use a real language like" then practically list JavaScript 3 times and exclude any other language ever to exist 😂