Skip to content

Commit

Permalink
feat: split world and game #1
Browse files Browse the repository at this point in the history
  • Loading branch information
SomethingSexy committed Oct 13, 2024
1 parent 492384a commit bbe23c1
Show file tree
Hide file tree
Showing 29 changed files with 443 additions and 455 deletions.
40 changes: 22 additions & 18 deletions internal/chronicle/adapter/http/game/game_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,31 @@ import (
"errors"
"net/http"

"github.com/SomethingSexy/chronicle/internal/chronicle/adapter/http/world"
"github.com/SomethingSexy/chronicle/internal/chronicle/core/domain"
"github.com/google/uuid"
)

func NewGameRequest(g domain.Game) GameRequest {
worlds := make([]*WorldRequest, len(g.Worlds))
for x, world := range g.Worlds {
worldRquest := NewWorldRequest(world)
worlds[x] = &worldRquest
}
worldRquest := world.NewWorldRequest(g.World)

return GameRequest{
ID: g.GameId.String(),
GameId: g.GameId.String(),
Name: g.Name,
Type: g.Type.String(),
Worlds: worlds,
ID: g.GameId.String(),
GameId: g.GameId.String(),
WorldId: g.WorldId.String(),
Name: g.Name,
Type: g.Type.String(),
World: &worldRquest,
}
}

type GameRequest struct {
ID string `jsonapi:"primary,games"`
GameId string `jsonapi:"attr,gameId"`
Name string `jsonapi:"attr,name"`
Type string `jsonapi:"attr,type"`
Worlds []*WorldRequest `jsonapi:"relation,worlds"`
ID string `jsonapi:"primary,games"`
GameId string `jsonapi:"attr,gameId"`
WorldId string `jsonapi:"attr,worldId"`
Name string `jsonapi:"attr,name"`
Type string `jsonapi:"attr,type"`
World *world.WorldRequest `jsonapi:"relation,worlds"`
}

func (a *GameRequest) Bind(r *http.Request) error {
Expand All @@ -45,13 +44,18 @@ func (a *GameRequest) Bind(r *http.Request) error {
return errors.New("gameId must be valid UUID")
}

if _, err := uuid.Parse(a.WorldId); err != nil {
return errors.New("worldId must be valid UUID")
}

return nil
}

func (a *GameRequest) ToDomain() domain.Game {
return domain.Game{
GameId: uuid.MustParse(a.GameId),
Name: a.Name,
Type: domain.NewGameType(a.Type),
GameId: uuid.MustParse(a.GameId),
WorldId: uuid.MustParse(a.WorldId),
Name: a.Name,
Type: domain.NewGameType(a.Type),
}
}
126 changes: 3 additions & 123 deletions internal/chronicle/adapter/http/game/server.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package game

import (
"log"
"net/http"

corePort "github.com/SomethingSexy/chronicle/internal/chronicle/core/port"
Expand Down Expand Up @@ -30,22 +31,6 @@ func (h GameHttpServer) Routes() chi.Router {
r.Get("/", h.ListGames)
r.Get("/{gameId}", h.GetGame)

// TODO: This is obviously going to get huge
// we need to decide how to organize these route handlers
// Either at this level or a higher level to apply
// relationships to root routes.
r.Post("/{gameId}/worlds", h.CreateWorld)
r.Get("/{gameId}/worlds/{worldId}", h.GetWorld)

// TODO: This should probably be relationships?
r.Post("/{gameId}/worlds/{worldId}/locations", h.CreateLocation)
r.Get("/{gameId}/worlds/{worldId}/locations", h.GetLocations)

r.Post("/{gameId}/worlds/{worldId}/relationships/characters", h.AddWorldCharacter)
// Using this format right now for patching a character that has been linked to a world
// This might not be correct and instead it could include "world-characters"
r.Patch("/{gameId}/worlds/{worldId}/characters/{characterId}", h.AddWorldCharacter)

return r
}

Expand Down Expand Up @@ -99,7 +84,8 @@ func (h GameHttpServer) GetGame(w http.ResponseWriter, r *http.Request) {
return
}

gameRequest := NewGameRequest((game))
log.Println(game)
gameRequest := NewGameRequest(game)

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
Expand All @@ -108,109 +94,3 @@ func (h GameHttpServer) GetGame(w http.ResponseWriter, r *http.Request) {
return
}
}

func (h GameHttpServer) CreateWorld(w http.ResponseWriter, r *http.Request) {
data := &WorldRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.CreateWorld.Handle(r.Context(), corePort.CreateWorld{
World: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}

func (h GameHttpServer) GetWorld(w http.ResponseWriter, r *http.Request) {
gameId := chi.URLParam(r, "gameId")
worldId := chi.URLParam(r, "worldId")

world, err := h.queries.GetWorld.Handle(r.Context(), corePort.GetWorldQuery{
// TODO: BAD check for error
GameId: uuid.MustParse(gameId),
WorldId: uuid.MustParse(worldId),
})
if err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

worldRquest := NewWorldRequest(world)

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapi.MarshalPayload(w, &worldRquest); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}
}

func (h GameHttpServer) CreateLocation(w http.ResponseWriter, r *http.Request) {
data := &LocationRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.CreateLocation.Handle(r.Context(), corePort.CreateLocation{
Location: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}

func (h GameHttpServer) GetLocations(w http.ResponseWriter, r *http.Request) {
gameId := chi.URLParam(r, "gameId")
worldId := chi.URLParam(r, "worldId")

locations, err := h.queries.ListLocations.Handle(r.Context(), corePort.LocationsQuery{
// TODO: BAD check for error
GameId: uuid.MustParse(gameId),
WorldId: uuid.MustParse(worldId),
})
if err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

responses := make([]*LocationRequest, len(locations))
for i, location := range locations {
locationRequest := NewLocationRequest(location)
responses[i] = &locationRequest
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapi.MarshalPayload(w, responses); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}
}

func (h GameHttpServer) AddWorldCharacter(w http.ResponseWriter, r *http.Request) {
worldId := chi.URLParam(r, "worldId")
data := &AddWorldCharacterRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.AddWorldCharacter.Handle(r.Context(), corePort.AddWorldCharacter{
// TODO: Bad check for error
WorldId: uuid.MustParse(worldId),
CharacterId: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}
1 change: 1 addition & 0 deletions internal/chronicle/adapter/http/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ func (h HttpServer) Start() {
// TODO: Given the application, this should mount all of the route handlers
r.Mount("/games", h.app.Routes()["Games"][0])
r.Mount("/characters", h.app.Routes()["Characters"][0])
r.Mount("/worlds", h.app.Routes()["Worlds"][0])

http.ListenAndServe(":3000", r)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package game
package world

import (
"errors"
Expand Down
147 changes: 147 additions & 0 deletions internal/chronicle/adapter/http/world/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package world

import (
"net/http"

corePort "github.com/SomethingSexy/chronicle/internal/chronicle/core/port"
"github.com/SomethingSexy/chronicle/internal/chronicle/port"
"github.com/SomethingSexy/chronicle/internal/common"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
"github.com/google/jsonapi"
"github.com/google/uuid"
)

func NewWorldHttpServer(commands port.WorldCommands, queries port.WorldQueries) GameHttpServer {
return GameHttpServer{
commands: commands,
queries: queries,
}
}

type GameHttpServer struct {
commands port.WorldCommands
queries port.WorldQueries
}

func (h GameHttpServer) Routes() chi.Router {
r := chi.NewRouter()

// TODO: This is obviously going to get huge
// we need to decide how to organize these route handlers
// Either at this level or a higher level to apply
// relationships to root routes.
r.Post("/", h.CreateWorld)
r.Get("/{worldId}", h.GetWorld)

// TODO: This should probably be relationships?
r.Post("/{worldId}/locations", h.CreateLocation)
r.Get("/{worldId}/locations", h.GetLocations)

r.Post("/{worldId}/relationships/characters", h.AddWorldCharacter)
// Using this format right now for patching a character that has been linked to a world
// This might not be correct and instead it could include "world-characters"
r.Patch("/{worldId}/characters/{characterId}", h.AddWorldCharacter)

return r
}

func (h GameHttpServer) CreateWorld(w http.ResponseWriter, r *http.Request) {
data := &WorldRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.CreateWorld.Handle(r.Context(), corePort.CreateWorld{
World: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}

func (h GameHttpServer) GetWorld(w http.ResponseWriter, r *http.Request) {
worldId := chi.URLParam(r, "worldId")

world, err := h.queries.GetWorld.Handle(r.Context(), corePort.GetWorldQuery{
WorldId: uuid.MustParse(worldId),
})
if err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

worldRquest := NewWorldRequest(world)

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapi.MarshalPayload(w, &worldRquest); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}
}

func (h GameHttpServer) CreateLocation(w http.ResponseWriter, r *http.Request) {
data := &LocationRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.CreateLocation.Handle(r.Context(), corePort.CreateLocation{
Location: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}

func (h GameHttpServer) GetLocations(w http.ResponseWriter, r *http.Request) {
worldId := chi.URLParam(r, "worldId")

locations, err := h.queries.ListLocations.Handle(r.Context(), corePort.LocationsQuery{
WorldId: uuid.MustParse(worldId),
})
if err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

responses := make([]*LocationRequest, len(locations))
for i, location := range locations {
locationRequest := NewLocationRequest(location)
responses[i] = &locationRequest
}

w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapi.MarshalPayload(w, responses); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}
}

func (h GameHttpServer) AddWorldCharacter(w http.ResponseWriter, r *http.Request) {
worldId := chi.URLParam(r, "worldId")
data := &AddWorldCharacterRequest{}
if err := render.Bind(r, data); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

if err := h.commands.AddWorldCharacter.Handle(r.Context(), corePort.AddWorldCharacter{
// TODO: Bad check for error
WorldId: uuid.MustParse(worldId),
CharacterId: data.ToDomain(),
}); err != nil {
render.Render(w, r, common.ErrInvalidRequest(err))
return
}

render.Status(r, http.StatusCreated)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package game
package world

import (
"errors"
Expand Down
Loading

0 comments on commit bbe23c1

Please sign in to comment.