Access object from server response when using yield call for a blob file - reactjs

So I try to make a call to the server to get a PDF file, which works when the file exist. But when there is no file, i get a 404 response from the server. I need to access this status in the result object. The problem is when the blob tries to download and it doesnt find the file, it does not provide me with the result from server, but instead it says this:
TypeError: Failed to execute 'createObjectURL' on 'URL': No function was found that matched the signature provided.
If I tweak it a bit it says "Error fetching file". But I really need the status from the server response due to displaying correct info if the file does not exist or if its an server error. Due to sensitive data, I cannot copy paste the result from server in here. But it does show result: { statusCode: 404 " } in the object.
This is my code:
export function* getInvoicePDFWorkerSaga(arg) {
const {
organizationNumber, agreementId, invoiceNumber,
} = arg;
try {
const blob = yield call(invoices.getInvoicePDF, organizationNumber, agreementId, invoiceNumber);
const blobUrl = URL.createObjectURL(blob);
downloadFile(blobUrl, `invoice_${invoiceNumber}`, 'pdf');
} catch (e) {
yield put(actions.getInvoicePDFFailedAction(invoiceNumber, formatError(e)));
const retry = yield call(RetryPrompt);
if (retry) {
yield call(getInvoicePDFWorkerSaga, arg);
}
}
}
getInvoicePDF: (organizationNumber, agreementId, invoiceNumber) => (
getBlob({ url: ENDPOINTS.getInvoicePDF(organizationNumber, agreementId, invoiceNumber) })
),

Related

SvelteKit form get request

I am trying to set up a simple endpoint in SvelteKit that reads the input given in a form and returns the result of an SQL query. In my first attempt I used the form actions and wrote the following code in the +page.server.js file:
export const actions = {
default: async (event) => {
let form_input = await event.request.formData();
let query = {
text: "select * from ux_return_shipments($1, $2, $3, $4)",
values: [form_input.get('beg-dep-date') || null, form_input.get('end-dep-date') || null, form_input.get('beg-arr-date') || null, form_input.get('end-arr-date') || null
}
try {
const result = await event.locals.pool.query(query);
return result.rows;
} catch (e) {
console.log(e);
}
}
};
I am now trying to set up the same process using a GET request instead of a POST one but I am having difficulties setting up the endpoint. I tried to replace the above code with this template but it looks like the endpoint is not getting activated since I see no activity server side:
export function GET({ url }) {
console.log(url);
return new Response("Test response");
};
What am I doing wrong? I see that using this code for an API endpoint (+server.js file) works correctly. I also checked the form element and the URL looks correct.
In case someone has the same problem I managed to solve it using this template:
export const load = async (event) => {
return ...
};
Using the load function I was able to set up a get endpoint and pass some data to the frontend using a return.

How to get request headers for the Apollo GraphQL error?

I need to get the request header on the client when an error occurs
const { data, error } = useQuery(gql`Query ...`);
// ..
if (error) {
// get the request headers here
// e.g. error.graphQLErrors[0].headers.requestId
}
I was trying to modify the error using onError link but this object is Read Only
import { onError } from '#apollo/client/link/error';
const errorLink = onError((errorHandler) => {
errorHandler.graphQLErrors[0].extensions = { requestId: ... }
})
I know I can extend extensions on the backend side but I need to generate the request ID on the client side.
There's an example similar to what you're describing on the Apollo docs. It doesn't use extensions specifically, but would enable you to generate the request ID mentioned.

ReactJS testing causing a typeError: network request failed

I have been trying to simulate file-upload as a test for my react-app but that was generating the following error :
TypeError: Network request failed
at node_modules/whatwg-fetch/dist/fetch.umd.js:535:18
at Timeout.task [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:516:19)
This is my test: trying to upload a file and check if an alert is raised.
test("triggers alert when receiving a file with inadequate content", async () => {
renderComponent();
global.alert = jest.fn();
const fileContent = raw("./file.kml");
const fakeFile = new File(
[fileContent],
"file.kml",
{ type: "text/xml" }
);
const selectType = screen.getByTestId("select-type");
await fireEvent.change(selectType, { target: { value: "type" } });
const fileUploader = screen.getByTestId("file-uploader");
await fireEvent.change(fileUploader, {
target: { files: [fakeFile] },
});
await waitFor(() => {
expect(global.alert).toHaveBeenCalledWith(
"alert"
);
});
});
});
I am kind of confused, because file is received and parsed by the component and it raise the alert I need to check but still fails because of the network error.
PS: I tried to mock a fetch but still have the same problem.
Any help would be appreciated.
I have been getting the same
Network request failed: Connection refused
error while testing.
I have explored many threads but no luck.
Out of the blue starting the back end server worked for me. (Even though I used mock service worker that intercepts network calls, starting the back end server worked.)
I don't know why.
Also, I have used import fetch from 'isomorphic-fetch'; in setup-test.js instead of whatwg-fetch.
In the end try adding a timeout:3000 option to your waitFor.

Error when sending POST request from React app to Rocket backend returns failure

I'm writing a simple web with Rocket as backend and React as frontend.
The code snippet looks like this for login page
#[post("/login", data = "<data>")]
pub fn login(
conn: DbConn,
mut cookies: Cookies<'_>,
data: Form<LoginForm>,
) -> Result<JsonValue, NotFound<String>> {
let valid_account = match Account::find_by_email(&*conn, data.email.as_str()) {
Ok(account) => {
if account.password == data.password {
account
} else {
return Err(NotFound("Incorrect email or password!".to_string()));
}
}
Err(_) => return Err(NotFound("Incorrect email or password!".to_string())),
};
cookies.add_private(
Cookie::build(AUTH_COOKIE, valid_account.id.to_string())
.same_site(rocket::http::SameSite::Strict)
.finish(),
);
Ok(json!({
"email": valid_account.email,
"name": valid_account.name,
}))
}
Code for main.rs
fn main() {
rocket::ignite()
.mount("/", routes![
account::login::login,
],
)
.register(catchers![errors::unauthorized])
.attach(rocket_cors::CorsOptions::default().to_cors().unwrap())
.manage(establish_connection())
.launch();
}
and code for React when trying to send the post request
export const postForm = async (
pathUrl: string,
postInfo: { [name: string]: any }
) => {
let axiosConfig = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Access-Control-Allow-Origin': '*',
},
};
try {
const response = await axios.post(
baseUrl + pathUrl,
querystringify.stringify(postInfo),
axiosConfig
);
return response.data as CurrentUser;
} catch (err) {
console.log(err);
return Promise.reject(err.response);
}
};
The code works fine it I enter the correct email and password.
However, it cannot capture the error message if I enter the wrong credentials.
Rocket log are the same between successful login and failure login which are
OPTIONS /login:
=> Error: No matching routes for OPTIONS /login.
=> Warning: Responding with 404 Not Found catcher.
=> CORS Fairing: Turned missing route OPTIONS /login into an OPTIONS pre-flight request
=> Response succeeded.
POST /login application/x-www-form-urlencoded:
=> Matched: POST /login (login)
=> Outcome: Success
=> Response succeeded.
and the error log in browser I captured was Error: "Request failed with status code 404" which was not the expected error message hard coded inside post function.
I believe it has something to do with Option or preflight processed inside Rocket which maybe in the purpose of security. But how can I suppress the system error and let my code to take over?
I have read previous SO post like state undefined: while sending post request from react app and GitHub issues like https://github.com/SergioBenitez/Rocket/issues/25. And still cannot find answer for my problem.
Thanks in advance!
Apparently I made several mistakes here due to unfamiliar with Rocket and React.
List here in case someone made the similar mistakes.
The 404 status code is from the first code snippets Result<JsonValue, NotFound<String>>. So if we write the return type as Result<JsonValue, Unauthorized<String>>, it would return 401 as unauthorized user.
Second, axios only receives json type and cannot parse string (correct me if I'm wrong). So we need to change the return type in server to Result<JsonValue, Unauthorized<JsonValue>>.

How to get error body using React Apollo Link Rest

I am creating an React app using Apollo Graphql and I am having some trouble with the Apollo Link Rest. The problem is that in the middle of my app I have to make a REST request, however this request can be sucessful and return a status code = 200 or it can fail, returning a status code = 400.
It is important for my app to show the end user an error message that is returned in this request's body in case of a 400 error. However when an error happens the Apollo Link Rest just throws an exception, but it doesn't return response body back to me.
Is there a way for me to get the response body, when there is an error with the Apollo Link Rest? I thought that I could get it from the result variable, but since the Apollo throws an exception, this variable never changes.
Here is my code:
const result = await context.client.query<MyQuery>({
query: MyQuery,
variables: {
input: {
companyId: variables.companyId,
},
},
});
query MyQuery($input: MyQueryInput!) {
myQuery(input: $input) #rest(
type: "QueryResponse",
method: "POST"
path: "v1/my-query"
) {
id
minimumPreparationTime
maximumPreparationTime
extras {
id
optional
key
}
warning
error {
id
type
message
}
}
}
Extending Greg comment and apollo-link-error, you can retrieve the error body from networkError.result.message.
You can use apollo-link-error to catch and handle server errors, network errors, and GraphQL errors. You should be able to conditionally set response.errors if needed.
import { onError } from "apollo-link-error";
const link = onError(({ graphQLErrors, networkError, response, operation }) =>
{
if (graphQLErrors)
graphQLErrors.map(({ message, locations, path }) =>
console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path:
${path}`,
),
);
if (networkError) console.log(`[Network error]: ${networkError}`);
response.error = // set error property here
});
It may also be worth noting Apollo exposes an errorPolicy option, for which the default is none. The policy can be modified to all which, according to the docs,
is the best way to notify your users of potential issues while still
showing as much data as possible from your server. It saves both data
and errors into the Apollo Cache so your UI can use them.

Resources