Personal Site

Properly handle TypeError: fetch() failed in the spotify API

vielle.dev a3314bb6 f75613f5

verified
+26 -3
+9 -1
src/components/home/playing/spotify/access.ts
··· 13 13 * @param userAuthCode Authentication code for the user (via callback). Uses the stored refresh token if not provided 14 14 * @returns `string`: access code to authorize requests 15 15 * @returns `undefined`: failed to authenticate user. 16 + * @returns `SpotofyError<NETWORK_ERR>` when a network error occours and the fetch request fails. 16 17 * @throws `SpotifyError<NO_AUTH>` when no refresh token is stored and no auth code is provided 17 18 */ 18 19 export default async function getAccessCode(userAuthCode?: string) { ··· 107 108 console.error("Response JSON failed", err); 108 109 else if (err instanceof SpotifyError && err.code === "INVALID_AUTH_RES") 109 110 console.error("Response malformed:", err); 110 - else { 111 + else if (err instanceof TypeError) { 112 + console.error("A network error occurred.", err); 113 + return new SpotifyError( 114 + "NETWORK_ERR", 115 + err, 116 + "Network error occurred. Could not reach spotify servers or something else.", 117 + ); 118 + } else { 111 119 console.error("Unhandled exception."); 112 120 throw err; 113 121 }
+16 -2
src/components/home/playing/spotify/api.ts
··· 7 7 * Wrapper for authorizing a spotify API with default headers etc 8 8 * @param url API endpoint to call. Pass a leading slash 9 9 * @returns `Response` 10 + * @throws `SpotifyError<NETWORK_ERR>` when a fetch request fails 10 11 * @throws `SpotifyError<NO_AUTH>` when auth fails 11 12 * @throws `Response` on non 200-299 status codes 12 13 */ ··· 21 22 "Failed to get access code. try using src/pages/_callback", 22 23 ); 23 24 25 + if (accessToken instanceof SpotifyError) throw accessToken; 26 + 24 27 // fetch the api and throw on non 2** code 25 28 return fetch(`https://api.spotify.com/v1${url}`, { 26 29 headers: { 27 30 Authorization: `Bearer ${accessToken}`, 28 31 }, 29 - }).then((res) => (res.ok ? res : throws(res))); 32 + }) 33 + .catch((err) => 34 + err instanceof TypeError 35 + ? throws( 36 + new SpotifyError("NETWORK_ERR", err, "Spotify API request failed"), 37 + ) 38 + : throws(err), 39 + ) 40 + .then((res) => (res.ok ? res : throws(res))); 30 41 } 31 42 /** 32 43 * Get the current playing track 33 44 * @returns `nowPlaying` 34 - * @throws `SpotifyError` of NO_AUTH | UNHANDLED_API_ERR | INVALID_AUTH_RES | RATE_LIMITED | NO_CONTENT | MALFORMED_SPOTIFY_RES 45 + * @throws `SpotifyError` of NO_AUTH | UNHANDLED_API_ERR | INVALID_AUTH_RES | RATE_LIMITED | NO_CONTENT | MALFORMED_SPOTIFY_RES | NETWORK_ERR 35 46 */ 36 47 export async function spotifyNowPlaying() { 37 48 type success = nowPlaying; ··· 46 57 if (err instanceof SpotifyError && err.code === "NO_AUTH") { 47 58 console.error("Authentication failed:", err.human); 48 59 rej(err); 60 + } else if (err instanceof SpotifyError && err.code === "NETWORK_ERR") { 61 + console.error("Network request failed:", err.human); 62 + rej(err) 49 63 } 50 64 }); 51 65
+1
src/components/home/playing/spotify/errors.ts
··· 7 7 "RATE_LIMITED", 8 8 "NO_CONTENT", 9 9 "MALFORMED_SPOTIFY_RES", 10 + "NETWORK_ERR" 10 11 ] as const; 11 12 12 13 export class SpotifyError {