add api docs for artist routes

+ extract hash and limit schemas
This commit is contained in:
mungai-njoroge
2024-03-04 01:31:46 +03:00
committed by Mungai Njoroge
parent 9e50eb4395
commit 7d064a8562
4 changed files with 163 additions and 81 deletions
+16 -4
View File
@@ -2,6 +2,7 @@
This module combines all API blueprints into a single Flask app instance.
"""
import datetime
from flask_cors import CORS
from flask_compress import Compress
@@ -28,6 +29,19 @@ from app.api import (
getall,
)
open_api_description = f"""
The REST API exposed by your Swing Music server
### Definition of terms:
#### 1. `limit`: The number of items to return.
In endpoints that request multiple lists of items, this represents the number of items to return for each list.
---
[MIT License](https://github.com/swing-opensource/swingmusic?tab=MIT-1-ov-file#MIT-1-ov-file) | Copyright (c) {datetime.datetime.now().year} [Mungai Njoroge](https://mungai.vercel.app)
"""
def create_api():
"""
@@ -36,9 +50,7 @@ def create_api():
api_info = Info(
title=f"Swing Music",
version=f"v{Keys.SWINGMUSIC_APP_VERSION}",
license={"name": "MIT", "url": "https://github.com/swing-opensource/swingmusic?tab=MIT-1-ov-file#MIT-1-ov-file"},
contact={"name": "Mungai Njoroge", "url": "https://mungai.vercel.app", "email": "geoffreymungai45@gmail.com"},
description="The REST API exposed by your Swing Music server",
description=open_api_description,
)
app = OpenAPI(__name__, info=api_info)
@@ -52,7 +64,7 @@ def create_api():
with app.app_context():
app.register_api(album.api)
app.register_blueprint(artist.api)
app.register_api(artist.api)
app.register_blueprint(send_file.api)
app.register_blueprint(search.api)
app.register_blueprint(folder.api)
+33 -48
View File
@@ -7,6 +7,7 @@ import random
from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint
from pydantic import BaseModel, Field
from app.api.apischemas import AlbumHashSchema, AlbumLimitSchema, ArtistHashSchema
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
@@ -23,22 +24,15 @@ from app.utils.hashing import create_hash
get_albums_by_albumartist = adb.get_albums_by_albumartist
check_is_fav = favdb.check_is_favorite
book_tag = Tag(name="Album", description="Single album")
api = APIBlueprint("album", __name__, url_prefix="", abp_tags=[book_tag])
bp_tag = Tag(name="Album", description="Single album")
api = APIBlueprint("album", __name__, url_prefix="", abp_tags=[bp_tag])
class GetAlbumBody(BaseModel):
albumhash: str = Field(
description="The hash of the album to get",
example="49e4819273",
min_length=Defaults.HASH_LENGTH,
max_length=Defaults.HASH_LENGTH,
)
@api.post("/album", summary="Get album")
def get_album_tracks_and_info(body: GetAlbumBody):
@api.post("/album")
def get_album_tracks_and_info(body: AlbumHashSchema):
"""
Get album and tracks
Returns album info and tracks for the given albumhash.
"""
albumhash = body.albumhash
@@ -84,43 +78,39 @@ def get_album_tracks_and_info(body: GetAlbumBody):
"info": album,
}
class GetAlbumTracksQuery(BaseModel):
albumhash: str = Field(
description="The hash of the album",
example="49e4819273",
min_length=Defaults.HASH_LENGTH,
max_length=Defaults.HASH_LENGTH,
)
@api.get("/album/<albumhash>/tracks", summary="Get album tracks")
def get_album_tracks(query: GetAlbumTracksQuery):
@api.get("/album/<albumhash>/tracks")
def get_album_tracks(path: AlbumHashSchema):
"""
Get album tracks
Returns all the tracks in the given album, sorted by disc and track number.
NOTE: No album info is returned.
"""
tracks = TrackStore.get_tracks_by_albumhash(query.albumhash)
tracks = TrackStore.get_tracks_by_albumhash(path.albumhash)
tracks = sort_by_track_no(tracks)
return tracks
class GetMoreFromArtistsBody(BaseModel):
class GetMoreFromArtistsBody(AlbumLimitSchema):
albumartists: str = Field(
description="The artist hashes to get more albums from",
example=Defaults.API_ARTISTHASH
)
limit: int = Field(
description="The maximum number of albums to return per artist",
example=7,
default=7,
example=Defaults.API_ARTISTHASH,
)
base_title: str = Field(
description="The base title of the album to exclude from the results.",
example=Defaults.API_ALBUMNAME,
default=None,
)
@api.post("/album/from-artist", summary="More from artist")
@api.post("/album/from-artist")
def get_more_from_artist(body: GetMoreFromArtistsBody):
"""
Get more from artist
Returns more albums from the given artist hashes.
"""
albumartists = body.albumartists
@@ -151,7 +141,7 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
return albums
class GetAlbumVersionsBody(BaseModel):
class GetAlbumVersionsBody(ArtistHashSchema):
og_album_title: str = Field(
description="The original album title (album.og_title)",
example=Defaults.API_ALBUMNAME,
@@ -160,14 +150,13 @@ class GetAlbumVersionsBody(BaseModel):
description="The base title of the album to exclude from the results.",
example=Defaults.API_ALBUMNAME,
)
artisthash: str = Field(
description="The artist hash",
example=Defaults.API_ARTISTHASH,
)
@api.post("/album/other-versions", summary="Get other versions")
@api.post("/album/other-versions")
def get_album_versions(body: GetAlbumVersionsBody):
"""
Get other versions
Returns other versions of the given album.
"""
og_album_title = body.og_album_title
@@ -189,20 +178,16 @@ def get_album_versions(body: GetAlbumVersionsBody):
return albums
class GetSimilarAlbumsQuery(BaseModel):
artisthash: str = Field(
description="The artist hash",
example=Defaults.API_ARTISTHASH,
)
limit: int = Field(
description="The maximum number of albums to return",
example=Defaults.API_CARD_LIMIT,
default=Defaults.API_CARD_LIMIT,
)
@api.get("/album/similar", summary="Get similar albums")
class GetSimilarAlbumsQuery(ArtistHashSchema, AlbumLimitSchema):
pass
@api.get("/album/similar")
def get_similar_albums(query: GetSimilarAlbumsQuery):
"""
Get similar albums
Returns similar albums to the given album.
"""
artisthash = query.artisthash
+83
View File
@@ -0,0 +1,83 @@
"""
Reusable Pydantic basic schemas for the API
"""
from pydantic import BaseModel, Field
from app.settings import Defaults
class AlbumHashSchema(BaseModel):
"""
Extending this class will give you a model with the `albumhash` field
"""
albumhash: str = Field(
description="The album hash",
example=Defaults.API_ALBUMHASH,
min_length=Defaults.HASH_LENGTH,
max_length=Defaults.HASH_LENGTH,
)
class ArtistHashSchema(BaseModel):
"""
Extending this class will give you a model with the `artisthash` field
"""
artisthash: str = Field(
description="The artist hash",
example=Defaults.API_ARTISTHASH,
min_length=Defaults.HASH_LENGTH,
max_length=Defaults.HASH_LENGTH,
)
class GenericLimitSchema(BaseModel):
"""
Extending this class will give you a model with the `limit` field
"""
limit: int = Field(
description="The number of items to return",
example=Defaults.API_CARD_LIMIT,
default=Defaults.API_CARD_LIMIT
)
# INFO: The following 3 classes are duplicated to specify the type of items
class TrackLimitSchema(BaseModel):
"""
Extending this class will give you a model with the `limit` field
"""
limit: int = Field(
description="The number of tracks to return",
example=Defaults.API_CARD_LIMIT,
default=Defaults.API_CARD_LIMIT
)
class AlbumLimitSchema(BaseModel):
"""
Extending this class will give you a model with the `limit` field
"""
limit: int = Field(
description="The number of albums to return",
example=Defaults.API_CARD_LIMIT,
default=Defaults.API_CARD_LIMIT
)
class ArtistLimitSchema(BaseModel):
"""
Extending this class will give you a model with the `limit` field
"""
limit: int = Field(
description="The number of artists to return",
example=Defaults.API_CARD_LIMIT,
default=Defaults.API_CARD_LIMIT
)
+31 -29
View File
@@ -1,11 +1,15 @@
"""
Contains all the artist(s) routes.
"""
import math
import random
from datetime import datetime
from flask import Blueprint, request
from flask import request
from flask_openapi3 import APIBlueprint, Tag
from pydantic import BaseModel, Field
from app.api.apischemas import AlbumLimitSchema, ArtistHashSchema, ArtistLimitSchema, TrackLimitSchema
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as fmdb
@@ -16,20 +20,19 @@ from app.store.albums import AlbumStore
from app.store.artists import ArtistStore
from app.store.tracks import TrackStore
api = Blueprint("artist", __name__, url_prefix="/")
bp_tag = Tag(name="Artist", description="Single artist")
api = APIBlueprint("artist", __name__, url_prefix="/", abp_tags=[bp_tag])
@api.route("/artist/<artisthash>", methods=["GET"])
def get_artist(artisthash: str):
@api.get("/artist/<string:artisthash>")
def get_artist(path: ArtistHashSchema, query: TrackLimitSchema):
"""
Get artist data.
Returns artist data, tracks and genres for the given artisthash.
"""
limit = request.args.get("limit")
if limit is None:
limit = 6
limit = int(limit)
artisthash = path.artisthash
limit = query.limit
artist = ArtistStore.get_artist_by_hash(artisthash)
@@ -79,16 +82,18 @@ def get_artist(artisthash: str):
}
@api.route("/artist/<artisthash>/albums", methods=["GET"])
def get_artist_albums(artisthash: str):
limit = request.args.get("limit")
class GetArtistAlbumsQuery(AlbumLimitSchema):
all: bool = Field(
description="Whether to ignore limit and return all albums", default=False
)
if limit is None:
limit = 6
return_all = request.args.get("all")
@api.get("/artist/<artisthash>/albums")
def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
return_all = query.all
artisthash = path.artisthash
limit = int(limit)
limit = query.limit
all_albums = AlbumStore.get_albums_by_artisthash(artisthash)
@@ -170,29 +175,26 @@ def get_artist_albums(artisthash: str):
}
@api.route("/artist/<artisthash>/tracks", methods=["GET"])
def get_all_artist_tracks(artisthash: str):
@api.get("/artist/<artisthash>/tracks")
def get_all_artist_tracks(path: ArtistHashSchema):
"""
Get all artist tracks
Returns all artists by a given artist.
"""
tracks = TrackStore.get_tracks_by_artisthash(artisthash)
tracks = TrackStore.get_tracks_by_artisthash(path.artisthash)
return {"tracks": serialize_tracks(tracks)}
@api.route("/artist/<artisthash>/similar", methods=["GET"])
def get_similar_artists(artisthash: str):
@api.get("/artist/<artisthash>/similar")
def get_similar_artists(path: ArtistHashSchema, query: ArtistLimitSchema):
"""
Returns similar artists.
"""
limit = request.args.get("limit")
limit = query.limit
if limit is None:
limit = 6
limit = int(limit)
artist = ArtistStore.get_artist_by_hash(artisthash)
artist = ArtistStore.get_artist_by_hash(path.artisthash)
if artist is None:
return {"error": "Artist not found"}, 404