[API-1] feat: search and spotify service

This commit is contained in:
Miguel da Mota 2024-01-01 16:26:44 +01:00
parent 52ef924f12
commit 57588c7e13
10 changed files with 495 additions and 4 deletions

View file

@ -5,6 +5,7 @@ mod middlewares;
mod models;
mod routes;
mod schema;
mod services;
use crate::helpers::db;
use actix_web::{web, App, HttpServer};
@ -22,6 +23,7 @@ async fn main() -> std::io::Result<()> {
.service(routes::auth::login)
.service(routes::me::routes())
.service(routes::users::routes())
.service(routes::search::routes())
})
.bind(("127.0.0.1", 9000))?
.run()

View file

@ -1,4 +1,5 @@
pub mod artists;
pub mod playlists;
pub mod spotify;
pub mod tracks;
pub mod user;

5
src/models/spotify.rs Normal file
View file

@ -0,0 +1,5 @@
pub struct Track {}
pub struct Artist {}
pub struct Album {}

View file

@ -1,4 +1,5 @@
pub mod auth;
pub mod me;
pub mod playlists;
pub mod search;
pub mod users;

26
src/routes/search.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::middlewares::error::ErrorResponse;
use crate::services::spotify;
use actix_web::{get, web, HttpResponse, Result, Scope};
use serde::{Deserialize, Serialize};
pub fn routes() -> Scope {
web::scope("/search").service(search)
}
#[derive(Deserialize)]
struct SearchQuery {
q: String,
}
#[derive(Serialize)]
struct SearchResponse {
track: (),
}
#[get("")]
async fn search(query: web::Query<SearchQuery>) -> Result<HttpResponse, ErrorResponse> {
let spotify = spotify::instance().await;
let track = spotify.search(&query.q).await;
Ok(HttpResponse::Ok().json(SearchResponse { track }))
}

2
src/services/mod.rs Normal file
View file

@ -0,0 +1,2 @@
mod service;
pub mod spotify;

9
src/services/service.rs Normal file
View file

@ -0,0 +1,9 @@
use async_trait::async_trait;
#[async_trait]
pub trait Service: Send + Sync {
fn get_token(&self) -> &String;
async fn fetch_token(&mut self) -> &String;
// async fn get_track_by_isrc(&self, isrc: &str);
}

82
src/services/spotify.rs Normal file
View file

@ -0,0 +1,82 @@
use crate::services::service::Service;
use actix_web::http::Method;
use async_trait::async_trait;
use reqwest::{Client, RequestBuilder};
use serde::Deserialize;
#[derive(Deserialize)]
struct SpotifyResponse {
access_token: String,
}
#[derive(Clone)]
pub struct Spotify {
token: String,
}
pub async fn instance<'a>() -> Spotify {
Spotify::new().await
}
impl Spotify {
pub async fn new() -> Spotify {
let mut spotify = Spotify {
token: String::new(),
};
spotify.fetch_token().await;
spotify
}
fn api(&self, url: &str, method: Method) -> RequestBuilder {
let client = Client::new();
client
.request(method, &format!("https://api.spotify.com/v1{url}"))
.bearer_auth(self.get_token())
}
// pub async fn get_track(self, spotify_id: &str) {
// let spotify = &SPOTIFY;
// }
pub async fn get_artist(self, spotify_id: &str) {}
pub async fn get_track_by_isrc(self, isrc: &str) {}
pub async fn search(self, search: &str) {}
}
#[async_trait]
impl Service for Spotify {
fn get_token(&self) -> &String {
&self.token
}
async fn fetch_token(&mut self) -> &String {
let response = Client::new()
.post("https://accounts.spotify.com/api/token")
.basic_auth(
get_env("SPOTIFY_CLIENT_ID"),
Some(get_env("SPOTIFY_CLIENT_SECRET")),
)
.form(&[("grant_type", "client_credentials")])
.send()
.await;
match response {
Ok(res) => {
let data: Result<SpotifyResponse, _> = res.json().await;
self.token = data.unwrap().access_token.into();
&self.token
}
Err(_) => {
panic!("Invalid response (Spotify Token)")
}
}
}
}
fn get_env(key: &str) -> String {
std::env::var(key).unwrap()
}