How to throw an exception from a server API code in Dart? - dart

I'm developing a client-server application in Dart and have been following the tutorial. My server code is roughly based on it.
In my server API code, when something goes wrong, I want to throw an exception, for example:
void checkEverything() {
if(somethingWrong)
throw new RpcError(400, "Something Wrong", "Something went wrong!");
}
#ApiMethod(path: 'myservice/{arg}')
Future<String> myservice(String arg) async {
checkEverything();
// ...
return myServiceResponse;
}
and that exception should be processed in the main server, e.g.
// ...
var apiResponse;
try {
var apiRequest = new HttpApiRequest.fromHttpRequest(request);
apiResponse = await _apiServer.handleHttpApiRequest(apiRequest);
} catch (error, stack) {
var exception = error is Error ? new Exception(error.toString()) : error;
if((error is RpcError && error.statusCode==400) {
// My code for creating the HTTP response
apiResponse = new HttpApiResponse.error(
HttpStatus.BAD_REQUEST, "Something went wrong", exception, stack);
}
else {
// standard error processing from the Dart tutorial
apiResponse = new HttpApiResponse.error(
HttpStatus.INTERNAL_SERVER_ERROR, exception.toString(),
exception, stack);
}
}
(snippet, see the tutorial for the complete code sans my error handling).
However, my exception never reaches the above catch clause. Instead, it seems to get caught in _apiServer.handleHttpApiRequest(apiRequest);, which, in turns, throws INTERNAL_SERVER_ERROR (500):
[WARNING] rpc: Method myservice returned null instead of valid return value
[WARNING] rpc:
Response
Status Code: 500
Headers:
access-control-allow-credentials: true
access-control-allow-origin: *
cache-control: no-cache, no-store, must-revalidate
content-type: application/json; charset=utf-8
expires: 0
pragma: no-cache
Exception:
RPC Error with status: 500 and message: Method with non-void return type returned 'null'
Unhandled exception:
RPC Error with status: 400 and message: Something went wrong!
#0 MyApi.myservice (package:mypackage/server/myapi.dart:204:24)
[...]
This is not very specific for the client. I'd like to communicate that an error has happened, not to return a good-looking response. So what is the proper way of handling server-side exceptions in Dart and passing that information to the client?

OK, I think I solved the problem. The throw clause apparently has to be in the API method itself, and not in a subordinate method. I.e.:
#ApiMethod(path: 'myservice/{arg}')
Future<String> myservice(String arg) async {
if(somethingWrong)
throw new RpcError(400, "Something Wrong", "Something went wrong!");
// ...
return myServiceResponse;
}
and not:
void checkEverything() {
if(somethingWrong)
throw new RpcError(400, "Something Wrong", "Something went wrong!");
}
#ApiMethod(path: 'myservice/{arg}')
Future<String> myservice(String arg) async {
checkEverything();
// ...
return myServiceResponse;
}

Related

SvelteKit Node streams are no longer supported

Since node-fetch was replaced by undici in #5117 some of us encountered the error
Node streams are no longer supported — use a ReadableStream instead
like in this post
It is not easy to reproduce, for me the error occured only in production.
This is a self-answered question in case you have the same problem.
The error comes from src/runtime/server/utils.js L46 and is thrown after checking the _readableState property and some type on the response body of the request.
For me the problem was that my endpoint.ts was returning the fetch directly.
export async function post({request}){
return fetch('...')
}
This used to work but not anymore since the fetch response is a complex object with the _readableState property. To fix this you have to consume the response and return a simpler object like
export async function post({request}){
try {
const res = await fetch('...')
const data = await res.json()
return {
status: 200,
body: JSON.stringify({...data}),
}
catch(error){
return { status: 500}
}
}

NestJs HttpException response to Dart's http request

I would like to parse the response that my NestJs backend is sending to my Dart front end.
If from NestJs controller I reply with
return new HttpException('Already running..', HttpStatus.PROCESSING);
I receive on Dart's Response object:
Response: {
...
statusCode: 201
body {
"response": "Already running..",
"status":102,
"message": "Already running..",
"name": "HttpException"
}
}
Whereas if I return
throw new HttpExcpetion('Already running..', HttpStatus.PROCESSING)
I receive:
Response: {
...
statusCode: 102
body: ""
}
I would have expected to receive something like the below:
Response: {
...
statusCode: 102
message: "Already running..",
}
Any ideas how the two approaches are different and what should be the proper, consistent way so I know how to parse responses from backend?

What kind of errors are returned by HttpServer stream in Dart

I'm going through the Dart server documentation. I see I can await for an HttpRequest like this:
import 'dart:io';
Future main() async {
var server = await HttpServer.bind(
InternetAddress.loopbackIPv4,
4040,
);
print('Listening on localhost:${server.port}');
await for (HttpRequest request in server) {
request.response.write('Hello, world!');
await request.response.close();
}
}
That's because HttpServer implements Stream. But since a stream can return either a value or an error, I should catch exceptions like this, right:
try {
await for (HttpRequest request in server) {
request.response.write('Hello, world!');
await request.response.close();
}
} catch (e) {
// ???
}
But I'm not sure what kind of exceptions can be caught. Do the exceptions arise from the request (and warrant a 400 level response) or from the server (and warrant a 500 level response)? Or both?
Error status codes
On exception, a BAD_REQUEST status code will be set:
} catch (e) {
// Try to send BAD_REQUEST response.
request.response.statusCode = HttpStatus.badRequest;
(see source)
That would be 400 (see badRequest).
Stream errors
In that same catch block, the exceptions will be rethrown, which means that you will still receive all the errors on your stream. This happens in processRequest, which processes all requests in bind.
And you get the errors on your stream because they are forwarded to the sink in bind.
Kinds of errors
I could only find a single explicit exception type:
if (disposition == null) {
throw const HttpException(
"Mime Multipart doesn't contain a Content-Disposition header value");
}
if (encoding != null &&
!_transparentEncodings.contains(encoding.value.toLowerCase())) {
// TODO(ajohnsen): Support BASE64, etc.
throw HttpException('Unsupported contentTransferEncoding: '
'${encoding.value}');
}
(see source)
These are both HttpExceptions.

axios async await function not returning validation errors

export const register = (user, callback, errorback) => async dispatch => {
try{
let response = await axios.post(`${PINGUIN_ROOT_URL}/users/create`, user)
if (response.data.auth_token){
auth_token = response.data.auth_token
dispatch({ type: REGISTER_SUCCESS, payload: auth_token})
callback()
} else {
let error = response
throw error
}
}catch(error){
dispatch({type: REGISTER_FAIL})
errorback()
}
Hi, I am building a login register based off of what we have learned. It works but for some reason the error validations wont come back. I built a rails api and I see the validation errors when I use postman but when I try to get the errors back using redux the register function above gets to the "let response = .." line and immediately goes to the catch(error) line. I dont know how to pass back the actual validation errors that I see when I use post man because the error that is being caught is the following:
Error: Request failed with status code 422
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:538)
at XMLHttpRequest.__didCompleteResponse (XMLHttpRequest.js:381)
at XMLHttpRequest.js:485
at RCTDeviceEventEmitter.emit (EventEmitter.js:181)
at MessageQueue.__callFunction (MessageQueue.js:250)
at MessageQueue.js:101
Now again, the code is working when it actually logs in the user however it fails to actually give me the validation errors that I need. I see the validation errors comming back as json in postman but i do not get to see them in practice. Help please?
You can get the response object from your error object as error.response
try{
let response = await axios.post(`${PINGUIN_ROOT_URL}/users/create`, user)
...
} catch(error){
console.error(error.response)
}

How to retrieve exact reason of the error from async HttpRequest?

I am trying to figure out how to find out exact reason of (async) HttpRequest (from 'dart:html') failure, and, to be honest, I am a bit lost here.
The onError callback receives only HttpRequestProgressError object, which doesn't have anything useful, and the HttpRequest object itself has "status" set to "0" in case of failure, even console shows "Failed to load resource" with no details.
What I want is to know the exact reason - like "connection refused" or "host name not resolved".
Is this possible at all?
Thank you!
Unfortunately, there is no property to report the error as detailed as you'd like. The reason is that JavaScript doesn't support this.
There are the properties status and statusText on the HttpRequest object (which you could get from your HttpRequestProgressEvent with evt.target, but those represent HTTP status codes. Every other error has the status code 0 - request failed. This could be anything, and the only place to look at is the browser's console, because this is an Exception thrown by the browser.
If your request was synchronous, you could surround the send() with a try-catch. If your request is async, this won't work.
See here
#library('Request');
#import('dart:html');
#import("dart:json");
typedef void RequestHandler(String responseText);
typedef void ErrorHandler(String error);
class ResourceRequest {
XMLHttpRequest request;
RequestHandler _callbackOnSuccess;
ErrorHandler _callbackOnFailure;
ResourceRequest.openGet(String url, RequestHandler callbackOnSuccess, [ErrorHandler callbackOnFailure])
: request = new XMLHttpRequest(),
_callbackOnSuccess = callbackOnSuccess,
_callbackOnFailure = callbackOnFailure {
request.open("GET", url, async : true);
request.on.loadEnd.add((XMLHttpRequestProgressEvent e) => onLoadEnd(e));
}
void send() {
request.send();
}
void onLoadEnd(XMLHttpRequestProgressEvent event) {
if (request.readyState == 4 && request.status == 200) {
_callbackOnSuccess(request.responseText);
} else if (_callbackOnFailure != null) {
_callbackOnFailure(request.statusText);
}
}
}

Resources