feat: add a new endpoint - GET /api/v1/versions/:code/servers #47

Merged
Kichiyaki merged 13 commits from feat/new-endpoint-list-servers into master 2022-08-26 14:39:40 +00:00
5 changed files with 116 additions and 21 deletions
Showing only changes of commit b92f6dfee1 - Show all commits

View File

@ -16,10 +16,10 @@ type Server struct {
Config ServerConfig `json:"config"`
BuildingInfo BuildingInfo `json:"buildingInfo"`
UnitInfo UnitInfo `json:"unitInfo"`
CreatedAt time.Time `json:"createdAt"`
PlayerDataUpdatedAt NullTime `json:"playerDataUpdatedAt"`
TribeDataUpdatedAt NullTime `json:"tribeDataUpdatedAt"`
VillageDataUpdatedAt NullTime `json:"villageDataUpdatedAt"`
CreatedAt time.Time `json:"createdAt" format:"date-time"`
PlayerDataUpdatedAt NullTime `json:"playerDataUpdatedAt" swaggertype:"string" format:"date-time" extensions:"x-nullable"`
TribeDataUpdatedAt NullTime `json:"tribeDataUpdatedAt" swaggertype:"string" format:"date-time" extensions:"x-nullable"`
VillageDataUpdatedAt NullTime `json:"villageDataUpdatedAt" swaggertype:"string" format:"date-time" extensions:"x-nullable"`
} // @name Server
func NewServer(s domain.Server) Server {
@ -48,3 +48,17 @@ func NewServer(s domain.Server) Server {
},
}
}
type ListServersResp struct {
Data []Server `json:"data"`
} // @name ListServersResp
func NewListServersResp(servers []domain.Server) ListServersResp {
resp := ListServersResp{
Data: make([]Server, 0, len(servers)),
}
for _, srv := range servers {
resp.Data = append(resp.Data, NewServer(srv))
}
return resp
}

View File

@ -33,6 +33,52 @@ func TestNewServer(t *testing.T) {
assertServer(t, srv, model.NewServer(srv))
}
func TestNewListServersResp(t *testing.T) {
t.Parallel()
servers := []domain.Server{
{
Key: "pl151",
URL: "https://pl151.plemiona.pl",
Open: true,
Special: false,
NumPlayers: 1234,
NumTribes: 1235,
NumVillages: 1236,
Config: domain.ServerConfig{},
BuildingInfo: domain.BuildingInfo{},
UnitInfo: domain.UnitInfo{},
CreatedAt: time.Now().Add(-20 * time.Hour),
PlayerDataUpdatedAt: time.Time{},
TribeDataUpdatedAt: time.Now(),
VillageDataUpdatedAt: time.Now().Add(-5 * time.Hour),
VersionCode: "pl",
},
{
Key: "pl143",
URL: "https://pl143.plemiona.pl",
Open: false,
Special: false,
NumPlayers: 2234,
NumTribes: 2235,
NumVillages: 2236,
Config: domain.ServerConfig{},
BuildingInfo: domain.BuildingInfo{},
UnitInfo: domain.UnitInfo{},
CreatedAt: time.Now().Add(-40 * time.Hour),
PlayerDataUpdatedAt: time.Now().Add(-1 * time.Second),
TribeDataUpdatedAt: time.Now().Add(-5 * time.Second),
VillageDataUpdatedAt: time.Now(),
VersionCode: "pl",
},
}
resp := model.NewListServersResp(servers)
assert.Len(t, resp.Data, len(servers))
for i, srv := range resp.Data {
assertServer(t, servers[i], srv)
}
}
func assertServer(tb testing.TB, dsrv domain.Server, rsrv model.Server) {
tb.Helper()

View File

@ -11,7 +11,7 @@ type Unit struct {
DefenseCavalry int16 `json:"defenseCavalry"`
DefenseArcher int16 `json:"defenseArcher"`
Carry int16 `json:"carry"`
}
} // @name Unit
type UnitInfo struct {
Spear Unit `json:"spear"`

View File

@ -47,7 +47,7 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
versionHandler := &version{
svc: cfg.VersionService,
}
serverHandler := &Server{
serverHandler := &server{
svc: cfg.ServerService,
}
@ -71,9 +71,10 @@ func NewRouter(cfg RouterConfig) *chi.Mux {
r.Get("/", versionHandler.list)
r.Route("/{versionCode}", func(r chi.Router) {
r.Get("/", versionHandler.getByCode)
r.Route("/servers", func(r chi.Router) {
r.Get("/", serverHandler.list)
})
r.With(verifyVersionCode(cfg.VersionService)).
Route("/servers", func(r chi.Router) {
r.Get("/", serverHandler.list)
})
})
})
})
@ -103,6 +104,18 @@ func methodNotAllowedHandler(w http.ResponseWriter, _ *http.Request) {
})
}
func verifyVersionCode(versionSvc VersionService) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if _, err := versionSvc.GetByCode(r.Context(), chi.URLParam(r, "versionCode")); err != nil {
renderErr(w, err)
return
}
next.ServeHTTP(w, r)
})
}
}
func renderErr(w http.ResponseWriter, err error) {
var convError domain.Error
if !errors.As(err, &convError) {

View File

@ -4,8 +4,11 @@ import (
"context"
"net/http"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
"gitea.dwysokinski.me/twhelp/core/internal/rest/internal/model"
"github.com/go-chi/chi/v5"
"gitea.dwysokinski.me/twhelp/core/internal/domain"
)
//counterfeiter:generate -o internal/mock/server_service.gen.go . ServerService
@ -13,18 +16,37 @@ type ServerService interface {
List(ctx context.Context, params domain.ListServersParams) ([]domain.Server, int64, error)
}
type Server struct {
type server struct {
svc ServerService
}
func NewServer(svc ServerService) *Server {
return &Server{svc: svc}
}
func (s *Server) Register(r chi.Router) {
r.Get("/api/v1/versions/{versionCode}/servers", s.list)
}
func (s *Server) list(w http.ResponseWriter, r *http.Request) {
// @ID listServers
// @Summary List servers
// @Description List all servers
// @Tags versions,servers
// @Produce json
// @Success 200 {object} model.ListServersResp
// @Success 404 {object} model.ErrorResp
// @Failure 500 {object} model.ErrorResp
// @Header 200 {integer} X-Total-Count "Total number of records"
// @Param versionCode path string true "Version code"
// @Router /versions/{versionCode}/servers [get]
func (s *server) list(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// TODO: add pagination / filters
servers, count, err := s.svc.List(ctx, domain.ListServersParams{
Special: domain.NullBool{
Valid: true,
Bool: false,
},
Open: domain.NullBool{},
VersionCodes: []string{chi.URLParamFromCtx(ctx, "versionCode")},
Count: true,
})
if err != nil {
renderErr(w, err)
return
}
setTotalCountHeader(w.Header(), count)
renderJSON(w, http.StatusOK, model.NewListServersResp(servers))
}