diff --git a/Makefile b/Makefile index 89c1c50..7d9c6b8 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,19 @@ build: go build -o ./bin/app ./src/cmd/app/main.go -run: +run:test ifeq ($(OS),Windows_NT) $env:GO_ENV="test"; go run ./src/cmd/app/main.go else GO_ENV=test go run ./src/cmd/app/main.go endif + +run:prod: +ifeq ($(OS),Windows_NT) + $env:GO_ENV="prod"; go run ./src/cmd/app/main.go +else + GO_ENV=prod go run ./src/cmd/app/main.go +endif test: go test -p 1 -v ./... diff --git a/README.md b/README.md index c573660..4ea01fc 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ You might need to remove mongodb setting from docker-compose.yml if launching th 1. Clone the repository 2. Configure the environment variables in the `.env.test` file -3. `make run` to start the application +3. `make run:test` to start the application # Integrated tests diff --git a/resources/swagger.yaml b/resources/swagger.yaml new file mode 100644 index 0000000..6cf2626 --- /dev/null +++ b/resources/swagger.yaml @@ -0,0 +1,348 @@ +openapi: 3.0.1 +info: + title: Switcher GitOps + version: v1.0.1 + description: GitOps Domain Snapshot Orchestrator for Switcher API. + contact: + name: Roger Floriano (petruki) + email: switcher.project@gmail.com + url: https://github.com/petruki + license: + name: MIT + url: https://github.com/switcherapi/switcher-gitops/blob/master/LICENSE +servers: + - url: http://localhost:8000 + description: Local + - url: https://localhost:8000 + description: Remote +paths: + /api/check: + get: + tags: + - API + summary: Check API status + description: Check API status + responses: + '200': + description: API status + content: + application/json: + schema: + type: object + properties: + status: + type: string + description: API status + version: + type: string + description: API version + release_time: + type: string + description: API last release date time + api_settings: + type: object + properties: + switcher_url: + type: string + description: Switcher API URL + switcher_secret: + type: boolean + description: Has Switcher API secret + git_token_secret: + type: boolean + description: Has Git token secret + core_handler_status: + type: boolean + description: Core handler status (-1 Created, 0 Initialized, 1 Running) + enum: [ "-1", "0", "1" ] + num_goroutines: + type: integer + description: Number of goroutines running + /account: + post: + tags: + - Account API + summary: Create a new account + description: Create a new account and starts handler when active + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AccountRequest' + responses: + '201': + description: Account created + content: + application/json: + schema: + $ref: '#/components/schemas/AccountResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Error creating accoun + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + put: + tags: + - Account API + summary: Update an existing account + description: Update an existing account and starts handler when active + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AccountRequest' + responses: + '200': + description: Account updated + content: + application/json: + schema: + $ref: '#/components/schemas/AccountResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Error updating account + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /account/{domainId}: + get: + tags: + - Account API + summary: Get All accounts by domain ID + description: Get all accounts by domain ID + parameters: + - name: domainId + in: path + required: true + description: Domain ID + schema: + type: string + format: uuid + responses: + '200': + description: Account list + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/AccountResponse' + '404': + description: Accounts not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Error getting accounts + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + /account/{domainId}/{environment}: + get: + tags: + - Account API + summary: Get account by domain ID and environment + description: Get account by domain ID and environment + parameters: + - name: domainId + in: path + required: true + description: Domain ID + schema: + type: string + format: uuid + - name: environment + in: path + required: true + description: Environment name + schema: + type: string + responses: + '200': + description: Account list + content: + application/json: + schema: + $ref: '#/components/schemas/AccountResponse' + '404': + description: Account not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Error getting account + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + delete: + tags: + - Account API + summary: Delete account by domain ID and environment + description: Delete account by domain ID and environment + parameters: + - name: domainId + in: path + required: true + description: Domain ID + schema: + type: string + format: uuid + - name: environment + in: path + required: true + description: Environment name + schema: + type: string + responses: + '204': + description: Account deleted + '400': + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + '500': + description: Error deleting account + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + AccountRequest: + type: object + properties: + repository: + type: string + description: Git repository URL + branch: + type: string + description: Git branch + example: main + token: + type: string + description: Git token + environment: + type: string + description: Environment name + example: default + domain: + type: object + properties: + id: + type: string + format: uuid + description: Domain ID + name: + type: string + description: Domain name + settings: + type: object + properties: + active: + type: boolean + description: Sync handler status + window: + type: string + description: Sync window time (s, m, h) + example: 1m + forceprune: + type: boolean + description: Force delete elements from the API when true + AccountResponse: + type: object + properties: + _id: + type: string + format: uuid + description: Account ID + repository: + type: string + description: Git repository URL + branch: + type: string + description: Git branch + example: main + token: + type: string + description: Git token + environment: + type: string + description: Environment name + example: default + domain: + type: object + properties: + id: + type: string + format: uuid + description: Domain ID + name: + type: string + description: Domain name + version: + type: string + description: Domain version + lastcommit: + type: string + description: Last respository commit hash + lastupdate: + type: string + description: Last respository commit date + status: + type: string + description: Sync status + enum: [ "Pending", "Synced", "OutSync", "Error" ] + message: + type: string + description: Sync last message + settings: + type: object + properties: + active: + type: boolean + description: Sync handler status + window: + type: string + description: Sync window time (s, m, h) + example: 1m + forceprune: + type: boolean + description: Force delete elements from the API when true + ErrorResponse: + type: object + properties: + error: + type: string \ No newline at end of file diff --git a/src/controller/account.go b/src/controller/account.go index 06755f5..f729513 100644 --- a/src/controller/account.go +++ b/src/controller/account.go @@ -41,6 +41,8 @@ func (controller *AccountController) RegisterRoutes(r *mux.Router) http.Handler } func (controller *AccountController) CreateAccountHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + var accountRequest model.Account err := json.NewDecoder(r.Body).Decode(&accountRequest) if err != nil { @@ -69,6 +71,8 @@ func (controller *AccountController) CreateAccountHandler(w http.ResponseWriter, } func (controller *AccountController) FetchAccountHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + domainId := mux.Vars(r)["domainId"] enviroment := mux.Vars(r)["enviroment"] @@ -84,6 +88,8 @@ func (controller *AccountController) FetchAccountHandler(w http.ResponseWriter, } func (controller *AccountController) FetchAllAccountsByDomainIdHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + domainId := mux.Vars(r)["domainId"] accounts := controller.accountRepository.FetchAllByDomainId(domainId) @@ -103,6 +109,8 @@ func (controller *AccountController) FetchAllAccountsByDomainIdHandler(w http.Re } func (controller *AccountController) UpdateAccountHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + var accountRequest model.Account err := json.NewDecoder(r.Body).Decode(&accountRequest) if err != nil { @@ -128,6 +136,8 @@ func (controller *AccountController) UpdateAccountHandler(w http.ResponseWriter, } func (controller *AccountController) DeleteAccountHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + domainId := mux.Vars(r)["domainId"] enviroment := mux.Vars(r)["enviroment"] diff --git a/src/controller/api.go b/src/controller/api.go index 5b4af19..2aabd61 100644 --- a/src/controller/api.go +++ b/src/controller/api.go @@ -13,10 +13,11 @@ import ( type ApiController struct { coreHandler *core.CoreHandler routeCheckApiPath string + routeApiDocsPath string } type ApiCheckResponse struct { - Status string `json:"message"` + Status string `json:"status"` Version string `json:"version"` ReleaseTime string `json:"release_time"` ApiSettings ApiSettingsResponse `json:"api_settings"` @@ -34,16 +35,25 @@ func NewApiController(coreHandler *core.CoreHandler) *ApiController { return &ApiController{ coreHandler: coreHandler, routeCheckApiPath: "/api/check", + routeApiDocsPath: "/api/docs", } } +func ConfigureHeaders(w http.ResponseWriter) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE") +} + func (controller *ApiController) RegisterRoutes(r *mux.Router) http.Handler { r.NewRoute().Path(controller.routeCheckApiPath).Name("CheckApi").HandlerFunc(controller.CheckApiHandler).Methods(http.MethodGet) + r.NewRoute().Path(controller.routeApiDocsPath).Name("ApiDocs").HandlerFunc(controller.ApiDocsHandler).Methods(http.MethodGet) return r } func (controller *ApiController) CheckApiHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + utils.ResponseJSON(w, ApiCheckResponse{ Status: "All good", Version: "1.0.1", @@ -57,3 +67,10 @@ func (controller *ApiController) CheckApiHandler(w http.ResponseWriter, r *http. }, }, http.StatusOK) } + +func (controller *ApiController) ApiDocsHandler(w http.ResponseWriter, r *http.Request) { + ConfigureHeaders(w) + + w.WriteHeader(http.StatusOK) + http.ServeFile(w, r, "resources/swagger.yaml") +} diff --git a/src/controller/api_test.go b/src/controller/api_test.go index e6fa547..a77ae94 100644 --- a/src/controller/api_test.go +++ b/src/controller/api_test.go @@ -14,3 +14,9 @@ func TestCheckApiHandler(t *testing.T) { assert.Equal(t, http.StatusOK, response.Code) assert.Contains(t, response.Body.String(), "All good") } + +func TestApiDocsHandler(t *testing.T) { + req, _ := http.NewRequest(http.MethodGet, "/api/docs", nil) + response := executeRequest(req) + assert.Equal(t, http.StatusOK, response.Code) +}