Setting status code for exception raised in load() function in SvelteKit - sveltekit

I have a load() route function that may throw a "maintenance mode" error if the backend is under maintenance. This may happen in __layout, load() or elsewhere in the frontend:
function load() {
if(looksLikeDataIsUnderMaintennce) throw new UnderMaintenanceError();
}
Then I am catching this error in __error.svelte to display a more specific error message instead of "HTTP 500 We are on fire".
<script context="module">
/** #type {import('#sveltejs/kit').Load} */
export function load({error, status}) {
const maintenance = error.name === "UnderMaintenanceError";
return {
props: {
title: `${status}`,
message: error.message,
maintenance: maintenance,
}
};
}
</script>
<script>
export let maintenance;
</script>
<div class="container">
{#if maintenance}
<h1 class="text-center">{chainName} data under maintenance, we are back in X minutes</h1>
{:else}
<h1 class="text-center">HTTP {title} error</h1>
<pre>{message}</pre>
{/if}
</div>
By default, SvelteKit serves exceptions with HTTP status code 500 (internal error). For maintenance, I would like to change the HTTP status code from 500 to more specific HTTP 503 Service Unavailable as that's the preferred HTTP status code for maintenance and temporarily unavailability. I could not find a direct way to do this - returning status from __error.load does not seem to do the trick.
Is there a way to change the HTTP status code for thrown exceptions and error handler in SvelteKit?

You can return an object with a status property, like in this example from the docs. That will automatically show the error page. You can pass more props if you want more information about the error.
So something like this:
export async function get() {
// If under maintenance
return {
status: 503
};
}
UPDATE:
For some reason, I can't get the error message to propagate in the get endpoint function, so if you want to pass the error around it seems you need to use the load function from that page, like so:
<script lang='ts' context='module'>
export function load({ error }) {
console.log(error);
return {
status: 503,
error: new UnderMaintenanceError(),
}
}
</script>
I don't know if I'm missing something or if it's just a bug.

Based on Odilf's answer, we were able to this in the load() function in __layout:
<script context="module">
import { checkChainMaintenance } from "$lib/chain/maintenance";
/** #type {import('#sveltejs/kit').Load} */
export function load({ params }) {
// Check for the data maintenance status.
// If under maintenance, trigger __error with a special
// layout and message.
try {
checkChainMaintenance(params.chain);
} catch(error) {
return { status: 503, error };
}
return {};
}
</script>
<slot />
See full example.

Related

SvelteKit - get protocol

Is it possible in SvelteKit to get protocol of current page (HTTP or HTTPS)?
Something like:
import {page} from '$app/stores';
console.log($page.protocol);
So far, I only see:
{
host: 'localhost:3000',
path: '/projektDetalji',
query: URLSearchParams { 'id' => '1' },
params: {}
}
You could use browser to make sure you are running in browser, then grab protocol from window.location.protocol.
<script context="module">
import { browser } from "$app/env"
if (browser) {
console.log(window.location.protocol);
}
</script>
From $app/env module section of sveltekit docs
Here's one way...
Within the handle() function of your hooks.server.js, the protocol can be gleaned using event.url?.protocol and then passed into the rest of your application via the locals object. For example...
/** #type {import('#sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
// Store the protocol in the locals object, which is passed
// in to handlers in +server.js and server load() functions
event.locals.protocol = event.url?.protocol;
return await resolve(event);
}
Later, retrieve it from the locals object in your +page.server.js files...
export async function load({params, locals}) {
if (locals.protocol) {
console.log ('Protocol is ' + locals.protocol);
}
}

Having problems with axios.post while try to get data FROM server

I am trying to use axios.post (in TS) to get responses from server (using POST as GET) without sending any Data. The server sends back the Data but REACT cant handle the responses.
Here is the react component:
interface allComapnies {
comapniesData:CompanyData[];
}
function GetAllCompanies(props:allComapnies): JSX.Element {
const myURL = globals.urls.admin+"get_company/all";
const [comapniesData,setData] = useState([new CompanyData()]);
useEffect(()=>{axios.post(myURL).then((response)=>{
console.log(response.data);
setData(response.data);
}).catch(error=>{console.log(error)});
},[]);
return (
<div className="getAllCompanies">
{comapniesData.map(item=><OneCompany
key ={item.id}
id={item.id}
name={item.name}
email={item.email}
/>)}
</div>
);
}
export default GetAllCompanies;
The console message shows:
Error: Request failed with status code 302
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.onloadend (xhr.js:54)
The browser get the responses from the server:
[{id: 2, name: "company2", email: "hgfytj#fdgreg", password: "trjyjytk",…},…]
The function of the REST Post inside the Controller in the Server(SPRING):
#RestController
#RequestMapping("admin")
#CrossOrigin(origins = "localhost:3000", allowedHeaders = "*")
#RequiredArgsConstructor
public class AdminController extends ClientController {
private final AdminService adminService;
...
#PostMapping("get_company/all")
public ResponseEntity<?> getAllCompanies() {
return new ResponseEntity<>(adminService.getAllCompanies(), HttpStatus.FOUND);
}
...
}
I found the problem. It was that I sent http status number 302 as a send confirmation, instead of number 200.
This prevented the server from sending the desired information in response. I have now changed the status to 200 and the information is received even when sending "axios.post" with an empty request.
#PostMapping("get_company/all")
public ResponseEntity<?> getAllCompanies() {
return new ResponseEntity<>(adminService.getAllCompanies(), HttpStatus.OK);
}
Try GET method instead POST cause you are getting data from your DB and not sending it to.

navigator.geolocation.getCurrentPosition() is not getting a response from googleapi

I am using react to get geolocation on localhost:3000. I have seen another person get the geolocation coordinates on their localhost, but I am unable to do so even with allow location access enabled on Chrome.
I have tried using both the hooks and class syntax in react. I have enabled allow access. I eventually used an ip address api to get a general location, but since the geolocation is supposed to work(at least that is what I have been told) I would at least like to see it work so I can implement it with https in the future. The error log does not even get fired, whereas the first three logs are getting fired when the component is mounted. Here is the code I have tried, I have made it as simple as possible:
const App = props => {
useEffect(() => {
console.log('hello')
console.log(navigator)
console.log(navigator.geolocation)
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
console.log(position)
}, (error) => {
console.log(error)
})
} else {
console.log('error')
}
}, [])
return (
<div>
<h3>Please Login.</h3>
</div>
)
}
export default App
I expect to receive a response from googleapi.
Edit:
I added the error callback and it printed:
message: "Network location provider at 'https://www.googleapis.com/' : No response received."
add the optional error callback to handle the error (if user declines location permission)
navigator.geolocation.getCurrentPosition(success[, error[, [options]])
you are checking only if it is in navigator or not !!!
if user declines location permission then error callback will handle it...
possible options are (reference taken from mdn)
{
enableHighAccuracy: true,
maximumAge : 30000,
timeout : 27000
}

Handle Error when the server is off in react js (TypeError Failed to fetch)

I need to show error in a dialog stating the server has stopped whenever the server crashes or server gets shut down.
I as console log my error in request as below:
export default function request(url, options) {
return fetch(url, options)
.then(checkStatus)
.then(parseJSON).
catch(error => {
console.log("error",error)
throw error;
});
}
the console is :
TypeError Failed to fetch
Can someone help me with this?
you can use navigator in you code in order to check if user is offline nor user can't connect to your WebService like below:
//if there was a problem with server
if(navigator && navigator.onLine) {
throw {
code: 'SERVER_CONNECTION_PROBLEM',
message: 'Server connection failure...'
}
} else { // if there is a problem with internet
throw {
code: 'INTERNET_CONNECTION_ERROR',
message: 'there is a problem with your INTERNET, god damn it...'
}
}
You can check error status e.g. error.status and do
if(error.statusCode === 503){ // or status code which your server send
// do something
}
There is library called react-offline.
which used in detect your network is in work or not.
After proper implementation it should be work, it shows offline page which you created when your network goes down...
link is here : https://openbase.com/js/react-offline/documentation
[Click here for documentation][1]
[1]: https://openbase.com/js/react-offline/documentation
code example :
<Offline
render={() => {
return (
<div>"I take precedence over any function as child component."</div>
);
}}
>
{() => {
return <div>"I will not render."</div>;
}}
</Offline>

How to handle api errors using aws-amplify?

I'm currently trying to POST data to my aws lambda functions triggered by aws api-gateway using the aws-amplify react lib.
Here is the code :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(console.log(err))
In the main case, everything is OK.
But my lambda function is design to validate the input data and return a status code 400 with a returned payload looking like that :
{
"errors": [
{
"field": "title",
"message": "This field is required"
}
]
}
I would like to catch those errors in order to display them in the frontend but aws-amplify seems to have an undocumented behavior.
By default, status code 400 returned are throw with a default error message :
Error: Request failed with status code 400
at createError (createError.js:16)
at settle (settle.js:18)
at XMLHttpRequest.handleLoad (xhr.js:77)
Is there a way to get the returned payload instead of this magical error?
It turns out that under the hood, aws-amplifyuse Axios to make http calls.
When using Axios, you have to console.log(error.response): https://github.com/axios/axios/issues/960
Here is the fix I've made :
API.post("snippets","snippets/", {
body: data,
}).then(response => response).catch(error => console.log(error.response.data))
A Pull Request on the aws-amplify documentation is open : https://github.com/aws/aws-amplify/pull/633
I also faced the similar issues, It showed the default error message "Request failed with status code 400", instead of the message that is returned from API.
I logged the Error object and it did not show the response attribute in it. But we do have response attribute. I tried logging the Error.response and it did contain the response sent from the API.
Just figured out this by going through the 'Cancel API requests' Amplify docs.
From what I can see this is the contents of the error object returned by the API call:
Heres what I am doing to just print out the error, obviously you would do a lot more here but its a good start.
async uploadUser(state, payload) {
const promise = API.graphql({
query: createUser,
variables: { input: payload },
});
try {
await promise;
} catch (error) {
// Print out the actual error given back to us.
console.log(error.errors[0].message);
// If the error is because the request was cancelled we can confirm here.
if (API.isCancel(error)) {
// handle user cancellation logic.
console.log(error.message);
}
}
Hope that helps 😃

Resources