feat: api - add a new endpoint - GET /api/v2/versions/{versionCode}/servers/{serverKey}

This commit is contained in:
Dawid Wysokiński 2024-02-10 11:53:14 +01:00
parent 79337cd60a
commit 6d61e43143
Signed by: Kichiyaki
GPG Key ID: B5445E357FB8B892
8 changed files with 167 additions and 11 deletions

View File

@ -67,6 +67,21 @@ paths:
$ref: "#/components/responses/ListServersResponse"
default:
$ref: "#/components/responses/ErrorResponse"
/v2/versions/{versionCode}/servers/{serverKey}:
get:
operationId: getServer
tags:
- versions
- servers
description: Get a server
parameters:
- $ref: "#/components/parameters/VersionCodePathParam"
- $ref: "#/components/parameters/ServerKeyPathParam"
responses:
200:
$ref: "#/components/responses/GetServerResponse"
default:
$ref: "#/components/responses/ErrorResponse"
components:
schemas:
Error:
@ -205,6 +220,12 @@ components:
required: true
schema:
type: string
ServerKeyPathParam:
in: path
name: serverKey
required: true
schema:
type: string
responses:
ListVersionsResponse:
description: ""
@ -247,6 +268,17 @@ components:
type: array
items:
$ref: "#/components/schemas/Server"
GetServerResponse:
description: ""
content:
application/json:
schema:
type: object
required:
- data
properties:
data:
$ref: "#/components/schemas/Server"
ErrorResponse:
description: Default error response.
content:

View File

@ -307,3 +307,36 @@ func (svc *ServerService) UpdatePlayerSnapshotsCreatedAt(
return svc.repo.Update(ctx, key, updateParams)
}
func (svc *ServerService) GetNormalByVersionCodeAndServerKey(
ctx context.Context,
versionCode, key string,
) (domain.Server, error) {
params := domain.NewListServersParams()
if err := params.SetVersionCodes([]string{versionCode}); err != nil {
return domain.Server{}, err
}
if err := params.SetKeys([]string{key}); err != nil {
return domain.Server{}, err
}
if err := params.SetSpecial(domain.NullBool{
Value: false,
Valid: true,
}); err != nil {
return domain.Server{}, err
}
res, err := svc.repo.List(ctx, params)
if err != nil {
return domain.Server{}, err
}
servers := res.Servers()
if len(servers) == 0 {
return domain.Server{}, domain.ServerNotFoundError{
Key: key,
}
}
return servers[0], nil
}

View File

@ -62,8 +62,12 @@ func NewAPIHTTPHandler(
r.MethodNotAllowed(h.handleMethodNotAllowed)
return apimodel.HandlerWithOptions(h, apimodel.ChiServerOptions{
BaseRouter: r,
Middlewares: []apimodel.MiddlewareFunc{middleware.NoCache},
BaseRouter: r,
Middlewares: []apimodel.MiddlewareFunc{
middleware.NoCache,
h.versionMiddleware,
h.serverMiddleware,
},
ErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
apiErrorRenderer{errors: []error{err}}.render(w, r)
},

View File

@ -1,10 +1,13 @@
package port
import (
"context"
"net/http"
"slices"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"github.com/go-chi/chi/v5"
)
func (h *apiHTTPHandler) ListServers(
@ -58,6 +61,53 @@ func (h *apiHTTPHandler) ListServers(
renderJSON(w, r, http.StatusOK, apimodel.NewListServersResponse(res))
}
func (h *apiHTTPHandler) GetServer(
w http.ResponseWriter,
r *http.Request,
_ apimodel.VersionCodePathParam,
_ apimodel.ServerKeyPathParam,
) {
server, _ := serverFromContext(r.Context())
renderJSON(w, r, http.StatusOK, apimodel.NewGetServerResponse(server))
}
func (h *apiHTTPHandler) serverMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
routeCtx := chi.RouteContext(ctx)
version, versionOK := versionFromContext(ctx)
serverKeyIdx := slices.Index(routeCtx.URLParams.Keys, "serverKey")
if !versionOK || serverKeyIdx < 0 {
next.ServeHTTP(w, r)
return
}
server, err := h.serverSvc.GetNormalByVersionCodeAndServerKey(
ctx,
version.Code(),
routeCtx.URLParams.Values[serverKeyIdx],
)
if err != nil {
apiErrorRenderer{errors: []error{err}}.render(w, r)
return
}
next.ServeHTTP(w, r.WithContext(serverToContext(ctx, server)))
})
}
type serverCtxKey struct{}
func serverToContext(ctx context.Context, s domain.Server) context.Context {
return context.WithValue(ctx, serverCtxKey{}, s)
}
func serverFromContext(ctx context.Context) (domain.Server, bool) {
s, ok := ctx.Value(serverCtxKey{}).(domain.Server)
return s, ok
}
func formatListServersParamsErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListServersParams" {
return nil

View File

@ -1,10 +1,13 @@
package port
import (
"context"
"net/http"
"slices"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
"github.com/go-chi/chi/v5"
)
func (h *apiHTTPHandler) ListVersions(w http.ResponseWriter, r *http.Request, params apimodel.ListVersionsParams) {
@ -33,16 +36,43 @@ 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
}
func (h *apiHTTPHandler) GetVersion(w http.ResponseWriter, r *http.Request, _ apimodel.VersionCodePathParam) {
version, _ := versionFromContext(r.Context())
renderJSON(w, r, http.StatusOK, apimodel.NewGetVersionResponse(version))
}
func (h *apiHTTPHandler) versionMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
routeCtx := chi.RouteContext(ctx)
idx := slices.Index(routeCtx.URLParams.Keys, "versionCode")
if idx < 0 {
next.ServeHTTP(w, r)
return
}
version, err := h.versionSvc.Get(ctx, routeCtx.URLParams.Values[idx])
if err != nil {
apiErrorRenderer{errors: []error{err}}.render(w, r)
return
}
next.ServeHTTP(w, r.WithContext(versionToContext(ctx, version)))
})
}
type versionCtxKey struct{}
func versionToContext(ctx context.Context, v domain.Version) context.Context {
return context.WithValue(ctx, versionCtxKey{}, v)
}
func versionFromContext(ctx context.Context) (domain.Version, bool) {
v, ok := ctx.Value(versionCtxKey{}).(domain.Version)
return v, ok
}
func formatListVersionsParamsErrorPath(segments []errorPathSegment) []string {
if segments[0].model != "ListVersionsParams" {
return nil

View File

@ -0,0 +1,3 @@
package apimodel
//go:generate oapi-codegen --config=config.yml ../../../../api/openapi3.yml

View File

@ -54,3 +54,9 @@ func NewListServersResponse(res domain.ListServersResult) ListServersResponse {
return resp
}
func NewGetServerResponse(v domain.Server) GetServerResponse {
return GetServerResponse{
Data: NewServer(v),
}
}

View File

@ -2,8 +2,6 @@ package apimodel
import "gitea.dwysokinski.me/twhelp/corev3/internal/domain"
//go:generate oapi-codegen --config=config.yml ../../../../api/openapi3.yml
func NewVersion(v domain.Version) Version {
return Version{
Code: v.Code(),