feat(api): refactor fetch calls to axios
Replaces the native fetch() API with axios for all OIDC-related frontend API calls. This improves consistency with other parts of the codebase and simplifies error handling. Addresses https://github.com/fallenbagel/jellyseerr/pull/1505#pullrequestreview-3001436908
This commit is contained in:
committed by
Michael Thomas
parent
205aa5da92
commit
67bbc73564
@@ -1,6 +1,7 @@
|
||||
import defineMessages from '@app/utils/defineMessages';
|
||||
import { processCallback } from '@app/utils/oidc';
|
||||
import type { PublicOidcProvider } from '@server/lib/settings';
|
||||
import axios from 'axios';
|
||||
import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
@@ -26,15 +27,11 @@ export default function OidcLoginButton({
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const redirectToLogin = useCallback(async () => {
|
||||
let redirectUrl: string;
|
||||
try {
|
||||
const res = await fetch(`/api/v1/auth/oidc/login/${provider.slug}`);
|
||||
if (res.ok) {
|
||||
const data = await res.json();
|
||||
redirectUrl = data.redirectUrl;
|
||||
} else {
|
||||
throw new Error();
|
||||
}
|
||||
const res = await axios.get<{ redirectUrl: string }>(
|
||||
`/api/v1/auth/oidc/login/${provider.slug}`
|
||||
);
|
||||
window.location.href = res.data.redirectUrl;
|
||||
} catch (e) {
|
||||
setLoading(false);
|
||||
onError?.(
|
||||
@@ -42,10 +39,7 @@ export default function OidcLoginButton({
|
||||
provider: provider.name,
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = redirectUrl;
|
||||
}, [provider, intl, onError]);
|
||||
|
||||
const handleCallback = useCallback(async () => {
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Transition } from '@headlessui/react';
|
||||
import { ChevronRightIcon } from '@heroicons/react/20/solid';
|
||||
import { MagnifyingGlassIcon } from '@heroicons/react/24/solid';
|
||||
import type { OidcProvider } from '@server/lib/settings';
|
||||
import axios from 'axios'; // <-- Import axios
|
||||
import {
|
||||
ErrorMessage,
|
||||
Field,
|
||||
@@ -99,24 +100,14 @@ export default function EditOidcModal(props: EditOidcModalProps) {
|
||||
|
||||
const onSubmit = async ({ slug, ...provider }: OidcProvider) => {
|
||||
try {
|
||||
const res = await fetch(`/api/v1/settings/oidc/${slug}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(provider),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
await axios.put(`/api/v1/settings/oidc/${slug}`, provider);
|
||||
|
||||
addToast(intl.formatMessage(messages.saveSuccess), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
});
|
||||
|
||||
if (res.status === 200) {
|
||||
addToast(intl.formatMessage(messages.saveSuccess), {
|
||||
appearance: 'success',
|
||||
autoDismiss: true,
|
||||
});
|
||||
|
||||
props.onOk();
|
||||
} else {
|
||||
throw new Error(`Request failed with code ${res.status}`);
|
||||
}
|
||||
props.onOk();
|
||||
} catch (e) {
|
||||
addToast(intl.formatMessage(messages.saveError), {
|
||||
appearance: 'error',
|
||||
|
||||
@@ -8,6 +8,7 @@ import { Transition } from '@headlessui/react';
|
||||
import { PlusIcon } from '@heroicons/react/24/outline';
|
||||
import { PencilIcon, TrashIcon } from '@heroicons/react/24/solid';
|
||||
import type { OidcProvider, OidcSettings } from '@server/lib/settings';
|
||||
import axios from 'axios'; // <-- Import axios
|
||||
import { useState } from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { useToasts } from 'react-toast-notifications';
|
||||
@@ -47,14 +48,12 @@ export default function SettingsOidc(props: SettingsOidcProps) {
|
||||
|
||||
async function onDelete(provider: OidcProvider) {
|
||||
try {
|
||||
const response = await fetch(`/api/v1/settings/oidc/${provider.slug}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
if (response.status !== 200)
|
||||
throw new Error(`Request failed with status ${response.status}`);
|
||||
|
||||
revalidate(await response.json());
|
||||
// The fetch call is replaced with axios.delete.
|
||||
// Axios automatically throws for non-2xx responses and handles JSON parsing.
|
||||
const response = await axios.delete<OidcSettings>(
|
||||
`/api/v1/settings/oidc/${provider.slug}`
|
||||
);
|
||||
revalidate(response.data);
|
||||
} catch (e) {
|
||||
addToast(intl.formatMessage(messages.deleteError), {
|
||||
autoDismiss: true,
|
||||
|
||||
@@ -159,10 +159,14 @@ const UserLinkedAccountsSettings = () => {
|
||||
...settings.currentSettings.openIdProviders.map((p) => ({
|
||||
name: p.name,
|
||||
action: async () => {
|
||||
const res = await fetch(`/api/v1/auth/oidc/login/${p.slug}`);
|
||||
if (!res.ok) setError(intl.formatMessage(messages.errorUnknown));
|
||||
const json = await res.json();
|
||||
window.location.href = json.redirectUrl;
|
||||
try {
|
||||
const res = await axios.get<{ redirectUrl: string }>(
|
||||
`/api/v1/auth/oidc/login/${p.slug}`
|
||||
);
|
||||
window.location.href = res.data.redirectUrl;
|
||||
} catch (e) {
|
||||
setError(intl.formatMessage(messages.errorUnknown));
|
||||
}
|
||||
},
|
||||
hide: accounts.some(
|
||||
(a) =>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import axios, { isAxiosError } from 'axios'; // <-- Import axios and isAxiosError
|
||||
|
||||
export async function processCallback(
|
||||
params: URLSearchParams,
|
||||
provider: string
|
||||
@@ -9,17 +11,22 @@ export async function processCallback(
|
||||
url.search = params.toString();
|
||||
|
||||
try {
|
||||
const result = await fetch(url);
|
||||
const message = await result.json();
|
||||
// The fetch call is replaced with axios.get.
|
||||
// On success, the JSON response is automatically parsed and available in res.data.
|
||||
const res = await axios.get(url.toString());
|
||||
|
||||
if (!result.ok) {
|
||||
return { type: 'error', message: message.message };
|
||||
}
|
||||
return {
|
||||
type: 'success',
|
||||
message,
|
||||
message: res.data,
|
||||
};
|
||||
} catch (e) {
|
||||
// Axios throws an error for non-2xx responses. We can check if it's an axios error
|
||||
// to safely access the error message from the server's response payload.
|
||||
if (isAxiosError(e) && e.response?.data?.message) {
|
||||
return { type: 'error', message: e.response.data.message };
|
||||
}
|
||||
|
||||
// Fallback for generic errors
|
||||
return {
|
||||
type: 'error',
|
||||
message: e.message,
|
||||
|
||||
Reference in New Issue
Block a user