diff --git a/docs/openapi/v2.yaml b/docs/openapi/v2.yaml
index 6fee7136..715ccd6d 100644
--- a/docs/openapi/v2.yaml
+++ b/docs/openapi/v2.yaml
@@ -1565,7 +1565,7 @@ paths:
         - edition
       security:
         - AdminAuth: []
-      operationId: postEditionGame
+      operationId: patchEditionGame
       requestBody:
         content:
           application/json:
diff --git a/go.mod b/go.mod
index 2c16ffed..eb3de6e9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,14 +1,19 @@
 module github.com/traPtitech/trap-collection-server
 
-go 1.24
+go 1.24.0
 
 require (
 	github.com/aws/aws-sdk-go-v2 v1.36.3
+	github.com/aws/aws-sdk-go-v2/config v1.29.9
 	github.com/aws/aws-sdk-go-v2/credentials v1.17.62
-	github.com/cosmtrek/air v1.52.1
+	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.66
+	github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2
+	github.com/cosmtrek/air v1.61.2
 	github.com/deepmap/oapi-codegen v1.16.3
 	github.com/dgraph-io/ristretto v0.2.0
 	github.com/getkin/kin-openapi v0.131.0
+	github.com/go-gormigrate/gormigrate/v2 v2.1.3
+	github.com/go-sql-driver/mysql v1.9.1
 	github.com/go-task/task/v3 v3.42.1
 	github.com/google/uuid v1.6.0
 	github.com/google/wire v0.6.0
@@ -16,18 +21,21 @@ require (
 	github.com/h2non/filetype v1.1.3
 	github.com/labstack/echo-contrib v0.17.2
 	github.com/labstack/echo/v4 v4.13.3
+	github.com/labstack/gommon v0.4.2
 	github.com/mazrean/formstream v1.1.2
 	github.com/ncw/swift/v2 v2.0.3
 	github.com/oapi-codegen/echo-middleware v1.0.2
 	github.com/oapi-codegen/oapi-codegen/v2 v2.4.1
 	github.com/oapi-codegen/runtime v1.1.1
 	github.com/ory/dockertest/v3 v3.11.0
+	github.com/prometheus/client_golang v1.21.1
 	github.com/stretchr/testify v1.10.0
 	go.uber.org/mock v0.5.0
 	golang.org/x/mod v0.24.0
 	golang.org/x/sync v0.12.0
 	gorm.io/driver/mysql v1.5.7
 	gorm.io/gorm v1.25.12
+	gorm.io/plugin/prometheus v0.1.0
 )
 
 require (
@@ -55,15 +63,18 @@ require (
 	github.com/aws/aws-sdk-go-v2/service/ssooidc v1.29.1 // indirect
 	github.com/aws/aws-sdk-go-v2/service/sts v1.33.17 // indirect
 	github.com/aws/smithy-go v1.22.2 // indirect
+	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bep/godartsass/v2 v2.3.2 // indirect
 	github.com/bep/golibsass v1.2.0 // indirect
 	github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/chainguard-dev/git-urls v1.0.2 // indirect
 	github.com/cli/safeexec v1.0.1 // indirect
 	github.com/cloudflare/circl v1.6.0 // indirect
 	github.com/containerd/continuity v0.4.3 // indirect
 	github.com/creack/pty v1.1.24 // indirect
 	github.com/cyphar/filepath-securejoin v0.4.1 // indirect
+	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/dlclark/regexp2 v1.11.4 // indirect
 	github.com/docker/cli v26.1.4+incompatible // indirect
 	github.com/docker/docker v27.1.1+incompatible // indirect
@@ -71,6 +82,7 @@ require (
 	github.com/docker/go-units v0.5.0 // indirect
 	github.com/dominikbraun/graph v0.23.0 // indirect
 	github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
+	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/elliotchance/orderedmap/v3 v3.1.0 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/fatih/color v1.18.0 // indirect
@@ -87,14 +99,21 @@ require (
 	github.com/gohugoio/hugo v0.139.4 // indirect
 	github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
+	github.com/google/subcommands v1.2.0 // indirect
+	github.com/gorilla/context v1.1.2 // indirect
 	github.com/gorilla/mux v1.8.1 // indirect
+	github.com/gorilla/securecookie v1.1.2 // indirect
 	github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
+	github.com/jinzhu/inflection v1.0.0 // indirect
+	github.com/jinzhu/now v1.1.5 // indirect
 	github.com/joho/godotenv v1.5.1 // indirect
 	github.com/josharian/intern v1.0.0 // indirect
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
 	github.com/klauspost/compress v1.17.11 // indirect
 	github.com/klauspost/cpuid/v2 v2.2.7 // indirect
 	github.com/mailru/easyjson v0.7.7 // indirect
+	github.com/mattn/go-colorable v0.1.13 // indirect
+	github.com/mattn/go-isatty v0.0.20 // indirect
 	github.com/mattn/go-zglob v0.0.6 // indirect
 	github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
 	github.com/mitchellh/mapstructure v1.5.1-0.20231216201459-8508981c8b6c // indirect
@@ -106,11 +125,16 @@ require (
 	github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.0 // indirect
-	github.com/opencontainers/runc v1.1.14 // indirect
+	github.com/opencontainers/runc v1.1.13 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/perimeterx/marshmallow v1.1.5 // indirect
 	github.com/pjbgf/sha1cd v0.3.2 // indirect
+	github.com/pkg/errors v0.9.1 // indirect
+	github.com/pmezard/go-difflib v1.0.0 // indirect
+	github.com/prometheus/client_model v0.6.1 // indirect
+	github.com/prometheus/common v0.62.0 // indirect
+	github.com/prometheus/procfs v0.15.1 // indirect
 	github.com/radovskyb/watcher v1.0.7 // indirect
 	github.com/sajari/fuzzy v1.0.0 // indirect
 	github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
@@ -121,6 +145,8 @@ require (
 	github.com/spf13/cast v1.7.0 // indirect
 	github.com/spf13/pflag v1.0.6 // indirect
 	github.com/tdewolff/parse/v2 v2.7.15 // indirect
+	github.com/valyala/bytebufferpool v1.0.0 // indirect
+	github.com/valyala/fasttemplate v1.2.2 // indirect
 	github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
 	github.com/xanzy/ssh-agent v0.3.3 // indirect
 	github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
@@ -134,31 +160,6 @@ require (
 )
 
 require (
-	github.com/aws/aws-sdk-go-v2/config v1.29.9
-	github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.66
-	github.com/aws/aws-sdk-go-v2/service/s3 v1.78.2
-	github.com/beorn7/perks v1.0.1 // indirect
-	github.com/cespare/xxhash/v2 v2.3.0 // indirect
-	github.com/davecgh/go-spew v1.1.1 // indirect
-	github.com/dustin/go-humanize v1.0.1 // indirect
-	github.com/go-gormigrate/gormigrate/v2 v2.1.3
-	github.com/go-sql-driver/mysql v1.9.1
-	github.com/google/subcommands v1.2.0 // indirect
-	github.com/gorilla/context v1.1.2 // indirect
-	github.com/gorilla/securecookie v1.1.2 // indirect
-	github.com/jinzhu/inflection v1.0.0 // indirect
-	github.com/jinzhu/now v1.1.5 // indirect
-	github.com/labstack/gommon v0.4.2
-	github.com/mattn/go-colorable v0.1.13 // indirect
-	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/pkg/errors v0.9.1 // indirect
-	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/prometheus/client_golang v1.21.1
-	github.com/prometheus/client_model v0.6.1 // indirect
-	github.com/prometheus/common v0.62.0 // indirect
-	github.com/prometheus/procfs v0.15.1 // indirect
-	github.com/valyala/bytebufferpool v1.0.0 // indirect
-	github.com/valyala/fasttemplate v1.2.2 // indirect
 	golang.org/x/crypto v0.35.0 // indirect
 	golang.org/x/net v0.36.0 // indirect
 	golang.org/x/sys v0.31.0 // indirect
@@ -167,7 +168,6 @@ require (
 	golang.org/x/tools v0.27.0 // indirect
 	google.golang.org/protobuf v1.36.1 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	gorm.io/plugin/prometheus v0.1.0
 )
 
 tool go.uber.org/mock/mockgen
diff --git a/go.sum b/go.sum
index 368d1a96..b4c292d7 100644
--- a/go.sum
+++ b/go.sum
@@ -166,8 +166,8 @@ github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZ
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8=
 github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
-github.com/cosmtrek/air v1.52.1 h1:R+BiGX9tWJ36ENM0ZroaRkagKgIlCmy+8IGTvMyoDV4=
-github.com/cosmtrek/air v1.52.1/go.mod h1:xILtq8JGIYwe++r/ib4PdhubiuKBmE1vutC49E+5A78=
+github.com/cosmtrek/air v1.61.2 h1:F0IkTrmb5Uf0LVfroPKE4xVV9NeoEkuvks3X83B5Hqo=
+github.com/cosmtrek/air v1.61.2/go.mod h1:yOz9vy7edZ75KRN9+Ofqwm3OU0wuv4Csc+ikMeZxxS8=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
@@ -514,8 +514,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
 github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
 github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
-github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w=
-github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA=
+github.com/opencontainers/runc v1.1.13 h1:98S2srgG9vw0zWcDpFMn5TRrh8kLxa/5OFUstuUhmRs=
+github.com/opencontainers/runc v1.1.13/go.mod h1:R016aXacfp/gwQBYw2FDGa9m+n6atbLWrYY8hNMT/sA=
 github.com/ory/dockertest/v3 v3.11.0 h1:OiHcxKAvSDUwsEVh2BjxQQc/5EHz9n0va9awCtNGuyA=
 github.com/ory/dockertest/v3 v3.11.0/go.mod h1:VIPxS1gwT9NpPOrfD3rACs8Y9Z7yhzO4SB194iUDnUI=
 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
@@ -624,9 +624,8 @@ github.com/tdewolff/minify/v2 v2.20.37 h1:Q97cx4STXCh1dlWDlNHZniE8BJ2EBL0+2b0n92
 github.com/tdewolff/minify/v2 v2.20.37/go.mod h1:L1VYef/jwKw6Wwyk5A+T0mBjjn3mMPgmjjA688RNsxU=
 github.com/tdewolff/parse/v2 v2.7.15 h1:hysDXtdGZIRF5UZXwpfn3ZWRbm+ru4l53/ajBRGpCTw=
 github.com/tdewolff/parse/v2 v2.7.15/go.mod h1:3FbJWZp3XT9OWVN3Hmfp0p/a08v4h8J9W1aghka0soA=
+github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52 h1:gAQliwn+zJrkjAHVcBEYW/RFvd2St4yYimisvozAYlA=
 github.com/tdewolff/test v1.0.11-0.20231101010635-f1265d231d52/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
-github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739 h1:IkjBCtQOOjIn03u/dMQK9g+Iw9ewps4mCl1nB8Sscbo=
-github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
 github.com/tetratelabs/wazero v1.8.2 h1:yIgLR/b2bN31bjxwXHD8a3d+BogigR952csSDdLYEv4=
 github.com/tetratelabs/wazero v1.8.2/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs=
 github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
diff --git a/src/handler/v2/edition.go b/src/handler/v2/edition.go
index 76f245be..188273e5 100644
--- a/src/handler/v2/edition.go
+++ b/src/handler/v2/edition.go
@@ -299,7 +299,7 @@ func (edition *Edition) GetEditionGames(ctx echo.Context, editionID openapi.Edit
 
 // エディションのゲームの変更
 // (PATCH /editions/{editionID}/games)
-func (edition *Edition) PostEditionGame(c echo.Context, editionID openapi.EditionIDInPath) error {
+func (edition *Edition) PatchEditionGame(c echo.Context, editionID openapi.EditionIDInPath) error {
 	var req openapi.PatchEditionGameRequest
 	err := c.Bind(&req)
 	if err != nil {
diff --git a/src/handler/v2/edition_test.go b/src/handler/v2/edition_test.go
new file mode 100644
index 00000000..4ef49c90
--- /dev/null
+++ b/src/handler/v2/edition_test.go
@@ -0,0 +1,1820 @@
+package v2
+
+import (
+	"bytes"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"net/url"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/traPtitech/trap-collection-server/pkg/types"
+	"go.uber.org/mock/gomock"
+
+	"github.com/google/uuid"
+	"github.com/labstack/echo/v4"
+	"github.com/stretchr/testify/assert"
+	"github.com/traPtitech/trap-collection-server/src/domain"
+	"github.com/traPtitech/trap-collection-server/src/domain/values"
+	"github.com/traPtitech/trap-collection-server/src/handler/v2/openapi"
+	"github.com/traPtitech/trap-collection-server/src/service"
+	"github.com/traPtitech/trap-collection-server/src/service/mock"
+)
+
+func TestGetEditions(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description    string
+		editions       []*domain.LauncherVersion
+		getEditionsErr error
+		expectEditions []openapi.Edition
+		isErr          bool
+		statusCode     int
+	}
+
+	now := time.Now()
+	editionID1 := values.NewLauncherVersionIDFromUUID(uuid.New())
+	editionID2 := values.NewLauncherVersionIDFromUUID(uuid.New())
+	editionName1 := values.NewLauncherVersionName("テストエディション")
+	editionName2 := values.NewLauncherVersionName("テストエディション2")
+	strURL := "https://example.com/questionnaire"
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+
+	testCases := []test{
+		{
+			description: "特に問題ないのでエラーなし",
+			editions: []*domain.LauncherVersion{
+				domain.NewLauncherVersionWithQuestionnaire(
+					editionID1,
+					editionName1,
+					values.NewLauncherVersionQuestionnaireURL(questionnaireURL),
+					now,
+				),
+			},
+			expectEditions: []openapi.Edition{
+				{
+					Id:            uuid.UUID(editionID1),
+					Name:          string(editionName1),
+					Questionnaire: &strURL,
+					CreatedAt:     now,
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "アンケートURLが無くてもエラーなし",
+			editions: []*domain.LauncherVersion{
+				domain.NewLauncherVersionWithoutQuestionnaire(
+					editionID1,
+					editionName1,
+					now,
+				),
+			},
+			expectEditions: []openapi.Edition{
+				{
+					Id:            uuid.UUID(editionID1),
+					Name:          string(editionName1),
+					Questionnaire: nil,
+					CreatedAt:     now,
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description:    "GetEditionsがエラーなので500",
+			getEditionsErr: errors.New("error"),
+			isErr:          true,
+			statusCode:     http.StatusInternalServerError,
+		},
+		{
+			description: "複数エディションでもエラーなし",
+			editions: []*domain.LauncherVersion{
+				domain.NewLauncherVersionWithQuestionnaire(
+					editionID1,
+					editionName1,
+					values.NewLauncherVersionQuestionnaireURL(questionnaireURL),
+					now,
+				),
+				domain.NewLauncherVersionWithoutQuestionnaire(
+					editionID2,
+					editionName2,
+					now,
+				),
+			},
+			expectEditions: []openapi.Edition{
+				{
+					Id:            uuid.UUID(editionID1),
+					Name:          string(editionName1),
+					Questionnaire: &strURL,
+					CreatedAt:     now,
+				},
+				{
+					Id:            uuid.UUID(editionID2),
+					Name:          string(editionName2),
+					Questionnaire: nil,
+					CreatedAt:     now,
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "エディションが存在しなくてもでもエラーなし",
+			editions:    []*domain.LauncherVersion{},
+			statusCode:  http.StatusOK,
+		},
+	}
+
+	for _, testCase := range testCases {
+		testCase := testCase
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodGet, "/api/v2/editions", nil)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			mockEditionService.
+				EXPECT().
+				GetEditions(gomock.Any()).
+				Return(testCase.editions, testCase.getEditionsErr)
+
+			err := edition.GetEditions(c)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+			assert.NoError(t, err)
+			if err != nil || testCase.isErr {
+				return
+			}
+
+			assert.Equal(t, testCase.statusCode, rec.Code)
+
+			var res []openapi.Edition
+			err = json.NewDecoder(rec.Body).Decode(&res)
+			if err != nil {
+				t.Fatalf("failed to decode response body: %v", err)
+			}
+
+			assert.Len(t, res, len(testCase.expectEditions))
+			for i, ed := range res {
+				assert.Equal(t, testCase.expectEditions[i].Id, ed.Id)
+				assert.Equal(t, testCase.expectEditions[i].Name, ed.Name)
+				assert.Equal(t, testCase.expectEditions[i].Questionnaire, ed.Questionnaire)
+				assert.WithinDuration(t, testCase.expectEditions[i].CreatedAt, ed.CreatedAt, time.Second)
+			}
+		})
+	}
+}
+
+func TestPostEdition(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description          string
+		reqBody              *openapi.NewEdition
+		invalidBody          bool
+		executeCreateEdition bool
+		name                 values.LauncherVersionName
+		questionnaireURL     types.Option[values.LauncherVersionQuestionnaireURL]
+		gameVersionIDs       []values.GameVersionID
+		createEditionErr     error
+		resultEdition        *domain.LauncherVersion
+		isErr                bool
+		statusCode           int
+		expectEdition        *openapi.Edition
+	}
+
+	now := time.Now()
+	editionUUID := uuid.New()
+	editionID := values.NewLauncherVersionIDFromUUID(editionUUID)
+	editionName := "テストエディション"
+	strURL := "https://example.com/questionnaire"
+	invalidURL := " https://example.com/questionnaire with spaces"
+	longName := strings.Repeat("あ", 33)
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+	gameVersionUUID1 := uuid.New()
+	gameVersionUUID2 := uuid.New()
+
+	testCases := []test{
+		{
+			description: "特に問題ないのでエラーなし",
+			reqBody: &openapi.NewEdition{
+				Name:          editionName,
+				Questionnaire: &strURL,
+				GameVersions:  []uuid.UUID{gameVersionUUID1, gameVersionUUID2},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.NewOption(values.NewLauncherVersionQuestionnaireURL(questionnaireURL)),
+			gameVersionIDs: []values.GameVersionID{
+				values.NewGameVersionIDFromUUID(gameVersionUUID1),
+				values.NewGameVersionIDFromUUID(gameVersionUUID2),
+			},
+			resultEdition: domain.NewLauncherVersionWithQuestionnaire(
+				editionID,
+				values.NewLauncherVersionName(editionName),
+				values.NewLauncherVersionQuestionnaireURL(questionnaireURL),
+				now,
+			),
+			expectEdition: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          editionName,
+				Questionnaire: &strURL,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusCreated,
+		},
+		{
+			description: "アンケートURLがなくてもエラーなし",
+			reqBody: &openapi.NewEdition{
+				Name:         editionName,
+				GameVersions: []uuid.UUID{gameVersionUUID1},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.Option[values.LauncherVersionQuestionnaireURL]{},
+			gameVersionIDs:       []values.GameVersionID{values.NewGameVersionIDFromUUID(gameVersionUUID1)},
+			resultEdition: domain.NewLauncherVersionWithoutQuestionnaire(
+				editionID,
+				values.NewLauncherVersionName(editionName),
+				now,
+			),
+			expectEdition: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          editionName,
+				Questionnaire: nil,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusCreated,
+		},
+		{
+			description: "Edition名が空文字なので400",
+			reqBody: &openapi.NewEdition{
+				Name:         "",
+				GameVersions: []uuid.UUID{gameVersionUUID1},
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "Edition名が長すぎるので400",
+			reqBody: &openapi.NewEdition{
+				Name:         longName,
+				GameVersions: []uuid.UUID{gameVersionUUID1},
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "URLが正しくないので400",
+			reqBody: &openapi.NewEdition{
+				Name:          editionName,
+				Questionnaire: &invalidURL,
+				GameVersions:  []uuid.UUID{gameVersionUUID1},
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "ゲームバージョンが重複しているので400",
+			reqBody: &openapi.NewEdition{
+				Name:         editionName,
+				GameVersions: []uuid.UUID{gameVersionUUID1, gameVersionUUID1},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.Option[values.LauncherVersionQuestionnaireURL]{},
+			gameVersionIDs: []values.GameVersionID{
+				values.NewGameVersionIDFromUUID(gameVersionUUID1),
+				values.NewGameVersionIDFromUUID(gameVersionUUID1),
+			},
+			createEditionErr: service.ErrDuplicateGameVersion,
+			isErr:            true,
+			statusCode:       http.StatusBadRequest,
+		},
+		{
+			description: "ゲームが重複しているので400",
+			reqBody: &openapi.NewEdition{
+				Name:         editionName,
+				GameVersions: []uuid.UUID{gameVersionUUID1, gameVersionUUID2},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.Option[values.LauncherVersionQuestionnaireURL]{},
+			gameVersionIDs: []values.GameVersionID{
+				values.NewGameVersionIDFromUUID(gameVersionUUID1),
+				values.NewGameVersionIDFromUUID(gameVersionUUID2),
+			},
+			createEditionErr: service.ErrDuplicateGame,
+			isErr:            true,
+			statusCode:       http.StatusBadRequest,
+		},
+		{
+			description: "無効なゲームバージョンIDが含まれているので400",
+			reqBody: &openapi.NewEdition{
+				Name:         editionName,
+				GameVersions: []uuid.UUID{gameVersionUUID1},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.Option[values.LauncherVersionQuestionnaireURL]{},
+			gameVersionIDs:       []values.GameVersionID{values.NewGameVersionIDFromUUID(gameVersionUUID1)},
+			createEditionErr:     service.ErrInvalidGameVersionID,
+			isErr:                true,
+			statusCode:           http.StatusBadRequest,
+		},
+		{
+			description: "サービス層でエラーが発生したので500",
+			reqBody: &openapi.NewEdition{
+				Name:         editionName,
+				GameVersions: []uuid.UUID{gameVersionUUID1},
+			},
+			executeCreateEdition: true,
+			name:                 values.NewLauncherVersionName(editionName),
+			questionnaireURL:     types.Option[values.LauncherVersionQuestionnaireURL]{},
+			gameVersionIDs:       []values.GameVersionID{values.NewGameVersionIDFromUUID(gameVersionUUID1)},
+			createEditionErr:     errors.New("internal error"),
+			isErr:                true,
+			statusCode:           http.StatusInternalServerError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		testCase := testCase
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			e := echo.New()
+			var req *http.Request
+			if testCase.invalidBody {
+				reqBody := bytes.NewBuffer([]byte("invalid"))
+				req = httptest.NewRequest(http.MethodPost, "/api/v2/editions", reqBody)
+				req.Header.Set("Content-Type", echo.MIMETextPlain)
+			} else {
+				reqBody := bytes.NewBuffer(nil)
+				if err := json.NewEncoder(reqBody).Encode(testCase.reqBody); err != nil {
+					t.Fatalf("failed to encode request body: %v", err)
+				}
+				req = httptest.NewRequest(http.MethodPost, "/api/v2/editions", reqBody)
+				req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
+			}
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			if testCase.executeCreateEdition {
+				mockEditionService.
+					EXPECT().
+					CreateEdition(
+						gomock.Any(),
+						testCase.name,
+						testCase.questionnaireURL,
+						testCase.gameVersionIDs,
+					).
+					Return(testCase.resultEdition, testCase.createEditionErr)
+			}
+
+			err := edition.PostEdition(c)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if errors.As(err, &httpErr) {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					} else {
+						t.Errorf("error is not *echo.HTTPError")
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, testCase.statusCode, rec.Code)
+			t.Logf("テストケース: %s", testCase.description)
+			t.Logf("レスポンスコード: %d", rec.Code)
+
+			if testCase.expectEdition != nil {
+				var res openapi.Edition
+				if err := json.NewDecoder(rec.Body).Decode(&res); err != nil {
+					t.Fatalf("failed to decode response body: %v", err)
+				}
+
+				assert.Equal(t, testCase.expectEdition.Id, res.Id)
+				assert.Equal(t, testCase.expectEdition.Name, res.Name)
+				assert.Equal(t, testCase.expectEdition.Questionnaire, res.Questionnaire)
+				assert.WithinDuration(t, testCase.expectEdition.CreatedAt, res.CreatedAt, time.Second)
+			}
+		})
+	}
+}
+
+func TestDeleteEdition(t *testing.T) {
+	t.Parallel()
+
+	editionID := uuid.New()
+
+	type test struct {
+		description       string
+		editionID         openapi.EditionIDInPath
+		executeDeleteMock bool
+		launcherVersionID values.LauncherVersionID
+		deleteEditionErr  error
+		isErr             bool
+		statusCode        int
+	}
+
+	testCases := []test{
+		{
+			description:       "特に問題ないのでエラー無し",
+			editionID:         editionID,
+			executeDeleteMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionID),
+			statusCode:        http.StatusOK,
+		},
+		{
+			description:       "存在しないエディションIDなので400",
+			editionID:         editionID,
+			executeDeleteMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionID),
+			deleteEditionErr:  service.ErrInvalidEditionID,
+			isErr:             true,
+			statusCode:        http.StatusBadRequest,
+		},
+		{
+			description:       "DeleteEditionがエラーなので500",
+			editionID:         editionID,
+			executeDeleteMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionID),
+			deleteEditionErr:  errors.New("internal error"),
+			isErr:             true,
+			statusCode:        http.StatusInternalServerError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		testCase := testCase
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			if testCase.executeDeleteMock {
+				mockEditionService.
+					EXPECT().
+					DeleteEdition(gomock.Any(), testCase.launcherVersionID).
+					Return(testCase.deleteEditionErr)
+			}
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodDelete, fmt.Sprintf("/api/v2/editions/%s", testCase.editionID), nil)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			err := edition.DeleteEdition(c, testCase.editionID)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, http.StatusOK, rec.Code)
+		})
+	}
+}
+
+func TestGetEdition(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description   string
+		editionID     openapi.EditionIDInPath
+		resultEdition *domain.LauncherVersion
+		GetEditionErr error
+		expectEdition *openapi.Edition
+		isErr         bool
+		statusCode    int
+	}
+
+	now := time.Now()
+	editionUUID := uuid.New()
+	editionID := values.NewLauncherVersionIDFromUUID(editionUUID)
+	editionName := values.NewLauncherVersionName("テストエディション")
+	strURL := "https://example.com/questionnaire"
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+
+	testCases := []test{
+		{
+			description: "アンケートURLありのエディションが取得できる",
+			editionID:   editionUUID,
+			resultEdition: domain.NewLauncherVersionWithQuestionnaire(
+				editionID,
+				editionName,
+				values.NewLauncherVersionQuestionnaireURL(questionnaireURL),
+				now,
+			),
+			expectEdition: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          string(editionName),
+				Questionnaire: &strURL,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "アンケートURLなしのエディションが取得できる",
+			editionID:   editionUUID,
+			resultEdition: domain.NewLauncherVersionWithoutQuestionnaire(
+				editionID,
+				editionName,
+				now,
+			),
+			expectEdition: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          string(editionName),
+				Questionnaire: nil,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description:   "存在しないエディションIDなので400",
+			editionID:     editionUUID,
+			GetEditionErr: service.ErrInvalidEditionID,
+			isErr:         true,
+			statusCode:    http.StatusBadRequest,
+		},
+		{
+			description:   "GetEditionがエラーなので500",
+			editionID:     editionUUID,
+			GetEditionErr: errors.New("internal error"),
+			isErr:         true,
+			statusCode:    http.StatusInternalServerError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			mockEditionService.
+				EXPECT().
+				GetEdition(gomock.Any(), values.NewLauncherVersionIDFromUUID(testCase.editionID)).
+				Return(testCase.resultEdition, testCase.GetEditionErr)
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v2/editions/%s", testCase.editionID), nil)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			err := edition.GetEdition(c, testCase.editionID)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, testCase.statusCode, rec.Code)
+
+			var res openapi.Edition
+			err = json.NewDecoder(rec.Body).Decode(&res)
+			assert.NoError(t, err)
+
+			assert.Equal(t, testCase.expectEdition.Id, res.Id)
+			assert.Equal(t, testCase.expectEdition.Name, res.Name)
+			assert.Equal(t, testCase.expectEdition.Questionnaire, res.Questionnaire)
+			assert.WithinDuration(t, testCase.expectEdition.CreatedAt, res.CreatedAt, time.Second)
+		})
+	}
+}
+
+func TestPatchEdition(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description       string
+		editionID         openapi.EditionIDInPath
+		reqBody           *openapi.PatchEdition
+		invalidBody       bool
+		executeUpdateMock bool
+		launcherVersionID values.LauncherVersionID
+		name              values.LauncherVersionName
+		questionnaireURL  types.Option[values.LauncherVersionQuestionnaireURL]
+		updateEditionErr  error
+		resultEdition     *domain.LauncherVersion
+		isErr             bool
+		statusCode        int
+		expectedRes       *openapi.Edition
+	}
+
+	now := time.Now()
+	editionUUID := uuid.New()
+	editionID := values.NewLauncherVersionIDFromUUID(editionUUID)
+	editionName := "テストエディション"
+	strURL := "https://example.com/questionnaire"
+	invalidURL := " https://example.com/questionnaire with spaces"
+	longName := strings.Repeat("あ", 33)
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+
+	testCases := []test{
+		{
+			description: "特に問題ないのでエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name:          editionName,
+				Questionnaire: &strURL,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.NewOption(values.NewLauncherVersionQuestionnaireURL(questionnaireURL)),
+			resultEdition: domain.NewLauncherVersionWithQuestionnaire(
+				editionID,
+				values.NewLauncherVersionName(editionName),
+				values.NewLauncherVersionQuestionnaireURL(questionnaireURL),
+				now,
+			),
+			expectedRes: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          editionName,
+				Questionnaire: &strURL,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "URLがなくてもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: editionName,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.Option[values.LauncherVersionQuestionnaireURL]{},
+			resultEdition: domain.NewLauncherVersionWithoutQuestionnaire(
+				editionID,
+				values.NewLauncherVersionName(editionName),
+				now,
+			),
+			expectedRes: &openapi.Edition{
+				Id:            editionUUID,
+				Name:          editionName,
+				Questionnaire: nil,
+				CreatedAt:     now,
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "リクエストボディが不正なので400",
+			editionID:   editionUUID,
+			invalidBody: true,
+			isErr:       true,
+			statusCode:  http.StatusBadRequest,
+		},
+		{
+			description: "名前が空文字なので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: "",
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "名前が長すぎるので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: longName,
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "URLが正しくないので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name:          editionName,
+				Questionnaire: &invalidURL,
+			},
+			isErr:      true,
+			statusCode: http.StatusBadRequest,
+		},
+		{
+			description: "ErrInvalidEditionIDなので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: editionName,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.Option[values.LauncherVersionQuestionnaireURL]{},
+			updateEditionErr:  service.ErrInvalidEditionID,
+			isErr:             true,
+			statusCode:        http.StatusBadRequest,
+		},
+		{
+			description: "ErrDuplicateGameVersionなので500",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: editionName,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.Option[values.LauncherVersionQuestionnaireURL]{},
+			updateEditionErr:  service.ErrDuplicateGameVersion,
+			isErr:             true,
+			statusCode:        http.StatusInternalServerError,
+		},
+		{
+			description: "ErrDuplicateGameなので500",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: editionName,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.Option[values.LauncherVersionQuestionnaireURL]{},
+			updateEditionErr:  service.ErrDuplicateGame,
+			isErr:             true,
+			statusCode:        http.StatusInternalServerError,
+		},
+		{
+			description: "サービス層でエラーなので500",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEdition{
+				Name: editionName,
+			},
+			executeUpdateMock: true,
+			launcherVersionID: editionID,
+			name:              values.NewLauncherVersionName(editionName),
+			questionnaireURL:  types.Option[values.LauncherVersionQuestionnaireURL]{},
+			updateEditionErr:  errors.New("internal error"),
+			isErr:             true,
+			statusCode:        http.StatusInternalServerError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			if !testCase.invalidBody && testCase.executeUpdateMock {
+				mockEditionService.
+					EXPECT().
+					UpdateEdition(
+						gomock.Any(),
+						testCase.launcherVersionID,
+						testCase.name,
+						testCase.questionnaireURL,
+					).
+					Return(testCase.resultEdition, testCase.updateEditionErr)
+			}
+
+			var reqBody []byte
+			var err error
+			if !testCase.invalidBody {
+				reqBody, err = json.Marshal(testCase.reqBody)
+				assert.NoError(t, err)
+			} else {
+				reqBody = []byte("invalid json")
+			}
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/api/v2/editions/%s", testCase.editionID), bytes.NewReader(reqBody))
+			req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			err = edition.PatchEdition(c, testCase.editionID)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, testCase.statusCode, rec.Code)
+
+			if testCase.expectedRes != nil {
+				var res openapi.Edition
+				err = json.NewDecoder(rec.Body).Decode(&res)
+				assert.NoError(t, err)
+
+				assert.Equal(t, testCase.expectedRes.Id, res.Id)
+				assert.Equal(t, testCase.expectedRes.Name, res.Name)
+				assert.Equal(t, testCase.expectedRes.Questionnaire, res.Questionnaire)
+				assert.WithinDuration(t, testCase.expectedRes.CreatedAt, res.CreatedAt, time.Second)
+			}
+		})
+	}
+}
+
+func TestGetEditionGames(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description        string
+		editionID          openapi.EditionIDInPath
+		gameVersions       []*service.GameVersionWithGame
+		getEditionGamesErr error
+		expectGames        []openapi.EditionGameResponse
+		isErr              bool
+		statusCode         int
+	}
+
+	now := time.Now()
+	editionUUID := uuid.New()
+	gameID := values.NewGameID()
+	gameID2 := values.NewGameID()
+	gameVersionID := values.NewGameVersionID()
+	gameVersionID2 := values.NewGameVersionID()
+	imageID := values.NewGameImageID()
+	videoID := values.NewGameVideoID()
+	fileID1 := values.NewGameFileID()
+	fileID2 := values.NewGameFileID()
+	fileID1UUID := uuid.UUID(fileID1)
+	fileID2UUID := uuid.UUID(fileID2)
+	game1 := domain.NewGame(
+		gameID,
+		values.NewGameName("テストゲーム1"),
+		values.NewGameDescription("テスト説明1"),
+		values.GameVisibilityTypePublic,
+		now,
+	)
+	game2 := domain.NewGame(
+		gameID2,
+		values.NewGameName("テストゲーム2"),
+		values.NewGameDescription("テスト説明2"),
+		values.GameVisibilityTypePrivate,
+		now,
+	)
+	gameLimited := domain.NewGame(
+		gameID,
+		values.NewGameName("テストゲーム"),
+		values.NewGameDescription("テスト説明"),
+		values.GameVisibilityTypeLimited,
+		now,
+	)
+	gameVersion := domain.NewGameVersion(
+		gameVersionID,
+		values.NewGameVersionName("v1.0.0"),
+		values.NewGameVersionDescription("リリース"),
+		now,
+	)
+	gameVersion2 := domain.NewGameVersion(
+		gameVersionID2,
+		values.NewGameVersionName("v1.0.0"),
+		values.NewGameVersionDescription("リリース"),
+		now,
+	)
+
+	strURL := "https://example.com"
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+	urlValue := values.NewGameURLLink(questionnaireURL)
+
+	testCases := []test{
+		{
+			description: "特に問題ないのでエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							URL: types.NewOption(urlValue),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Url:         &strURL,
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "ゲームURLとゲームファイルがnullでもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: gameLimited,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets:      &service.Assets{},
+						ImageID:     imageID,
+						VideoID:     videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "windowsでもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Windows: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Win32: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "macでもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Mac: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Darwin: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "jarでもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Jar: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Jar: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "ファイルが複数あってももエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Jar:     types.NewOption(fileID1),
+							Windows: types.NewOption(fileID2),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Jar:   &fileID1UUID,
+							Win32: &fileID2UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "ファイルとurlが両方あってもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Windows: types.NewOption(fileID1),
+							URL:     types.NewOption(urlValue),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Win32: &fileID1UUID,
+						},
+						Url: &strURL,
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "2つ以上のゲームがリストに含まれていてもエラーなし",
+			editionID:   editionUUID,
+			gameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game1,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							URL: types.NewOption(urlValue),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+				{
+					Game: game2,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion2,
+						Assets: &service.Assets{
+							URL: types.NewOption(urlValue),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム1",
+					Description: "テスト説明1",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Url:         &strURL,
+					},
+				},
+				{
+					Id:          uuid.UUID(gameID2),
+					Name:        "テストゲーム2",
+					Description: "テスト説明2",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID2),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Url:         &strURL,
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description:        "不正なeditionIDなので400",
+			editionID:          editionUUID,
+			getEditionGamesErr: service.ErrInvalidEditionID,
+			isErr:              true,
+			statusCode:         http.StatusBadRequest,
+		},
+		{
+			description:        "サービス層でエラーが発生したので500",
+			editionID:          editionUUID,
+			getEditionGamesErr: errors.New("internal error"),
+			isErr:              true,
+			statusCode:         http.StatusInternalServerError,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			mockEditionService.
+				EXPECT().
+				GetEditionGameVersions(
+					gomock.Any(),
+					values.NewLauncherVersionIDFromUUID(testCase.editionID),
+				).
+				Return(testCase.gameVersions, testCase.getEditionGamesErr)
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodGet, fmt.Sprintf("/api/v2/editions/%s/games", testCase.editionID), nil)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			err := edition.GetEditionGames(c, testCase.editionID)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, testCase.statusCode, rec.Code)
+
+			var res []openapi.EditionGameResponse
+			err = json.NewDecoder(rec.Body).Decode(&res)
+			if err != nil {
+				t.Fatalf("failed to decode response body: %v", err)
+			}
+
+			assert.Len(t, res, len(testCase.expectGames))
+			for i, game := range res {
+				assert.Equal(t, testCase.expectGames[i].Id, game.Id)
+				assert.Equal(t, testCase.expectGames[i].Name, game.Name)
+				assert.Equal(t, testCase.expectGames[i].Description, game.Description)
+				assert.WithinDuration(t, testCase.expectGames[i].CreatedAt, game.CreatedAt, 2*time.Second)
+
+				assert.Equal(t, testCase.expectGames[i].Version.Id, game.Version.Id)
+				assert.Equal(t, testCase.expectGames[i].Version.Name, game.Version.Name)
+				assert.Equal(t, testCase.expectGames[i].Version.Description, game.Version.Description)
+				assert.WithinDuration(t, testCase.expectGames[i].Version.CreatedAt, game.Version.CreatedAt, 2*time.Second)
+				assert.Equal(t, testCase.expectGames[i].Version.Url, game.Version.Url)
+				assert.Equal(t, testCase.expectGames[i].Version.Files, game.Version.Files)
+				assert.Equal(t, testCase.expectGames[i].Version.ImageID, game.Version.ImageID)
+				assert.Equal(t, testCase.expectGames[i].Version.VideoID, game.Version.VideoID)
+			}
+		})
+	}
+}
+
+func TestPatchEditionGame(t *testing.T) {
+	t.Parallel()
+
+	type test struct {
+		description           string
+		editionID             openapi.EditionIDInPath
+		reqBody               *openapi.PatchEditionGameRequest
+		invalidBody           bool
+		executeUpdateMock     bool
+		launcherVersionID     values.LauncherVersionID
+		gameVersionIDs        []values.GameVersionID
+		updateEditionGamesErr error
+		resultGameVersions    []*service.GameVersionWithGame
+		expectGames           []openapi.EditionGameResponse
+		isErr                 bool
+		statusCode            int
+	}
+
+	now := time.Now()
+	editionUUID := uuid.New()
+	gameID := values.NewGameID()
+	gameVersionID1 := values.NewGameVersionID()
+	gameVersionID2 := values.NewGameVersionID()
+	fileID1 := values.NewGameFileID()
+	fileID2 := values.NewGameFileID()
+	fileID1UUID := uuid.UUID(fileID1)
+	fileID2UUID := uuid.UUID(fileID2)
+	imageID := values.NewGameImageID()
+	videoID := values.NewGameVideoID()
+	game := domain.NewGame(
+		gameID,
+		values.NewGameName("テストゲーム"),
+		values.NewGameDescription("テスト説明"),
+		values.GameVisibilityTypePublic,
+		now,
+	)
+	gameVersion := domain.NewGameVersion(
+		gameVersionID1,
+		values.NewGameVersionName("v1.0.0"),
+		values.NewGameVersionDescription("リリース"),
+		now,
+	)
+
+	strURL := "https://example.com"
+	questionnaireURL, err := url.Parse(strURL)
+	if err != nil {
+		t.Fatalf("failed to parse url: %v", err)
+	}
+	urlValue := values.NewGameURLLink(questionnaireURL)
+
+	testCases := []test{
+		{
+			description: "特に問題ないのでエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{
+					uuid.UUID(gameVersionID1),
+					uuid.UUID(gameVersionID2),
+				},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs: []values.GameVersionID{
+				gameVersionID1,
+				gameVersionID2,
+			},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets:      &service.Assets{},
+						ImageID:     imageID,
+						VideoID:     videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "空のゲームバージョン一覧でもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{},
+			},
+			executeUpdateMock:  true,
+			launcherVersionID:  values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:     []values.GameVersionID{},
+			resultGameVersions: []*service.GameVersionWithGame{},
+			expectGames:        []openapi.EditionGameResponse{},
+			statusCode:         http.StatusOK,
+		},
+		{
+			description: "不正なリクエストボディなので400",
+			editionID:   editionUUID,
+			invalidBody: true,
+			isErr:       true,
+			statusCode:  http.StatusBadRequest,
+		},
+		{
+			description: "不正なゲームバージョンIDなので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock:     true,
+			launcherVersionID:     values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:        []values.GameVersionID{gameVersionID1},
+			updateEditionGamesErr: service.ErrInvalidEditionID,
+			isErr:                 true,
+			statusCode:            http.StatusBadRequest,
+		},
+		{
+			description: "ErrDuplicateGameVersionなので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{
+					uuid.UUID(gameVersionID1),
+					uuid.UUID(gameVersionID1),
+				},
+			},
+			executeUpdateMock:     true,
+			launcherVersionID:     values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:        []values.GameVersionID{gameVersionID1, gameVersionID1},
+			updateEditionGamesErr: service.ErrDuplicateGameVersion,
+			isErr:                 true,
+			statusCode:            http.StatusBadRequest,
+		},
+		{
+			description: "ErrDuplicateGameなので400",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock:     true,
+			launcherVersionID:     values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:        []values.GameVersionID{gameVersionID1},
+			updateEditionGamesErr: service.ErrDuplicateGame,
+			isErr:                 true,
+			statusCode:            http.StatusBadRequest,
+		},
+		{
+			description: "サービス層でエラーが発生したので500",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock:     true,
+			launcherVersionID:     values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:        []values.GameVersionID{gameVersionID1},
+			updateEditionGamesErr: errors.New("internal error"),
+			isErr:                 true,
+			statusCode:            http.StatusInternalServerError,
+		},
+		{
+			description: "windowsでもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{
+					uuid.UUID(gameVersionID1),
+					uuid.UUID(gameVersionID2),
+				},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs: []values.GameVersionID{
+				gameVersionID1,
+				gameVersionID2,
+			},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Windows: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Win32: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "macファイルでもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:    []values.GameVersionID{gameVersionID1},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Mac: types.NewOption(fileID2),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Darwin: &fileID2UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "jarファイルでもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:    []values.GameVersionID{gameVersionID1},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Jar: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Jar: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "ファイルが複数でもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:    []values.GameVersionID{gameVersionID1},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							Windows: types.NewOption(fileID1),
+							Mac:     types.NewOption(fileID2),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Files: &openapi.GameVersionFiles{
+							Win32:  &fileID1UUID,
+							Darwin: &fileID2UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+		{
+			description: "urlとファイルでもエラーなし",
+			editionID:   editionUUID,
+			reqBody: &openapi.PatchEditionGameRequest{
+				GameVersionIDs: []uuid.UUID{uuid.UUID(gameVersionID1)},
+			},
+			executeUpdateMock: true,
+			launcherVersionID: values.NewLauncherVersionIDFromUUID(editionUUID),
+			gameVersionIDs:    []values.GameVersionID{gameVersionID1},
+			resultGameVersions: []*service.GameVersionWithGame{
+				{
+					Game: game,
+					GameVersion: service.GameVersionInfo{
+						GameVersion: gameVersion,
+						Assets: &service.Assets{
+							URL:     types.NewOption(urlValue),
+							Windows: types.NewOption(fileID1),
+						},
+						ImageID: imageID,
+						VideoID: videoID,
+					},
+				},
+			},
+			expectGames: []openapi.EditionGameResponse{
+				{
+					Id:          uuid.UUID(gameID),
+					Name:        "テストゲーム",
+					Description: "テスト説明",
+					CreatedAt:   now,
+					Version: openapi.GameVersion{
+						Id:          uuid.UUID(gameVersionID1),
+						Name:        "v1.0.0",
+						Description: "リリース",
+						CreatedAt:   now,
+						ImageID:     uuid.UUID(imageID),
+						VideoID:     uuid.UUID(videoID),
+						Url:         &strURL,
+						Files: &openapi.GameVersionFiles{
+							Win32: &fileID1UUID,
+						},
+					},
+				},
+			},
+			statusCode: http.StatusOK,
+		},
+	}
+
+	for _, testCase := range testCases {
+		t.Run(testCase.description, func(t *testing.T) {
+			t.Parallel()
+
+			ctrl := gomock.NewController(t)
+			mockEditionService := mock.NewMockEdition(ctrl)
+			edition := NewEdition(mockEditionService)
+
+			var reqBody []byte
+			var err error
+			if !testCase.invalidBody {
+				reqBody, err = json.Marshal(testCase.reqBody)
+				assert.NoError(t, err)
+			} else {
+				reqBody = []byte("invalid json")
+			}
+
+			e := echo.New()
+			req := httptest.NewRequest(http.MethodPatch, fmt.Sprintf("/api/v2/editions/%s/games", testCase.editionID), bytes.NewReader(reqBody))
+			req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON)
+			rec := httptest.NewRecorder()
+			c := e.NewContext(req, rec)
+
+			if testCase.executeUpdateMock {
+				mockEditionService.
+					EXPECT().
+					UpdateEditionGameVersions(
+						gomock.Any(),
+						testCase.launcherVersionID,
+						testCase.gameVersionIDs,
+					).
+					Return(testCase.resultGameVersions, testCase.updateEditionGamesErr)
+			}
+
+			err = edition.PatchEditionGame(c, testCase.editionID)
+
+			if testCase.isErr {
+				if testCase.statusCode != 0 {
+					var httpErr *echo.HTTPError
+					if assert.ErrorAs(t, err, &httpErr, "error should be *echo.HTTPError") {
+						assert.Equal(t, testCase.statusCode, httpErr.Code)
+					}
+				} else {
+					assert.Error(t, err)
+				}
+				return
+			}
+
+			assert.NoError(t, err)
+			assert.Equal(t, testCase.statusCode, rec.Code)
+
+			if testCase.expectGames != nil {
+				var res []openapi.EditionGameResponse
+				err = json.NewDecoder(rec.Body).Decode(&res)
+				assert.NoError(t, err)
+
+				assert.Len(t, res, len(testCase.expectGames))
+				for i, game := range res {
+					assert.Equal(t, testCase.expectGames[i].Id, game.Id)
+					assert.Equal(t, testCase.expectGames[i].Name, game.Name)
+					assert.Equal(t, testCase.expectGames[i].Description, game.Description)
+					assert.WithinDuration(t, testCase.expectGames[i].CreatedAt, game.CreatedAt, 2*time.Second)
+
+					assert.Equal(t, testCase.expectGames[i].Version.Id, game.Version.Id)
+					assert.Equal(t, testCase.expectGames[i].Version.Name, game.Version.Name)
+					assert.Equal(t, testCase.expectGames[i].Version.Description, game.Version.Description)
+					assert.WithinDuration(t, testCase.expectGames[i].Version.CreatedAt, game.Version.CreatedAt, 2*time.Second)
+					assert.Equal(t, testCase.expectGames[i].Version.Url, game.Version.Url)
+					assert.Equal(t, testCase.expectGames[i].Version.Files, game.Version.Files)
+					assert.Equal(t, testCase.expectGames[i].Version.ImageID, game.Version.ImageID)
+					assert.Equal(t, testCase.expectGames[i].Version.VideoID, game.Version.VideoID)
+				}
+			}
+		})
+	}
+}
diff --git a/src/handler/v2/game_version_test.go b/src/handler/v2/game_version_test.go
index 33fd6918..cb124c6d 100644
--- a/src/handler/v2/game_version_test.go
+++ b/src/handler/v2/game_version_test.go
@@ -552,7 +552,7 @@ func TestPostGameVersion(t *testing.T) {
 	fileID2 := values.NewGameFileID()
 	fileID1UUID := uuid.UUID(fileID1)
 	fileID2UUID := uuid.UUID(fileID2)
-	invalidURL := " https://example.com"
+	invalidURL := " https://example.com with spaces"
 	strURL := "https://example.com"
 	urlLink, err := url.Parse(strURL)
 	if err != nil {
diff --git a/src/handler/v2/openapi/openapi.gen.go b/src/handler/v2/openapi/openapi.gen.go
index 58785335..764c5678 100644
--- a/src/handler/v2/openapi/openapi.gen.go
+++ b/src/handler/v2/openapi/openapi.gen.go
@@ -823,8 +823,8 @@ type PostEditionAuthorizeJSONRequestBody = EditionAuthorizeRequest
 // PatchEditionJSONRequestBody defines body for PatchEdition for application/json ContentType.
 type PatchEditionJSONRequestBody = PatchEdition
 
-// PostEditionGameJSONRequestBody defines body for PostEditionGame for application/json ContentType.
-type PostEditionGameJSONRequestBody = PatchEditionGameRequest
+// PatchEditionGameJSONRequestBody defines body for PatchEditionGame for application/json ContentType.
+type PatchEditionGameJSONRequestBody = PatchEditionGameRequest
 
 // PostGameJSONRequestBody defines body for PostGame for application/json ContentType.
 type PostGameJSONRequestBody = NewGame
@@ -896,7 +896,7 @@ type ServerInterface interface {
 	GetEditionGames(ctx echo.Context, editionID EditionIDInPath) error
 	// エディションのゲームの変更
 	// (PATCH /editions/{editionID}/games)
-	PostEditionGame(ctx echo.Context, editionID EditionIDInPath) error
+	PatchEditionGame(ctx echo.Context, editionID EditionIDInPath) error
 	// プロダクトキーの一覧の取得
 	// (GET /editions/{editionID}/keys)
 	GetProductKeys(ctx echo.Context, editionID EditionIDInPath, params GetProductKeysParams) error
@@ -1174,8 +1174,8 @@ func (w *ServerInterfaceWrapper) GetEditionGames(ctx echo.Context) error {
 	return err
 }
 
-// PostEditionGame converts echo context to params.
-func (w *ServerInterfaceWrapper) PostEditionGame(ctx echo.Context) error {
+// PatchEditionGame converts echo context to params.
+func (w *ServerInterfaceWrapper) PatchEditionGame(ctx echo.Context) error {
 	var err error
 	// ------------- Path parameter "editionID" -------------
 	var editionID EditionIDInPath
@@ -1188,7 +1188,7 @@ func (w *ServerInterfaceWrapper) PostEditionGame(ctx echo.Context) error {
 	ctx.Set(AdminAuthScopes, []string{})
 
 	// Invoke the callback with all the unmarshaled arguments
-	err = w.Handler.PostEditionGame(ctx, editionID)
+	err = w.Handler.PatchEditionGame(ctx, editionID)
 	return err
 }
 
@@ -2010,7 +2010,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
 	router.GET(baseURL+"/editions/:editionID", wrapper.GetEdition)
 	router.PATCH(baseURL+"/editions/:editionID", wrapper.PatchEdition)
 	router.GET(baseURL+"/editions/:editionID/games", wrapper.GetEditionGames)
-	router.PATCH(baseURL+"/editions/:editionID/games", wrapper.PostEditionGame)
+	router.PATCH(baseURL+"/editions/:editionID/games", wrapper.PatchEditionGame)
 	router.GET(baseURL+"/editions/:editionID/keys", wrapper.GetProductKeys)
 	router.POST(baseURL+"/editions/:editionID/keys", wrapper.PostProductKey)
 	router.POST(baseURL+"/editions/:editionID/keys/:productKeyID/activate", wrapper.PostActivateProductKey)
@@ -2156,82 +2156,82 @@ var swaggerSpec = []string{
 	"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",
-	"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",
+	"ioWVsiPu5O+z6ab0zuh5d5aYyM0zkKdul5LKz/VjymbxQhsD9dH3SHmlTuukbKWwbgUutlG6OOqEt0mf",
+	"pWXSA1Dvglu0+BTH79HgqL5T+Jw4PoXTEb+Qz4VUEY21V9Sjxq9LFFpdtCsg5SJheV7GVX5pIvVRXs6e",
+	"A97Xec7A1BBrXd30K/PUVv3SZ5J+nFWP034wrTV0L7VFlRALJZlF+oy4s79+veyXWl+/fk8sVIyhwubZ",
+	"xwf5ZADvGNl23uGDAPVbzyECp2nuQAfoc4fdxx0IBYX2OYNSMHQ+wxRQnBqCWoYScUO3yEuiIchShAM1",
+	"oaXoC8alOVJEwyjdFOAxB8ztO3hNxyzjLG8Q5wXOLQlyBMcdwmfgvkF8RxnEfUqxBBhbaos/YoQB5EHa",
+	"So9YwwXQvD28jRSp2TWcbekn48qzPWRTbwjwto/hyZ7mbLClPk/r87SwPI1izmKvufoCMT2QrTVy6wk6",
+	"7ox5R6+X2p1C7eYTbgN7s6iZXYy7unVrbuuHS//v92mrbQx8nMH3iV/ma9/f8aErZ6mRkp37ipf42LRT",
+	"amWkzaGC5q48Qju9Vmld6jVmituooEGV+ArSdabflKsZvcf2RH2ULsbv9iPlZXcVWchj4FRdKWjHU1CS",
+	"lvsCW5lkA+osuzI2ndk7TN0y7TVY5a+7W3tehopmj6HH3TRU2smzvY4dpVAYKnCdBFmxtuzN79gqaK4m",
+	"eGSGgJZltL7Jl3CbtsqbSIkEreoGnMG88p5MpxOylMLU46lEbaKtq6hgdWP9ytatedJygGEVr9xN11bg",
+	"6yrTF/AWVDZ31ckp0XluCO0Dalo5dhLcjUB0V1s3Z43l2Y2Xc/WX1ZAbG/brlcdZPuljyl//cCvrd7RR",
+	"5K3f91gKmqsFI3Gp1n/5HulXNl/9biK/nWlkkbTdpE5/Cm9/z1azd7XX21y6XLvxhK5imXAZ55eLLKIj",
+	"7S4Uc5xx4o1jpcbLa/D9GjCcWacL7bpH+eIdCLTFdJxHuB6S/P4yAtXkPAwKM4XpS2wJyID9+J0mbdkp",
+	"eog+UDHbtdhAsQuII20BWGaB1zxOnIc8QtrTrR8uhUVVvtzkNEsrscIRqkG5hbDP1nPprJM+aSV9u+1G",
+	"NJKQVDmn0mZv3qL6LTtAAnHP3bma6+3w9Xa3P1jGmqFcu3t/48Wv+FCfF0CbuOVpzdyrKn/QvbuduVtW",
+	"f31f58EkdDTwzey2erM1ihigiZtl4Jcz+CCJJgKqha3yOVuYHk9tXl4xZm+QZia+DUq5d9kOhiHQJswd",
+	"ThincwTRU8vlj6wTpCPRCurebmG9Sy5+G94x1RbcB+qlQOu+N3Qe/xcqIcwc3Yy+YjriiWeFWdTUOCWM",
+	"0S56NROMhQjDdM02Sl2xtnR4hya79fSlXu7x0EDmKta7EYGuErlB5OxJNrMEasNMMz+6bSKhOYB6uyap",
+	"XMk4HdD8ekRMtYW5CFhkafXwnsi82DF0y6u37kvA/glktl4cyk9ERHe41DEBPkC7uDaO0e10cK6/Xtxe",
+	"bgO1GUQ5DgVP85WUYAAaXtvLHIetEbjtHqVu6zh2GX9U0EyFpwrtEe6D7W4Z/AV9/acdfNTdXiFICfLP",
+	"XfO93AxZfflb0JOQ/iMqFqmD7XdUnKmtTyPtNdv6xfKMeT0qPqHxSCvTUN1vqEOMabfDtpVhHVD6bF0H",
+	"x/XTcu3C1UBV7V3YezfClulsYkHLFjwcnXNC16TxORSf4dlMXCsrgbgdkbbcLxnQ508t2Fu8jMBH1wMi",
+	"aYe+xzejirCzipO1cAto8p3GDoJac/emCMPnbNlJDLP4NuY47MY2WYBkkAaazCdUJSNl1aFT6WxyMC6p",
+	"UmjTLOFpnTfP0nlEeWWba3o25pg7O6yJ+gum8TB4q4zXgMeBvlYyTlgs0x54pEvWcp/39pZuyKMOPuf1",
+	"UxHJR/yQaRIX1xfdTWSr/HWFM7NZ7E1YdUvHVFkdzKlZWUqG5z4HzUE7qLAJGuCC+iluNxNyHvSOrlFw",
+	"O7BAASlj21s1CirmTV2kJ7MndIKJ4NsRF3fHJnudUfN6pjrKGzg7hovycSftd1Chjgo9T4SDo4dDQ0ky",
+	"lJSJ2tkD4uQwXkqH7alhFVmnjtktkdJLem1fpPRFSl+kdE+kcPhNL4sUiOXNhc8k81qM8g1yO1zR1hvr",
+	"f0fatJWpQSOflzfWr9S+WwdqdMSduqw0edUKJ8614CjMZPG4qkJt+BQY4QKaPwBvojekmX6RPvm5HFMb",
+	"+QFZAAFpWTCxo8S6Hhrx4V92beBcL+eTuaiDUBsGweOfIYDfFRwemtuaOUsmTBfbGLXbigOOpYD6b+Wt",
+	"7y65WCdQG9/KoiSlySY9cQ0cPfXrL4zi1WYccJUgB5xz+GZ9cBNk291ywsF0obxwDui13wtnQs/H/0Ys",
+	"da4swL47rm8Sbskdx0VpF6cihLLNnjjKWsR9cJSc2uR9w+fWrAOOQLDTHjiToXXeBWdN1IBTdsz7xuWU",
+	"/W4GfV7YsubmQlwfTuirs5mf8d+hfWNkaidkLa4XxoBpc5suOMRgMhGPmAXZzhguGZbQO14w+0j7xsrt",
+	"MFZSpNilZkq6vZ5PAMA8oqGFEp4SZc8i/q726K1i1kmT5QeZJ3kSogmfV4CYaLoTlgX+bvi9QmiPXXF5",
+	"9aQy2ZccfcnRlxydkRyN3Vo9Jjmy6UR7/FqtZL7Vq/fr85c2Cxd9yk2YZSzNsdyltWrlx1u35veYGUIm",
+	"htnJQ29YdYLqt15slX72wbo1oHQ6h1k2gQyNtGXzD32B63cLSs/7OJ3oVIoeHb6NfTNaTQsmJ0nB1t5O",
+	"GOSACxqTF6YvYOaoFzwpnrswhY8QAbN5OixbSEV7YPuunFTCuk2seZCu86baWC9sPH8OpzVreWLMaUrs",
+	"Cir0gGEAfRpplyxqczF1n6n6xRf6FjTB4gtc3uKSrsBtuUY0EHRD5/M5OduGaiuu1fCLr5h4sjay8fz5",
+	"xouHG+tXoJ4cQPj1xc1HGpTK1MHPfA/pGkggq8oKKKhXKNVRMrwK5ZIYqYX1zMdA4gKVlOzqL5ZY6guL",
+	"3SgsXFjEersoRjmZgguv+uy6z67bzK55pXNMdt3puxBh+kHXoDOk3mLLKerctmt8Y5kz6GKZjbsIrLXs",
+	"Z2SjJSMb1Dzm183ktEFtrhSvMf0rnDf5fnlbSu56NtOjFXi7UMnTRArBgp78poEdSwfwa73bixWf+n72",
+	"HVICIAiFXdLHKrK73YUAnITAj0PyDQCy+X4Hi6PSSboQAcRMFRgG7mUfncnG51WA3n0XBr9MjXq5unX/",
+	"e6SVzyqpePpsLhqXsmeVVPRzKYvJyvRglDZXlljbkzmVrjOFgn0vqf3SVH2+367IeB+m4Mv4A64CQ6QS",
+	"e4s3An77FXH3+fuwCDef76DRRpD9+rSV6WA5UJ8+NjtaV9xVpG/17DhwZGLgzAjkDzBFyAsax7Xtmt9e",
+	"GsDQ0Z8myCTV7gr6DRG8U5okjx8pcTndqdp5xuyN+vUXgXaKpvJ2ruK/dZ3q35WmknY+JTvvVtIOTBcq",
+	"aYdAz7q5tjtpxxq+n7TT+xdoeli74hrtYAt+PA/IZZvvzibUQ6Tu0HPqgdQdAsFOp+6YbK0LF3c6kQC/",
+	"7MhVncsv+6k7fY7YpgumC319+KGvCkc+w2OhE3jI1Fz4hgvFtnlOFxJ4YDKRBB4Lsp25PjKMoXcSeOwj",
+	"7Ydhhw3DbjkGm2LELo3B3imsFxhEwxhseEqUN4tk77RHdRWLwTb5feMbvlM8NJG9EyAjWsregSV1I3sn",
+	"hALZleydntQn+2Jje7N3+pJj90qOxtk72y45rNJrXLnA6VvvqSjHbVfMZfxM2bgWuH57asd57bLRCHRP",
+	"9tbSY/t4k8bAy9Y+vSFlYH1RsnIcHzEeMUrXeEKgMB2p+9Ym9wNzeo49cDHRUeMLFkwUCLN1eGCEuxsj",
+	"PLHralY6MnAwnUjIMfwK0qpSPKmkwMn9GjMH8w3Caf3QyI42f89shS7ScNS59TA9R3eETWfX1uLjyBT2",
+	"KNspUNorTgBefkKCg40+hNiMSDCJtXEepZurUT2elP8TIt0Kod7N8k/G1TUHrP3Lh9IkRpt+21Y/NGTV",
+	"UBejJkOcECodyoecNwi444VDTUEmukatSk9XiPuRh2lXQyfeFpa415Y+w+wFhmnmGgvwzF5jicGdAFkN",
+	"JY2PZXQoJiUSJ6XYF74KLL49Qp7cMtKq5GIHGF0h18pZpM8ch4XhI4bTGDiYjstIK5n4VVxBxW/gNnkf",
+	"LmKvIeqwgu+ZbJgCuXOuoGIBjEX/gFvgtFCuxUG6BxF1xrybaiWWghsEYr5AxaLj3skk8lo2iI3Xd43V",
+	"b+3QGvdbJWP6Mgm3gLGXUXEV6U9Iv6X6lV9rF2cBKq5YTCuEBwN14OBpKZGQU5Mybbi05ufh7F68lXOb",
+	"jA7BQwqywWsQkjkLCLUE+yVZl1cAC+gJVYyln2o3FgVOiI5SNS5dNKrPIPTWZU+qJuVcTsKAqxiXnxtX",
+	"vutk1JLb4gJs5Clc/0hseRHpawxtElpsQmORWBBjCE+kPoIMGHI3pTSejsu+9G0vUl8wph+DnYcki1ft",
+	"gzBzY1eO/OXgO0irAi5+KmeVUwpkcdav3zN9v0DFHnrZLK9aiijhJS5s1i8cTChySsUcFxBbX2DfMeF5",
+	"7OP3kbbOYxKNjKZ4Ojd3GCOCKBidtSpdB6G3ijDXMNe8uTKHlbvibdMIhZmHCJM7LUtxQILzkffThGSd",
+	"1Cp/JSUzCaxpnVbVTG58aOjLvWpWyuz9PDMkZZShM2P0+C35+ye6/79hHe1tjBbH88PDo2/GAPh/U+Jv",
+	"489jMXoY8Ik+k47Lf4vRE6MPOo7R//G/JWX1dDr+9tHR/W/ad/6cmlVSk0A7R2V18GA6/YUi++0yJ+cg",
+	"CPht6WQsPjI6tu+PA1hFf3vojwPvfJVRsnLu7b/K8ejA8L6Bw9K5gdHh0dGBkTfHR/eNj4wMvHf4kz8O",
+	"HJa+GjwwKb89uv+t0eHh4T8O/IeqZj5MJc79ceAoFrUyZ2VT7WMKLDdwEpCJW1UP8q0z+FcmCLUOZjE3",
+	"BvF4CcMAEunJNOlywI/s8d5QSKpo/fqLrbs/EiFPxdWPSH/koTlKFbfMCu1e2RciEOd9slqPMN/HIVf3",
+	"oirNS/VSr4nSXheWTV8Buhc+J4TYmKAcaORHTTlZUgMsvc+XjfXVwMBdnmg6CoN2I6IWzyQSTOvYSGhP",
+	"nvPtEr+YzSOkPYXY2DVjfVWJ4xv2t5dJsGzvY5jt0OAjHRd+DE5hNCK6HpcZG+urJMmbVt/w1t1iLqHE",
+	"XHTPWF/ds/Fqdnx02FhfJXg9Mkz+XmcKeawgfQaDuzTyf0exHMIPFDT6JH7LHIDz4BtIqx5P1e8WjPVV",
+	"el9Zc1QbMl2Id8Gs9QpprzZe362VNDGuD9jZmYxJOjxTlYu1XanZvDzVUwRIMCB0/RW22kobaXB3h2R2",
+	"Txi5jtXLESwZM3Qe/2e6jMLdCMmLjc3XQOUUwfSFzfsl1u7sVz4PY/BRVVLzuU6RqnOWDlJsY0LlEmbL",
+	"VPk/PgZ6e2Uzc4J8AsznzGu3nzX0iB0HU7yE9AeoeBNMm0/NSBOraoa4DngM5uyGCMIziYgggto7SMs3",
+	"o0XoKbDpX8w548Nlz3ko6W8YY+2zG4A2zvqN1dChe4c7Wt+NHK33KDcvrxjTl1gnVsuxeSxo2NKSfAAF",
+	"sbqexy03FvB3WPXFNJgPz0+kdz6bYCx2Metm6jTdjUJAkt+zg3H5DDyvKntVOXaa/8740FAiHZMSp9M5",
+	"dXxseHjY+5j1zQlr3SGsw86bdNWK+QNV4tKBIxPOYlO0IhO5UHsLR7mGYwG9dfPHrcIDpFX9Bs0TrtbA",
+	"rGVcLG+8vMYWN244MDjqOSNbwVwNR5gkHTbPCxZdFBoParQFj8n6BIXGpCFd58ULvAiNaxUvaDCyXeJE",
+	"aFjSTjsYrFADXGg02hwweInXIAB1RWzbZuayd0R3GOue2uKyK9bWBec3Gs4oE5WHN59rZMvi5VkHYWVU",
+	"NJh+C9GZgXdyisGtrxLkbjgOKGBTJ6b+fwAAAP//Aw7xBhBcAQA=",
 }
 
 // GetSwagger returns the content of the embedded swagger specification file