Using the API

The extension development kit provides APIs to interact with the main app and perform external network operations.

Fetching App State

For this example lets consider the getCurrentSong API. getCurrentSong returns the actively playing song.

{{#tabs }} {{#tab name="Rust" }}

#![allow(unused)]
fn main() {
impl Provider for SampleExtension {
    fn scrobble(&self, _req: ScrobbleRequest) -> api::MoosyncResult<()> {
        let song = get_current_song()?;
        if let Some(song) = song {
            if let Some(inner) = song.song {
                if let Some(title) = inner.title {
                    info!("Currently playing song: {}", title);
                }
            }
        }
        Ok(())
    }
}
}

{{#endtab }} {{#tab name="Golang" }}

func (s *SampleExtension) Scrobble(req *extensions.ScrobbleRequest) error {
	song, err := api.GetCurrentSong()
	if err != nil {
		return err
	}
	if song != nil && song.GetSong() != nil {
		api.LogInfo("Currently playing song: %s", song.GetSong().GetTitle())
	}
	return nil
}

{{#endtab }} {{#tab name="Python" }}

class ScrobbleExtension(Extension):
    def scrobble(self, req):
        song = self.api.get_current_song()
        if song and song.song:
            print(f"Currently playing: {song.song.title}")

{{#endtab }} {{#tab name="Javascript" }}

export function registerApiUsage() {
  const api = getApi();

  api.on("scrobble", async (req) => {
    const song = await api.getCurrentSong();
    if (song && song.song && song.song.title) {
      console.log("Currently playing song:", song.song.title);
    }
    return new ScrobbleResponse();
  });
}

{{#endtab }} {{#endtabs }}


Making HTTP Requests

Extensions can make outgoing HTTP requests through the host runner using the SDK's HTTP APIs. Both single requests and batch/parallel requests are supported.

Permissions: To communicate with external servers, specify allowed hosts in your extension manifest (package.json) under "allowed_hosts" (for example, ["api.spotify.com", "*.last.fm"]).

{{#tabs }} {{#tab name="Rust" }}

#![allow(unused)]
fn main() {
pub fn search_and_fetch_details(query: &str) -> api::MoosyncResult<()> {
    use moosync_edk::http::{self, HttpRequest};

    let url = format!("https://api.spotify.com/v1/search?q={}&type=track", query);
    let resp = http::get(&url, None)?;
    if resp.is_success() {
        info!("Search response: {}", resp.text().unwrap_or_default());
    }

    let post_req = HttpRequest::post("https://api.spotify.com/v1/playlists")
        .header("Authorization", "Bearer token123")
        .body(r#"{"name":"My Playlist"}"#.as_bytes().to_vec())
        .timeout_ms(5000);
    let post_resp = http::request(&post_req)?;
    info!("Create playlist status: {}", post_resp.status_code);

    let track_urls = vec![
        "https://api.spotify.com/v1/tracks/1",
        "https://api.spotify.com/v1/tracks/2",
    ];
    let responses = http::batch_get(&track_urls, None)?;
    for r in responses {
        info!("Track status: {}", r.status_code);
    }
    Ok(())
}
}

{{#endtab }} {{#tab name="Golang" }}

func searchAndFetchDetails(query string) error {
	url := "https://api.spotify.com/v1/search?q=" + query + "&type=track"
	resp, err := api.HttpGet(url, nil)
	if err != nil {
		return err
	}
	if resp.OK() {
		api.LogInfo("Search response: %s", resp.Text())
	}

	postReq := api.HttpRequest{
		URL:       "https://api.spotify.com/v1/playlists",
		Method:    "POST",
		Headers:   map[string]string{"Authorization": "Bearer token123"},
		Body:      []byte(`{"name":"My Playlist"}`),
		TimeoutMs: 5000,
	}
	postResp, err := api.SendHttpRequest(postReq)
	if err != nil {
		return err
	}
	api.LogInfo("Create playlist status: %d", postResp.StatusCode)

	trackURLs := []string{
		"https://api.spotify.com/v1/tracks/1",
		"https://api.spotify.com/v1/tracks/2",
	}
	resps, errs := api.BatchHttpGet(trackURLs, nil)
	if len(errs) > 0 {
		return errs[0]
	}
	for _, r := range resps {
		api.LogInfo("Track status: %d", r.StatusCode)
	}
	return nil
}

{{#endtab }} {{#tab name="Python" }}

from moosync_edk import http_get, http_request, http_batch_get

def search_and_fetch_details(query):
    url = f"https://api.spotify.com/v1/search?q={query}&type=track"
    resp = http_get(url)
    if resp.ok:
        print(f"Search response: {resp.text}")

    post_resp = http_request(
        url="https://api.spotify.com/v1/playlists",
        method="POST",
        headers={"Authorization": "Bearer token123"},
        body='{"name": "My Playlist"}',
        timeout_ms=5000,
    )
    print(f"Create playlist status: {post_resp.status_code}")

    track_urls = [
        "https://api.spotify.com/v1/tracks/1",
        "https://api.spotify.com/v1/tracks/2",
    ]
    resps = http_batch_get(track_urls)
    for r in resps:
        print(f"Track status: {r.status_code}")

{{#endtab }} {{#tab name="Javascript" }}

export async function searchAndFetchDetails(query: string) {
  const api = getApi();

  const url = `https://api.spotify.com/v1/search?q=${encodeURIComponent(query)}&type=track`;
  const resp = await api.fetch(url);
  if (resp.ok) {
    const text = await resp.text();
    console.log("Search response:", text);
  }

  const postResp = await api.fetch({
    url: "https://api.spotify.com/v1/playlists",
    method: "POST",
    headers: { Authorization: "Bearer token123" },
    body: JSON.stringify({ name: "My Playlist" }),
    timeoutMs: 5000,
  });
  console.log("Create playlist status:", postResp.status);

  const responses = await api.batchFetch([
    "https://api.spotify.com/v1/tracks/1",
    "https://api.spotify.com/v1/tracks/2",
  ]);
  for (const r of responses) {
    console.log("Track status:", r.status);
  }
}

{{#endtab }} {{#endtabs }}