OwnTube-tv / web-client

Portable video client for PeerTube in React Native
https://owntube-tv.github.io/web-client/
The Unlicense
0 stars 11 forks source link

Add service for the PeerTube API, related to #10 #33

Closed mblomdahl closed 1 month ago

mblomdahl commented 2 months ago

This service will be used to interact with the PeerTube backend API. It will be used to reliably retrieve videos when needed; at the moment, its functionality is limited to ...

  1. restricting the subset of videos returned to those classified as "local", "non-live", and "Safe-For-Work"
  2. limiting the number of videos returned to the requested number of videos, and
  3. handling pagination transparently (as the API only returns a maximum of 100 videos on each request)

In the future, this service will be extended to include more functionality, such as ...

  1. handling rate limits enforced by the backend
  2. dealing with unexpected 4xx and 5xx errors gracefully
  3. support for offline mode (i.e. when the backend is unreachable)
  4. retrieving individual video details for playback
  5. long polling for new/changed videos, and
  6. efficient caching (e.g. using IndexedDB) to reduce the number of unnecessary requests

Ping @OGTor & @ar9708 & @tryklick, FYI!


(Note: As an exercise, feel free to see if you can improve upon the PeertubeVideosApi service to make it more readable and understandable, and still passing all tests.)

TOPDeveloperPB commented 2 months ago

In the file OwnTube.tv/lib/peertubeVideosApi.test.ts :

Mocking the API calls: Currently, the tests directly call the PeerTube API. It might be better to mock the API calls using a library like jest-mock or no-mock to isolate the tests and avoid making external requests during testing.

  1. Error Handling:

The tests currently focus on successful responses. Consider adding tests that handle error scenarios like network issues or invalid responses from the API.

Edge Cases: You could explore testing edge cases like fetching 0 videos or exceeding the total available videos by a large margin.

Refactoring for Readability: The test for video properties can be refactored into a separate function to improve readability.

TOPDeveloperPB commented 2 months ago

in the file OwnTube.tv/lib/peertubeVideosApi.ts

Code Duplication: private createAxiosInstance(peertubeHost: string, debugLogging: boolean): void { const baseURL = https://${peertubeHost}/api/v1/; this.instance = axios.create({ baseURL, headers: { "Content-Type": "application/json", "User-Agent": "OwnTube.tv/1.0.0 (https://app.owntube.tv/)", }, });

// Request interceptor this.instance.interceptors.request.use((config) => { if (debugLogging) { console.debug(Requesting '${baseURL}${config.url}' with '${JSON.stringify(config.params)}'); } return config; });

// Response interceptor this.instance.interceptors.response.use( (response) => { if (debugLogging) { console.debug(Received response with status ${response.status}); } return response; }, (error) => { if (debugLogging) { console.error(Error response: ${JSON.stringify(error.response)}); } return Promise.reject(error); } ); }

  1. Type Safety: Ensure type safety wherever possible. For example, when handling Axios responses, you can use TypeScript generics to specify the type of data you expect. 3 Using axios.create: Instead of directly creating an axios instance, you can use axios.create to create a customized instance. This allows you to save the configuration and use it for other requests. Example: private createAxiosInstance(peertubeHost: string): void { const instance = axios.create({ baseURL: https://${peertubeHost}/api/v1/, headers: { "Content-Type": "application/json", "User-Agent": "OwnTube.tv/1.0.0 (https://app.owntube.tv/)", }, });

instance.interceptors.request.use((config) => { if (this.debugLogging) { console.debug(Requesting '${config.baseURL}${config.url}' with '${JSON.stringify(config.params)}'); } return config; });

instance.interceptors.response.use((response) => { if (this.debugLogging) { console.debug( Received response with status ${response.status} and data '${JSON.stringify(response.data).substring(0, 255)}...', ); } return response; });

this.instance = instance; }

Using function parameters: You can pass parameters such as debugLogging as function arguments instead of using class properties. This makes the function more flexible. For example: private createAxiosInstance(peertubeHost: string, debugLogging: boolean): void { const instance = axios.create({ baseURL: https://${peertubeHost}/api/v1/, headers: { "Content-Type": "application/json", "User-Agent": "OwnTube.tv/1.0.0 (https://app.owntube.tv/)", }, });

instance.interceptors.request.use((config) => { if (debugLogging) { console.debug(Requesting '${config.baseURL}${config.url}' with '${JSON.stringify(config.params)}'); } return config; });

instance.interceptors.response.use((response) => { if (debugLogging) { console.debug( Received response with status ${response.status} and data '${JSON.stringify(response.data).substring(0, 255)}...', ); } return response; });

this.instance = instance; }

Extract Constants: You are using some values, such as this.maxChunkSize, multiple times. Extract them into constants to make the code more readable."

Error Handling: Instead of using try/catch inside the loop, you can move this logic outside the loop. This way, you'll avoid unnecessary error catching

mblomdahl commented 2 months ago

@tryklick & @OGTor Rebased this on main after merging #42 this morning. Should be good to merge!

@TOPDeveloperPB I have a hard time following your 2 comments here, it would be a lot easier if you use the GitHub review functionality + apply proper Markdown formatting to code samples.

image
ar9708 commented 1 month ago

Merged in #62