feat: api - add a new endpoint - GET /api/v2/versions/{versionCode}
This commit is contained in:
parent
28877f1b9b
commit
a66bbb0b2f
|
@ -36,6 +36,19 @@ paths:
|
|||
$ref: "#/components/responses/ListVersionsResponse"
|
||||
default:
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
/v2/versions/{versionCode}:
|
||||
get:
|
||||
operationId: getVersion
|
||||
tags:
|
||||
- versions
|
||||
description: Get a version
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/VersionCodePathParam"
|
||||
responses:
|
||||
200:
|
||||
$ref: "#/components/responses/GetVersionResponse"
|
||||
default:
|
||||
$ref: "#/components/responses/ErrorResponse"
|
||||
components:
|
||||
schemas:
|
||||
Error:
|
||||
|
@ -81,29 +94,23 @@ components:
|
|||
timezone:
|
||||
type: string
|
||||
example: Europe/Warsaw
|
||||
PaginationResponse:
|
||||
Cursor:
|
||||
type: object
|
||||
x-go-type-skip-optional-pointer: true
|
||||
properties:
|
||||
self:
|
||||
description: Cursor pointing to the current page.
|
||||
type: string
|
||||
x-go-type-skip-optional-pointer: true
|
||||
first:
|
||||
description: Cursor pointing to the first page.
|
||||
type: string
|
||||
x-go-type-skip-optional-pointer: true
|
||||
prev:
|
||||
description: Cursor pointing to the previous page.
|
||||
type: string
|
||||
x-go-type-skip-optional-pointer: true
|
||||
next:
|
||||
description: Cursor pointing to the next page.
|
||||
type: string
|
||||
x-go-type-skip-optional-pointer: true
|
||||
last:
|
||||
description: Cursor pointing to the last page.
|
||||
type: string
|
||||
x-go-type-skip-optional-pointer: true
|
||||
PaginationResponse:
|
||||
type: object
|
||||
properties:
|
||||
cursor:
|
||||
$ref: "#/components/schemas/Cursor"
|
||||
parameters:
|
||||
CursorQueryParam:
|
||||
in: query
|
||||
|
@ -117,6 +124,12 @@ components:
|
|||
schema:
|
||||
type: integer
|
||||
required: false
|
||||
VersionCodePathParam:
|
||||
in: path
|
||||
name: versionCode
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
ListVersionsResponse:
|
||||
description: ""
|
||||
|
@ -127,12 +140,23 @@ components:
|
|||
- $ref: "#/components/schemas/PaginationResponse"
|
||||
- type: object
|
||||
required:
|
||||
- items
|
||||
- data
|
||||
properties:
|
||||
items:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/Version"
|
||||
GetVersionResponse:
|
||||
description: ""
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/Version"
|
||||
ErrorResponse:
|
||||
description: Default error response.
|
||||
content:
|
||||
|
|
|
@ -45,6 +45,10 @@ type listVersionsParamsApplier struct {
|
|||
}
|
||||
|
||||
func (a listVersionsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
||||
if codes := a.params.Codes(); len(codes) > 0 {
|
||||
q = q.Where("version.code IN (?)", bun.In(codes))
|
||||
}
|
||||
|
||||
for _, s := range a.params.Sort() {
|
||||
codeCursor := a.params.Cursor().Code()
|
||||
|
||||
|
|
|
@ -139,6 +139,36 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
|||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: codes limit=1",
|
||||
params: func(t *testing.T) domain.ListVersionsParams {
|
||||
t.Helper()
|
||||
|
||||
params := domain.NewListVersionsParams()
|
||||
require.NoError(t, params.SetLimit(1))
|
||||
|
||||
res, err := repos.version.List(ctx, params)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, res)
|
||||
|
||||
require.NoError(t, params.SetCodes([]string{res.Versions()[0].Code()}))
|
||||
|
||||
return params
|
||||
},
|
||||
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||
t.Helper()
|
||||
versions := res.Versions()
|
||||
codes := params.Codes()
|
||||
assert.Len(t, versions, len(codes))
|
||||
for _, v := range versions {
|
||||
assert.Contains(t, codes, v.Code())
|
||||
}
|
||||
},
|
||||
assertError: func(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.NoError(t, err)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "OK: limit=5",
|
||||
params: func(t *testing.T) domain.ListVersionsParams {
|
||||
|
|
|
@ -24,3 +24,24 @@ func (svc *VersionService) List(
|
|||
) (domain.ListVersionsResult, error) {
|
||||
return svc.repo.List(ctx, params)
|
||||
}
|
||||
|
||||
func (svc *VersionService) Get(ctx context.Context, code string) (domain.Version, error) {
|
||||
params := domain.NewListVersionsParams()
|
||||
if err := params.SetCodes([]string{code}); err != nil {
|
||||
return domain.Version{}, err
|
||||
}
|
||||
|
||||
res, err := svc.repo.List(ctx, params)
|
||||
if err != nil {
|
||||
return domain.Version{}, err
|
||||
}
|
||||
|
||||
versions := res.Versions()
|
||||
if len(versions) == 0 {
|
||||
return domain.Version{}, domain.VersionNotFoundError{
|
||||
VersionCode: code,
|
||||
}
|
||||
}
|
||||
|
||||
return versions[0], nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package domain
|
|||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
|
@ -172,6 +173,7 @@ func (vc VersionCursor) Encode() string {
|
|||
}
|
||||
|
||||
type ListVersionsParams struct {
|
||||
codes []string
|
||||
sort []VersionSort
|
||||
cursor VersionCursor
|
||||
limit int
|
||||
|
@ -189,6 +191,15 @@ func NewListVersionsParams() ListVersionsParams {
|
|||
}
|
||||
}
|
||||
|
||||
func (params *ListVersionsParams) Codes() []string {
|
||||
return params.codes
|
||||
}
|
||||
|
||||
func (params *ListVersionsParams) SetCodes(codes []string) error {
|
||||
params.codes = codes
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
versionSortMinLength = 1
|
||||
versionSortMaxLength = 1
|
||||
|
@ -308,3 +319,25 @@ func (res ListVersionsResult) Self() VersionCursor {
|
|||
func (res ListVersionsResult) Next() VersionCursor {
|
||||
return res.next
|
||||
}
|
||||
|
||||
type VersionNotFoundError struct {
|
||||
VersionCode string
|
||||
}
|
||||
|
||||
func (e VersionNotFoundError) Error() string {
|
||||
return fmt.Sprintf("version with code %s not found", e.VersionCode)
|
||||
}
|
||||
|
||||
func (e VersionNotFoundError) Code() ErrorCode {
|
||||
return ErrorCodeNotFound
|
||||
}
|
||||
|
||||
func (e VersionNotFoundError) Slug() string {
|
||||
return "version-not-found"
|
||||
}
|
||||
|
||||
func (e VersionNotFoundError) Params() map[string]any {
|
||||
return map[string]any{
|
||||
"Code": e.VersionCode,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,16 @@ func (h *apiHTTPHandler) ListVersions(w http.ResponseWriter, r *http.Request, pa
|
|||
renderJSON(w, r, http.StatusOK, apimodel.NewListVersionsResponse(res))
|
||||
}
|
||||
|
||||
func (h *apiHTTPHandler) GetVersion(w http.ResponseWriter, r *http.Request, versionCode apimodel.VersionCodePathParam) {
|
||||
version, err := h.versionSvc.Get(r.Context(), versionCode)
|
||||
if err != nil {
|
||||
apiErrorRenderer{errors: []error{err}}.render(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
renderJSON(w, r, http.StatusOK, apimodel.NewGetVersionResponse(version))
|
||||
}
|
||||
|
||||
func formatListVersionsParamsErrorPath(elems []errorPathElement) []string {
|
||||
if elems[0].model != "ListVersionsParams" {
|
||||
return nil
|
||||
|
|
|
@ -17,14 +17,22 @@ func NewListVersionsResponse(res domain.ListVersionsResult) ListVersionsResponse
|
|||
versions := res.Versions()
|
||||
|
||||
resp := ListVersionsResponse{
|
||||
Items: make([]Version, 0, len(versions)),
|
||||
Self: res.Self().Encode(),
|
||||
Next: res.Next().Encode(),
|
||||
Data: make([]Version, 0, len(versions)),
|
||||
Cursor: Cursor{
|
||||
Next: res.Next().Encode(),
|
||||
Self: res.Self().Encode(),
|
||||
},
|
||||
}
|
||||
|
||||
for _, v := range versions {
|
||||
resp.Items = append(resp.Items, NewVersion(v))
|
||||
resp.Data = append(resp.Data, NewVersion(v))
|
||||
}
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
func NewGetVersionResponse(v domain.Version) GetVersionResponse {
|
||||
return GetVersionResponse{
|
||||
Data: NewVersion(v),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user