How to return 404 in Qwik onGet? - qwik

I'm using Qwik, and I want to return 404 when from my onGet method.
Unfortunately the docs does not include an example regarding this. And I can't find anything through Google search.
Basically I want to do this:
const onGet = async({ params, url }) => {
// searching the DB or API for the item
// return the item if it exist,
// but return 404 it it does not
// and I don't know how to return 404
}

Using qwikcity loader$
import { component$ } from "#builder.io/qwik";
import { loader$ } from "#builder.io/qwik-city";
export const githubLoader = loader$(async ({ fail }) => {
try {
const res = await fetch("https://api.github.com/users/harshmangalam");
if (res.ok) {
const user = await res.json();
return user;
}
// return error status for 401,403,404 ,500 etc...
return fail(res.status, {
message: "Error message",
});
} catch (error) {
return fail(500, {
message: "error message",
});
}
});
export default component$(() => {
const githubSignal = githubLoader.use();
return <pre>{JSON.stringify(githubSignal.value, null, 4)}</pre>;
});
Add some non-exists username you will get error message.

import { component$, Resource } from "#builder.io/qwik";
import {
type RequestHandler,
useEndpoint,
type DocumentHead,
} from "#builder.io/qwik-city";
export const onGet: RequestHandler = async ({ response }) => {
const res = await fetch("https://api.github.com/users/harshmangalam");
if (res.ok) {
const user = await res.json();
return user;
}
// return error status for 401,403,404 ,500 etc...
throw response.error(res.status);
};
export default component$(() => {
const resource = useEndpoint<typeof onGet>();
return (
<Resource
value={resource}
onResolved={(data) => <pre>{JSON.stringify(data, null, 4)}</pre>}
onRejected={(error) => <pre>{JSON.stringify(error, null, 4)}</pre>}
onPending={() => <p>Loading...</p>}
/>
);
});

Related

change toolkit redux state inside of fetch

I just want to update state outside of component after server give me failed response.
the project is react native .
After a lot of online search on website like this , I learn that i need to import my store and use dispatch method. but when i import storage and dispatch it, it give me this error: Property 'crypto' doesn't exist .
this is my feachService.js code:
import { URL } from 'react-native-url-polyfill';
import { store } from '../store/index'
import { errorSliceActions } from '../store/slices/global/errorSlice'
export default (url, isGet) => {
let headers = {
Referer: new URL(url).origin,
}
headers['X-Requested-With'] = 'XMLHttpRequest'
return fetch(
url,
{
method: (isGet ? 'GET' : 'POST'),
headers: headers
})
.then(function (res) {
return res.json();
})
.then(function (res)
{
if(res && res.isSuccess == false && res.message) {
store.dispatch(errorSliceActions.add(res.message));
}
return {json: function() { return res; }};
})
.catch(function (error) { console.log(error.message); })
};
this is my storage js file:
import { configureStore } from '#reduxjs/toolkit';
import errorSliceReducer from './slices/global/errorSlice';
export const store = configureStore({
reducer: {
errorSlice: errorSliceReducer
}
});
this is my error slice.js file:
import { createSlice } from "#reduxjs/toolkit"
function uuidv4() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
const errorSlice = createSlice({
name: "errorSlice",
initialState: {
errors: [
]
},
reducers:
{
add: (state, action) => {
const newItem = {
id: uuidv4(),
message: action.payload
};
return [...state, newItem];
},
remove: (state, action) => {
return { errors: state.errors.filter(function(item) { return item.id != action.payload; }) }
}
}
})
export const errorSliceActions = errorSlice.actions;
export default errorSlice.reducer
and this is my code for executing fetch request
async function loadInfo (inputSearch, inputPage) {
if(config.dataurl) {
console.log(inputSearch);
setIsLoading(true);
const hasQuestionMark = config.dataurl.indexOf('?') > 0;
let targetUrl = '/test/test' + config.dataurl + (!hasQuestionMark ? '?' : '&');
targetUrl += 'page=' + inputPage;
targetUrl += '&search=' + inputSearch;
console.log(targetUrl);
const response = await feachService(appJSon.baseUrl + targetUrl , true);
const responseData = await response.json();
setIsLoading(false);
if(responseData.pagination)
setPagination(responseData.pagination);
if(!responseData.results)
setItems([]);
else
setItems(responseData.results);
}
}
useEffect(() => {
loadInfo('', 1).catch(function (error) { console.log(error.message); });
}, [])
what am i doing wrong ?

Urql config with guest token for SSG on next js

So I have a project using the latest Next js 13, React 18, Urql 3, and using typescript
Currently, I have issues when trying to query the urql from the getstaticprops function. My urql request needs a guest token, and I'm storing the token on session storage(other suggestions ?).
It has no issue when the query is running on the client, but I have it when querying inside the function.
My concern is related to the token reading, so the server cannot read the session storage value.
I'm asking what is the better and simplest way to make this work.
Does use cookies to store guest tokens will make this work?
Or the configuration that doesn't work?
This is my current config for urql.ts
import {
createClient,
ssrExchange,
dedupExchange,
cacheExchange,
fetchExchange,
} from "urql";
import { GRAPH_URL } from "#lib/constant/env";
import type { TypedDocumentNode } from "#urql/core";
const isServerSide = typeof window === "undefined";
const ssrCache = ssrExchange({
isClient: !isServerSide,
});
const client = createClient({
url: GRAPH_URL,
exchanges: [dedupExchange, cacheExchange, ssrCache, fetchExchange],
fetchOptions: () => {
const token = sessionStorage.getItem("accessToken");
return {
headers: {
authorization: token ? `Bearer ${token}` : "",
},
};
},
});
const query = async (
query: TypedDocumentNode<any, object>,
variables?: Record<string, string | string[] | unknown>
) => {
try {
const response = await client.query(query, variables as any).toPromise();
return response;
} catch (error) {
if (error instanceof Error) console.error(error.message);
}
};
const mutation = async (
mutation: TypedDocumentNode<any, object>,
variables?: Record<string, string | string[] | unknown>
) => {
try {
const response = await client
.mutation(mutation, variables as any)
.toPromise();
return response;
} catch (error) {
if (error instanceof Error) console.error(error.message);
}
};
export { client, query, mutation, ssrCache };
And this some of the code for the blog index page
export const getStaticProps = async () => {
await fetchArticlesSummary();
return {
props: {
urqlState: ssrCache.extractData(),
},
revalidate: 600,
};
};
export default withUrqlClient(() => ({
url: GRAPH_URL,
}))(BlogPage);
This is for the fetchArticlesSummary
export const fetchArticlesSummary = async () => {
try {
const {
data: { listArticles },
}: any = await query(getListArticle);
return listArticles.items;
} catch (error) {
return {
notFound: true,
};
}
};
I also doing a setup on _app.tsx
export default function App({ Component, pageProps }: AppProps) {
if (pageProps.urqlState) {
ssrCache.restoreData(pageProps.urqlState);
}
return (
<Provider value={client}>
<Component {...pageProps} />
</Provider>
);
}
Thank you
I have followed urql documentation about server-side configuration and many others but still don't have any solutions.

When onRejected in axios.interceptors.request.use will be triggered?

I've been trying for two hours to figure out when onRejected will work in axios.interceptors.request.use. I searched everywhere, but I didn't find an answer. I want to handle all cases where the request fails. Basically my goal is to find out if the request will be repeated if it is rejected in axios.interceptors.request.use. I'm using axios-retry. I did my best to simulate this state, but it didn't work.
The documentation says (axios-retry)
retry on Network Error & 5xx responses
Please, can you help me? Thank you in advance.
import axios from "axios";
import store from './store/index';
import router from "./router";
import axiosRetry from "axios-retry";
export const HTTP = axios.create({
baseURL: '/api/'
});
HTTP.defaults.showLoader = true;
HTTP.interceptors.request.use(
request => {
store.commit('loader_x/PENDING');
const token = store.getters["auth_x/token"];
if (token) {
request.headers["Authorization"] = token;
}
// return false;
// throw new Error('Request ERROR');
return request;
},
error => {
console.log('ERROR REQUEST');
store.commit('loader_x/DONE');
return Promise.reject(error);
}
);
HTTP.interceptors.response.use(
response => {
store.commit('loader_x/DONE');
return response;
},
error => {
console.log('RESPONSE ERROR');
if ('sub_code' in error.response.data) {
switch (error.response.data.sub_code) {
case 403:
HTTP.post('refresh-token')
.then(res => {
const authToken = res.data.token_type + ' ' + res.data.access_token;
store.commit('auth_x/REFRESH_TOKEN', authToken);
error.config.headers['Authorization'] = authToken;
return HTTP(error.config);
})
.catch(err => {
store.commit('auth_x/LOGOUT');
router.push('login').then(() => {
store.commit('snackbar_x/SHOW_MESSAGE', { content: err.response.data.message, color: 'info' });
});
});
break;
case 410:
store.commit('auth_x/SET_SUBSCRIBED_STATUS', false);
router.push('subscription').then(() => {
store.commit('snackbar_x/SHOW_MESSAGE', { content: error.response.data.message, color: 'info' });
});
break;
}
}
store.commit('loader_x/DONE');
return Promise.reject(error);
}
);
const retryDelay = (retryNumber = 0) => {
const seconds = Math.pow(2, retryNumber) * 1000;
const randomMs = 1000 * Math.random();
if (retryNumber === 3)
return seconds + randomMs;
};
axiosRetry(HTTP, {
retries: 3,
retryDelay,
// retry on Network Error & 5xx responses
retryCondition: axiosRetry.isRetryableError,
});

React Redux rejectWithValue() not working

I'm currently facing a problem, when I try to reject a value when my node-fetch request fail, thunkApi.rejectWithValue() isn't working. However when my request is pending or when It's fulfilled, It's working fine.
Here's my slice :
export const userSlice = createSlice({
name: "user",
initialState: initialState as User,
reducers: {
...
},
extraReducers: (builder) => {
...
builder.addCase(changePassUser.pending, (state) => {
GGLog("FETCHING CHANGEPASS API...");
state.isFetching = true;
return state;
});
builder.addCase(changePassUser.fulfilled, (state, { payload }) => {
GGLog("FULFILLED CHANGEPASS:", JSON.stringify(payload));
state.isFetching = false;
state.isSuccess = true;
state.isError = false;
return state;
});
// eslint-disable-next-line #typescript-eslint/no-explicit-any
builder.addCase(changePassUser.rejected, (state, { payload }: any) => {
GGLog("REJECTED CHANGEPASS:", JSON.parse(payload));
state.isFetching = false;
state.isError = true;
state.errorMessage = payload.data;
return state;
});
},
});
Here's my thunk :
export const changePassUser = createAsyncThunk(
"users/password/update",
async ({ oldpassword, newpassword }: RegisterParameters, thunkAPI) => {
try {
const res = await changePassApi.changePass.return({
oldpassword: oldpassword,
newpassword: newpassword,
});
GGLog("API_CHANGEPASS_RES:", res);
const data = await res.json();
if (res.ok) {
GGLog("API_DATA_RESPONSE_OK: ", data);
const tokenData = JSON.stringify(res.headers);
const token = JSON.parse(tokenData).map["x-auth"];
await localStorage.store("token", token);
return data;
} else {
GGLog("API_DATA_RESPONSE_NOK: ", data);
return thunkAPI.rejectWithValue(data);
}
} catch (e) {
GGLog("Error while fetching Login API => ", e);
return thunkAPI.rejectWithValue(e);
}
}
);
And here's the result in the console :
Console output
Any ideas ? Am I missing something ?
Thanks :)
Okay I've found my problem, I was just focused on the thunk and didn't pay attention to the promise rejection. I was trying to parse a JSON that does'nt exist... Just remove the GGLog("REJECTED CHANGEPASS:", JSON.parse(payload));in the slice.
It's working fine now !

Using AsyncStorage to show screen on first login

I'm trying to only show the disclosure screen the first time the user logs in by using AsyncStorage. Currently getData is returning a Promise and it goes straight to the landing screen on first login.
Could I get some help to get this functioning the way I want it to?
This is my login handler:
const key = 'key';
const storeData = async () => {
try {
await AsyncStorage.setItem('key', 'true');
} catch (error) {
// saving failed
console.log(error.message);
}
};
const getData = async key => {
let value = '';
try {
value = await AsyncStorage.getItem(key);
return JSON.parse(value);
} catch (e) {
console.log(error.message);
}
};
const _loginHandler = () => {
if (userName == '' || password == '') {
console.log('gagagagagagagagagagagagagagagagag');
} else {
setShowLoading(true);
const payload = {userName: userName.trim(), password: password.trim()};
setUserName('');
setPassword('');
_UserLoginHandler(payload).then(data => {
setShowLoading(false);
if (data.error) {
GlobalShowSnackBar(data.error);
} else {
setTimeout(() => {
setUserId(data);
//props.navigation.replace(getData("key")?'Landing':'Disclosure')
console.log('Key Value ' + JSON.stringify(getData('key'))); <-- this outputs Key Value {"_U":0,"_V":0,"_W":null,"_X":null}
if (getData('key')) {
props.navigation.navigate('Landing');
} else {
storeData(key);
props.navigation.navigate('Disclosure');
}
}, 500);
}
});
}
};
I got it to work with
getData('key').then(val => {
if (val) {
props.navigation.navigate('Landing');
} else {
storeData(key);
props.navigation.navigate('Disclosure');
}
});