From 588b30d9bbbd0f8699a4c229452d6d8eea6e7b93 Mon Sep 17 00:00:00 2001 From: Phan An Date: Fri, 25 Dec 2020 12:52:28 +0100 Subject: [PATCH] feat: modify the response format for search --- .../5.0.0/reference/{api.yaml => api.v5.yaml} | 92 +++++++++++++++++-- .../API/Search/ExcerptSearchController.php | 8 +- .../API/Search/SongSearchController.php | 7 +- app/Services/SearchService.php | 36 ++++++-- 4 files changed, 118 insertions(+), 25 deletions(-) rename api-docs/5.0.0/reference/{api.yaml => api.v5.yaml} (95%) diff --git a/api-docs/5.0.0/reference/api.yaml b/api-docs/5.0.0/reference/api.v5.yaml similarity index 95% rename from api-docs/5.0.0/reference/api.yaml rename to api-docs/5.0.0/reference/api.v5.yaml index ea6e0bef..854f48e7 100644 --- a/api-docs/5.0.0/reference/api.yaml +++ b/api-docs/5.0.0/reference/api.v5.yaml @@ -2,7 +2,7 @@ openapi: 3.0.0 info: title: Koel API version: 5.0.0 - description: 'The API for [Koel](http://koel.dev), the music streaming application that works.' + description: 'The API for [Koel](https://koel.dev), the music streaming application that works.' contact: name: An Phan url: 'https://phanan.net' @@ -11,7 +11,7 @@ info: name: MIT url: 'https://github.com/koel/koel/blob/master/LICENSE.md' servers: - - url: 'http://localhost:8000' + - url: 'https://koel.test' description: Local tags: - name: interaction @@ -852,8 +852,7 @@ paths: $ref: '#/components/schemas/Song' operationId: post-os-s3-song description: Create a new song or update an existing one with data sent from AWS - security: - - appKey: [] + security: [] requestBody: content: application/json: @@ -908,8 +907,7 @@ paths: '204': description: No Content description: Remove a song whose information matches the data sent from AWS S3 (`bucket` and `key`) - security: - - appKey: [] + security: [] requestBody: content: application/json: @@ -1103,6 +1101,84 @@ paths: description: Download a whole playlist. This is NOT an XmlHttpRequest. The response will be a download response of either one media file or a zip file containg multiple media files. security: - api-token: [] + /api/search: + get: + summary: 'Search for songs, albums, and artists' + tags: + - search + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + results: + type: object + required: + - songs + - artists + - albums + properties: + songs: + type: array + description: An array of max 6 best-matching songs' IDs + items: + type: string + artists: + type: array + description: An array of max 6 best-matching artists' IDs + items: + type: integer + albums: + type: array + description: An array of max 6 best-matching albums' IDs + items: + type: number + required: + - results + operationId: get-api-search + description: 'Seach for songs, albums, and artists, with a maximum of {count} results each.' + security: + - Bearer Token: [] + parameters: + - schema: + type: string + in: query + name: q + description: The keywords to search + required: true + - schema: + type: integer + minimum: 1 + default: 6 + in: query + name: count + description: 'The maximum number of results for songs, artists, and albums' + parameters: [] + /api/search/songs: + get: + summary: Search for songs + tags: + - search + responses: {} + operationId: get-api-search-songs + description: Get all songs that matches a search query. + security: + - Bearer Token: [] + requestBody: + content: + application/json: + schema: + type: object + properties: + songs: + type: array + description: An array of matching songs' IDs + items: {} + required: + - songs components: schemas: User: @@ -1638,10 +1714,6 @@ components: Bearer Token: type: http scheme: bearer - appKey: - name: The applcation key (APP_KEY in .env) - type: apiKey - in: query api-token: name: The API token as a query parameter type: apiKey diff --git a/app/Http/Controllers/API/Search/ExcerptSearchController.php b/app/Http/Controllers/API/Search/ExcerptSearchController.php index 74a07ae0..d50e5beb 100644 --- a/app/Http/Controllers/API/Search/ExcerptSearchController.php +++ b/app/Http/Controllers/API/Search/ExcerptSearchController.php @@ -22,8 +22,14 @@ class ExcerptSearchController extends Controller throw new InvalidArgumentException('A search query is required.'); } + $count = (int) $request->get('count', SearchService::DEFAULT_EXCERPT_RESULT_COUNT); + + if ($count < 0) { + throw new InvalidArgumentException('Invalid count parameter.'); + } + return [ - 'results' => $this->searchService->excerptSearch($request->get('q')), + 'results' => $this->searchService->excerptSearch($request->get('q'), $count), ]; } } diff --git a/app/Http/Controllers/API/Search/SongSearchController.php b/app/Http/Controllers/API/Search/SongSearchController.php index f3602974..255c475d 100644 --- a/app/Http/Controllers/API/Search/SongSearchController.php +++ b/app/Http/Controllers/API/Search/SongSearchController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\API\Search; use App\Http\Controllers\API\Controller; -use App\Models\Song; use App\Services\SearchService; use Illuminate\Http\Request; use InvalidArgumentException; @@ -24,11 +23,7 @@ class SongSearchController extends Controller } return [ - 'songs' => $this->searchService->searchSongs($request->get('q')) - ->get() - ->map(static function (Song $song): string { - return $song->id; - }), + 'songs' => $this->searchService->searchSongs($request->get('q')), ]; } } diff --git a/app/Services/SearchService.php b/app/Services/SearchService.php index 25073f1b..3e767b11 100644 --- a/app/Services/SearchService.php +++ b/app/Services/SearchService.php @@ -2,15 +2,20 @@ namespace App\Services; +use App\Models\Album; +use App\Models\Artist; +use App\Models\Song; use App\Repositories\AlbumRepository; use App\Repositories\ArtistRepository; use App\Repositories\SongRepository; -use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Collection; use Laravel\Scout\Builder; class SearchService { + public const DEFAULT_EXCERPT_RESULT_COUNT = 6; + private $songRepository; private $albumRepository; private $artistRepository; @@ -26,23 +31,38 @@ class SearchService } /** @return array */ - public function excerptSearch(string $keywords): array + public function excerptSearch(string $keywords, int $count): array { return [ - 'songs' => self::getTopResults($this->songRepository->search($keywords)), - 'artists' => self::getTopResults($this->artistRepository->search($keywords)), - 'albums' => self::getTopResults($this->albumRepository->search($keywords)), + 'songs' => self::getTopResults($this->songRepository->search($keywords), $count) + ->map(static function (Song $song): string { + return $song->id; + }), + 'artists' => self::getTopResults($this->artistRepository->search($keywords), $count) + ->map(static function (Artist $artist): int { + return $artist->id; + }), + 'albums' => self::getTopResults($this->albumRepository->search($keywords), $count) + ->map(static function (Album $album): int { + return $album->id; + }), ]; } /** @return Collection|array */ - private static function getTopResults(Builder $query, int $count = 6): Collection + private static function getTopResults(Builder $query, int $count): Collection { return $query->take($count)->get(); } - public function searchSongs(string $keywords): Builder + /** @return Collection|array */ + public function searchSongs(string $keywords): Collection { - return $this->songRepository->search($keywords); + return $this->songRepository + ->search($keywords) + ->get() + ->map(static function (Song $song): string { + return $song->id; + }); } }