Code Monkey home page Code Monkey logo

soundify's Introduction

Hi, I'm Artem! 👋

19-year-old guy originally from Ukraine, but due to the war, I currently live in Poland.
I mainly work with UI, but I'm constantly learning new things and keeping an eye on technology in other areas.

Currently studying for a computer science in WSZIB Kraków

wakatime

soundify's People

Contributors

allcontributors[bot] avatar danluki avatar lwjerri avatar mellkam avatar renovate[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

danluki itsbrex

soundify's Issues

[Bug]: `PageIterator` skip last track

For example, I have a playlist with 45 tracks, and when I use PageIterator for getPlaylistTracks I receive a partial tracks list. Here minimal code to reproduce the problem:

const playlistTracksIterator = new PageIterator((opts) =>
  getPlaylistTracks(client, PLAYLIST_ID, opts),
);
const playlistTracksList = await playlistTracksIterator.collect();

console.log(preparedTracksList.length); // 44, because last track is missed.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yaml
  • actions/checkout v3
  • actions/setup-node v3
  • pnpm/action-setup v2
  • actions/checkout v3
  • actions/setup-node v3
  • pnpm/action-setup v2
  • codecov/codecov-action v3
  • actions/checkout v3
  • actions/setup-node v3
  • pnpm/action-setup v2
.github/workflows/npm-publish.yaml
  • actions/checkout v3
  • actions/setup-node v3
  • pnpm/action-setup v2
npm
examples/next-ssr/package.json
  • cookies-next 2.1.2
  • next 13.4.6
  • react 18.2.0
  • react-dom 18.2.0
  • @tanstack/react-query 4.29.14
  • typescript 5.1.3
examples/node-express-auth/package.json
  • cookie-parser 1.4.6
  • express 4.18.2
  • @types/cookie-parser 1.4.3
  • @types/express 4.17.17
  • typescript 5.1.3
examples/react-implicit-grant/package.json
  • @tanstack/react-query 4.29.14
  • react 18.2.0
  • react-dom 18.2.0
  • react-router-dom 6.13.0
  • @vitejs/plugin-react 3.1.0
  • typescript 5.1.3
  • vite 4.3.9
examples/react-pkce-auth/package.json
  • @tanstack/react-query 4.29.14
  • react 18.2.0
  • react-dom 18.2.0
  • react-router-dom 6.13.0
  • @vitejs/plugin-react 3.1.0
  • typescript 5.1.3
  • vite 4.3.9
package.json
  • @types/node 20.3.1
  • all-contributors-cli 6.26.0
  • envalid 7.3.1
  • prettier 2.8.8
  • rimraf 5.0.1
  • typescript 5.1.3
  • vite 4.3.9
  • vitest 0.32.2
  • @vitest/coverage-c8 0.32.2
  • vitest-fetch-mock 0.2.2
  • @faker-js/faker 8.0.2
  • pnpm 8.6.3

  • Check this box to trigger a request for Renovate to run again on this repository

Add the ability to call endpoint functions from the class, instead of separate functions

The problem is that the endpoints are a bunch of separate functions that need to pass the client as the first argument each time. In code it look like this:

import { SpoitifyClient, getCurrentUserProfile, getUserProfile } from "soundify-web-api";

const client = new SpotifyClient("ACCESS_TOKEN");

const currentUser = await getCurrentUserProfile(client);
const user123 = await getUserProfile(client, "some-user-id-123");

The obvious question would be: why can't we do that?

import { SpotifyClient } from "soundify-web-api";

const client = new SpotifyCleint("ACCESS_TOKEN");

const currentUser = await client.getCurrentUserProfile();
const user123 = await client.getUserProfile("some-user-id-123");

The answer is this. We want to have a treeshake on the client and not import all the functions we don't need. Plus, personally I don't like to write one huge class with hundreds of methods.
But for the backend, it's much easier to use this type of composition. It would be great for implementing dependencies and a good developer experience. So what can we do?

Functions or class methods for api calls?

Currently, api calls are presented as separate functions, such as this one.

export const getCurrentUserProfile = (spotifyClient: ISpotifyClient) => {
    return spotifyClient.fetch<UserPrivate>("/me");
};

// Usage example
const spotifyClient = new SpotifyClient(...);
const user = await getCurrentUserProfile(spotifyClient);

But in most api libraries, you can see a single class that contains all the api calls, so you can just do that.

const spotifyAPI = new SpotifyAPI()
const user = await spotifyAPI.getCurrentUserProfile();

What do you prefer to use?
Please write what you think about it. You can just "prefer functions" or "prefer class".

From my point of view, I can highlight some pros and cons:

  • Pros
    • Easy to treeshake in a web bundle.
    • Decomposition. Much easier to support a bunch of functions than one big class (in my opinion).
  • Cons.
    • A class is just easier to use. You can pass it throughout your application and use it. It's awkwardly to pass a client every time just to use call. Idk

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: .github/renovate.json
Error type: The renovate configuration file contains some invalid settings
Message: "fileMatch" may not be defined at the top level of a config and must instead be within a manager block

v0.1.0 TODO

Authorization flows

  • Authorization Code Flow - AuthCode namespace
  • Implicit Grant Flow - ImplicitGrant namespace
  • Client Credentials Flow - ClientCredentials namespace
  • Authorization code with PKCE - PKCEAuthCode namespace

API coverage

Examples

Other

  • Ability to retry when 5xx or 429 is received. Example below
const client = new SpotifyClient("ACCESS_TOKEN", {
  retry5xx: {
    times: 5,
    delay: 0,
  },
  retry429: {
    times: 3,
    delay: 300,
  }
})

Future TODO

  • Make tests with json schema validation to ensure that types are correct. Maybe it futures releases.
  • Shows, Episodes, Audiobooks, Chapters, Player endpoints

Automatic pagination

Paginator will create request for every 20 tracks.

const playlistTracks = new Paginator((opts) =>
  getPlaylistTracks(client, "6LPdVFowaGmmHu3nb20Mg3", opts)
);

for await (const track of playlistTracks) {
  console.log(track);
}

You can change the chunk size by setting limit in second argument.

const playlistTracks = new Paginator(
  (opts) => getPlaylistTracks(client, "6LPdVFowaGmmHu3nb20Mg3", opts),
  { limit: 50 }
);

Tests for the API

describe("getEpisode", async () => {
  test("returns an episode object", async () => {
    const episode_id = "123";
    const market = "EN" as Market;
    const spotify_episode_response = {
      description:
        "A Spotify podcast sharing fresh insights on important topics of the moment—in a way only Spotify can. You’ll hear from experts in the music, podcast and tech industries as we discover and uncover stories about our work and the world around us.",
      html_description:
        "<p>A Spotify podcast sharing fresh insights on important topics of the moment—in a way only Spotify can. You’ll hear from experts in the music, podcast and tech industries as we discover and uncover stories about our work and the world around us.</p>",
      duration_ms: 1686230,
      explicit: false,
      external_urls: {
        spotify: "string"
      },
      href: "https://api.spotify.com/v1/episodes/5Xt5DXGzch68nYYamXrNxZ",
      id: "5Xt5DXGzch68nYYamXrNxZ",
      images: [
        {
          url: "https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228",
          height: 300,
          width: 300
        }
      ],
      is_externally_hosted: false,
      is_playable: false,
      language: "en",
      languages: ["fr", "en"],
      name: "Starting Your Own Podcast: Tips, Tricks, and Advice From Anchor Creators",
      release_date: "1981-12-15",
      release_date_precision: "day",
      resume_point: {
        fully_played: false,
        resume_position_ms: 0
      },
      type: "episode",
      uri: "spotify:episode:0zLhl3WsOCQHbe1BPTiHgr",
      restrictions: {
        reason: "string"
      },
      show: {
        available_markets: ["string"],
        copyrights: [
          {
            text: "string",
            type: "string"
          }
        ],
        description: "string",
        html_description: "string",
        explicit: false,
        external_urls: {
          spotify: "string"
        },
        href: "string",
        id: "string",
        images: [
          {
            url: "https://i.scdn.co/image/ab67616d00001e02ff9ca10b55ce82ae553c8228",
            height: 300,
            width: 300
          }
        ],
        languages: ["string"],
        media_type: "string",
        name: "string",
        publisher: "string",
        type: "show",
        uri: "string",
        total_episodes: 0
      }
    };

    const mockedFetch = vi.fn();
    mockedFetch.mockResolvedValue(spotify_episode_response);
    const client: HTTPClient = {
      fetch: mockedFetch
    };

    const result = await getEpisode(client, episode_id, market);

    expect(client.fetch).toHaveBeenCalledWith(
      `/episodes/${episode_id}`,
      "json",
      { query: { market } }
    );
    expect(result).toBeDefined();
    expect(result).toMatchObject(spotify_episode_response);
  });
});

There is what i got for getEpisode, wanna see you opinion is this enough or we need more tests for api methods. Because I think it's not full. Or, I just want to see you @MellKam code for this tests as a example.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.