From b6eb4f1e331ebdff4560f2bebe44f901c1b55413 Mon Sep 17 00:00:00 2001 From: Adam Gulczynski Date: Tue, 25 Jul 2023 22:40:16 +0200 Subject: [PATCH] add API docs using swagger(#68) --- api/employer.go | 71 ++- api/employer_test.go | 12 +- api/job.go | 87 +++ api/job_test.go | 14 +- api/server.go | 58 +- api/user.go | 69 +- api/user_test.go | 12 +- docs/docs.go | 1433 ++++++++++++++++++++++++++++++++++++++++++ docs/swagger.json | 1404 +++++++++++++++++++++++++++++++++++++++++ docs/swagger.yaml | 937 +++++++++++++++++++++++++++ go.mod | 21 +- go.sum | 78 +++ main.go | 4 + 13 files changed, 4153 insertions(+), 47 deletions(-) create mode 100644 docs/docs.go create mode 100644 docs/swagger.json create mode 100644 docs/swagger.yaml diff --git a/api/employer.go b/api/employer.go index 7cde0ca..89d0465 100644 --- a/api/employer.go +++ b/api/employer.go @@ -48,7 +48,19 @@ func newEmployerResponse(employer db.Employer, company db.Company) employerRespo } } -// createEmployer handles creation of an employer +// @Schemes +// @Summary Create employer +// @Description Create a new employer +// @Tags employers +// @Accept json +// @Produce json +// @param CreateEmployerRequest body createEmployerRequest true "Employer and company details" +// @Success 201 {object} employerResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 403 {object} ErrorResponse "Company with given name or employer with given email already exists" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /employers [post] +// createEmployer handles creating a new employer func (server *Server) createEmployer(ctx *gin.Context) { var request createEmployerRequest if err := ctx.ShouldBindJSON(&request); err != nil { @@ -119,6 +131,19 @@ type loginEmployerResponse struct { Employer employerResponse `json:"employer"` } +// @Schemes +// @Summary Login employer +// @Description Login an employer +// @Tags employers +// @Accept json +// @Produce json +// @param LoginEmployerRequest body loginEmployerRequest true "Employer credentials" +// @Success 200 {object} loginEmployerResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 404 {object} ErrorResponse "Employer with given email or company with given id does not exist" +// @Failure 401 {object} ErrorResponse "Incorrect password" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /employers/login [post] // loginEmployer handles login of an employer func (server *Server) loginEmployer(ctx *gin.Context) { var request loginEmployerRequest @@ -175,6 +200,14 @@ func (server *Server) loginEmployer(ctx *gin.Context) { ctx.JSON(http.StatusOK, res) } +// @Schemes +// @Summary Get employer +// @Description Get the details of the authenticated employer +// @Tags employers +// @Produce json +// @Success 200 {object} employerResponse +// @Failure 500 {object} ErrorResponse "Internal error" +// @Router /employers [get] // getEmployer get details of the authenticated employer func (server *Server) getEmployer(ctx *gin.Context) { authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) @@ -201,6 +234,17 @@ type updateEmployerRequest struct { CompanyLocation string `json:"company_location"` } +// @Schemes +// @Summary Update employer +// @Description Update the details of the authenticated employer +// @Tags employers +// @Accept json +// @Produce json +// @param UpdateEmployerRequest body updateEmployerRequest true "Employer details to update" +// @Success 200 {object} employerResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /employers [patch] // updateEmployer handles update of an employer details func (server *Server) updateEmployer(ctx *gin.Context) { var request updateEmployerRequest @@ -295,6 +339,22 @@ type updateEmployerPasswordRequest struct { NewPassword string `json:"new_password" binding:"required,min=6"` } +type updateEmployerPasswordResponse struct { + Message string `json:"message"` +} + +// @Schemes +// @Summary Update employer password +// @Description Update/change logged-in employer password +// @Tags employers +// @Accept json +// @Produce json +// @param UpdateEmployerPasswordRequest body updateEmployerPasswordRequest true "Employer old and new password" +// @Success 200 {object} updateEmployerPasswordResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 401 {object} ErrorResponse "Incorrect password" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /employers/password [patch] // updateEmployerPassword handles user password update func (server *Server) updateEmployerPassword(ctx *gin.Context) { var request updateEmployerPasswordRequest @@ -334,9 +394,16 @@ func (server *Server) updateEmployerPassword(ctx *gin.Context) { return } - ctx.JSON(http.StatusOK, gin.H{"message": "password updated successfully"}) + ctx.JSON(http.StatusOK, updateEmployerPasswordResponse{"password updated successfully"}) } +// @Schemes +// @Summary Delete employer +// @Description Delete the logged-in employer +// @Tags employers +// @Success 204 {null} null +// @Failure 500 {object} ErrorResponse "Any error" +// @Router /employers [delete] // deleteEmployer handles deleting employer func (server *Server) deleteEmployer(ctx *gin.Context) { authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) diff --git a/api/employer_test.go b/api/employer_test.go index e14178d..0ea417c 100644 --- a/api/employer_test.go +++ b/api/employer_test.go @@ -215,7 +215,7 @@ func TestCreateEmployerAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/employers" + url := "/api/v1/employers" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) require.NoError(t, err) @@ -405,7 +405,7 @@ func TestLoginEmployerAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/employers/login" + url := "/api/v1/employers/login" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) require.NoError(t, err) @@ -496,7 +496,7 @@ func TestGetEmployerAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/employers" + url := "/api/v1/employers" req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) @@ -755,7 +755,7 @@ func TestUpdateEmployerAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/employers" + url := "/api/v1/employers" req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data)) require.NoError(t, err) @@ -928,7 +928,7 @@ func TestUpdateEmployerPasswordAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/employers/password" + url := "/api/v1/employers/password" req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data)) require.NoError(t, err) @@ -1053,7 +1053,7 @@ func TestDeleteEmployerAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/employers" + url := "/api/v1/employers" req, err := http.NewRequest(http.MethodDelete, url, nil) require.NoError(t, err) diff --git a/api/job.go b/api/job.go index 1dd5512..d30d826 100644 --- a/api/job.go +++ b/api/job.go @@ -54,6 +54,17 @@ type createJobRequest struct { RequiredSkills []string `json:"required_skills" binding:"required"` } +// @Schemes +// @Summary Create job +// @Description Create a new job +// @Tags jobs +// @Accept json +// @Produce json +// @param CreateJobRequest body createJobRequest true "Job details" +// @Success 201 {object} jobResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs [post] // createJob handles creating a job posting - job with job skills func (server *Server) createJob(ctx *gin.Context) { var request createJobRequest @@ -118,6 +129,14 @@ type deleteJobRequest struct { ID int32 `uri:"id" binding:"required,min=1"` } +// @Schemes +// @Summary Delete job +// @Description Delete the job with the given id +// @Tags jobs +// @param id path integer true "Job ID" +// @Success 204 {null} null +// @Failure 500 {object} ErrorResponse "Any error" +// @Router /jobs/{id} [delete] // deleteJob handles deleting a job posting func (server *Server) deleteJob(ctx *gin.Context) { var request deleteJobRequest @@ -172,6 +191,20 @@ type updateJobRequest struct { RequiredSkillIDsToRemove []int32 `json:"required_skill_ids_to_remove"` } +// @Schemes +// @Summary Update job +// @Description update the job with the given id +// @Tags jobs +// @Param id path integer true "Job ID" +// @Param UpdateJobRequest body updateJobRequest true "Job details to update" +// @Accept json +// @Produce json +// @Success 200 {object} jobResponse +// @Failure 400 {object} ErrorResponse "Invalid request query or body" +// @Failure 401 {object} ErrorResponse "User making the request not an employer or employer not the owner of the job" +// @Failure 404 {object} ErrorResponse "Job not found" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs/{id} [patch] // updateJob handles updating a job posting - job and job skills func (server *Server) updateJob(ctx *gin.Context) { // job ID @@ -305,6 +338,17 @@ type getJobRequest struct { ID int32 `uri:"id" binding:"required,min=1"` } +// @Schemes +// @Summary Get job +// @Description Get details of the job with the given id +// @Tags jobs +// @Param id path integer true "Job ID" +// @Produce json +// @Success 200 {object} jobResponse +// @Failure 400 {object} ErrorResponse "Invalid request query" +// @Failure 404 {object} ErrorResponse "Job not found" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs/{id} [get] // getJob handles getting a job posting with all details // without job skills - these are fetched separately // to allow for the client to get paginated job skills. @@ -338,6 +382,23 @@ type filterAndListJobs struct { PageSize int32 `form:"page_size" binding:"required,min=5,max=15"` } +// @Schemes +// @Summary Filter and list jobs +// @Description Filter and list jobs +// @Tags jobs +// @Param page query integer true "Page number" +// @Param page_size query integer true "Page size" +// @Param title query string false "Job title - matches partially (ILIKE)" +// @Param industry query string false "Job industry - exact name" +// @Param job_location query string false "Job location - exact name" +// @Param salary_min query integer false "Salary min - must be smaller or equal salary_max" +// @Param salary_max query integer false "Salary max - must be greater or equal salary_min" +// @Produce json +// @Success 200 {array} []db.ListJobsByFiltersRow +// @Failure 400 {object} ErrorResponse "Invalid query" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs [get] +// filterAndListJobs handles filtering and listing jobs func (server *Server) filterAndListJobs(ctx *gin.Context) { var request filterAndListJobs if err := ctx.ShouldBindQuery(&request); err != nil { @@ -384,6 +445,18 @@ type listJobsByMatchingSkillsRequest struct { PageSize int32 `form:"page_size" binding:"required,min=5,max=15"` } +// @Schemes +// @Summary List jobs by matching skills +// @Description List jobs that match the authenticated users skills +// @Tags jobs +// @Param page query integer true "Page number" +// @Param page_size query integer true "Page size" +// @Produce json +// @Success 200 {array} []db.ListJobsMatchingUserSkillsRow +// @Failure 400 {object} ErrorResponse "Invalid query" +// @Failure 401 {object} ErrorResponse "Employer making the request - only users can access" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs/match-skills [get] // listJobsByMatchingSkills handles listing all jobs // that skills match the users skills. func (server *Server) listJobsByMatchingSkills(ctx *gin.Context) { @@ -429,6 +502,20 @@ type listJobsByCompanyRequest struct { PageSize int32 `form:"page_size" binding:"required,min=5,max=15"` } +// @Schemes +// @Summary List jobs by company +// @Description List jobs by company name, id or part of the name. +// @Tags jobs +// @Param page query integer true "Page number" +// @Param page_size query integer true "Page size" +// @Param id query integer false "Company ID" +// @Param name query string false "Company name" +// @Param name_contains query string false "Part of the company name" +// @Produce json +// @Success 200 {array} []db.ListJobsByCompanyNameRow +// @Failure 400 {object} ErrorResponse "Invalid query. Only one of the three parameters is allowed." +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /jobs/company [get] // listJobsByCompany handles listing jobs by company. // Required parameters: // - page (page number) diff --git a/api/job_test.go b/api/job_test.go index 341958a..163d8d5 100644 --- a/api/job_test.go +++ b/api/job_test.go @@ -299,7 +299,7 @@ func TestCreateJobAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/jobs" + url := "/api/v1/jobs" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) require.NoError(t, err) @@ -482,7 +482,7 @@ func TestDeleteJobAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := fmt.Sprintf("/jobs/%d", tc.jobID) + url := fmt.Sprintf("/api/v1/jobs/%d", tc.jobID) req, err := http.NewRequest(http.MethodDelete, url, nil) require.NoError(t, err) @@ -594,7 +594,7 @@ func TestGetJobAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := fmt.Sprintf("/jobs/%d", tc.jobID) + url := fmt.Sprintf("/api/v1/jobs/%d", tc.jobID) req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) @@ -811,7 +811,7 @@ func TestFilterAndListJobsAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/jobs" + url := "/api/v1/jobs" req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) @@ -1074,7 +1074,7 @@ func TestListJobsByMatchingSkillsAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/jobs/match-skills" + url := "/api/v1/jobs/match-skills" req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) @@ -1603,7 +1603,7 @@ func TestUpdateJobAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := fmt.Sprintf("/jobs/%d", tc.jobID) + url := fmt.Sprintf("/api/v1/jobs/%d", tc.jobID) req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data)) require.NoError(t, err) @@ -1954,7 +1954,7 @@ func TestListJobsByCompanyAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/jobs/company" + url := "/api/v1/jobs/company" req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) diff --git a/api/server.go b/api/server.go index 63e6b45..d8103a0 100644 --- a/api/server.go +++ b/api/server.go @@ -3,10 +3,13 @@ package api import ( "fmt" db "github.com/aalug/go-gin-job-search/db/sqlc" + "github.com/aalug/go-gin-job-search/docs" "github.com/aalug/go-gin-job-search/token" "github.com/aalug/go-gin-job-search/utils" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" + swaggerfiles "github.com/swaggo/files" + ginSwagger "github.com/swaggo/gin-swagger" ) // Server serves HTTP requests for the service @@ -38,47 +41,54 @@ func NewServer(config utils.Config, store db.Store) (*Server, error) { func (server *Server) setupRouter() { router := gin.Default() + routerV1 := router.Group("/api/v1") + + // CORS corsConfig := cors.DefaultConfig() corsConfig.AllowAllOrigins = true corsConfig.AllowHeaders = append(corsConfig.AllowHeaders, "Authorization") router.Use(cors.New(corsConfig)) + // Swagger docs + router.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerfiles.Handler)) + docs.SwaggerInfo.BasePath = "/api/v1" + // === users === - router.POST("/users", server.createUser) - router.POST("/users/login", server.loginUser) + routerV1.POST("/users", server.createUser) + routerV1.POST("/users/login", server.loginUser) // === employers === - router.POST("/employers", server.createEmployer) - router.POST("/employers/login", server.loginEmployer) + routerV1.POST("/employers", server.createEmployer) + routerV1.POST("/employers/login", server.loginEmployer) // === jobs === - router.GET("/jobs/:id", server.getJob) - router.GET("/jobs", server.filterAndListJobs) - router.GET("/jobs/company", server.listJobsByCompany) + routerV1.GET("/jobs/:id", server.getJob) + routerV1.GET("/jobs", server.filterAndListJobs) + routerV1.GET("/jobs/company", server.listJobsByCompany) // ===== routes that require authentication ===== - authRoutes := router.Group("/").Use(authMiddleware(server.tokenMaker)) + authRoutesV1 := routerV1.Group("/").Use(authMiddleware(server.tokenMaker)) // === users === - authRoutes.GET("/users", server.getUser) - authRoutes.PATCH("/users", server.updateUser) - authRoutes.PATCH("/users/password", server.updateUserPassword) - authRoutes.DELETE("/users", server.deleteUser) + authRoutesV1.GET("/users", server.getUser) + authRoutesV1.PATCH("/users", server.updateUser) + authRoutesV1.PATCH("/users/password", server.updateUserPassword) + authRoutesV1.DELETE("/users", server.deleteUser) // === employers === - authRoutes.GET("/employers", server.getEmployer) - authRoutes.PATCH("/employers", server.updateEmployer) - authRoutes.PATCH("/employers/password", server.updateEmployerPassword) - authRoutes.DELETE("/employers", server.deleteEmployer) + authRoutesV1.GET("/employers", server.getEmployer) + authRoutesV1.PATCH("/employers", server.updateEmployer) + authRoutesV1.PATCH("/employers/password", server.updateEmployerPassword) + authRoutesV1.DELETE("/employers", server.deleteEmployer) // === jobs === // for employers, jobs CRUD - authRoutes.POST("/jobs", server.createJob) - authRoutes.DELETE("/jobs/:id", server.deleteJob) - authRoutes.PATCH("/jobs/:id", server.updateJob) + authRoutesV1.POST("/jobs", server.createJob) + authRoutesV1.DELETE("/jobs/:id", server.deleteJob) + authRoutesV1.PATCH("/jobs/:id", server.updateJob) // for users, listing jobs that use user details - authRoutes.GET("/jobs/match-skills", server.listJobsByMatchingSkills) + authRoutesV1.GET("/jobs/match-skills", server.listJobsByMatchingSkills) server.router = router } @@ -88,6 +98,10 @@ func (server *Server) Start(address string) error { return server.router.Run(address) } -func errorResponse(err error) gin.H { - return gin.H{"error": err.Error()} +type ErrorResponse struct { + Error string `json:"error"` +} + +func errorResponse(err error) ErrorResponse { + return ErrorResponse{Error: err.Error()} } diff --git a/api/user.go b/api/user.go index b41f805..fd1b8e6 100644 --- a/api/user.go +++ b/api/user.go @@ -74,6 +74,18 @@ func newUserResponse(user db.User, skills []db.UserSkill) userResponse { } } +// @Schemes +// @Summary Create user +// @Description Create a new user +// @Tags users +// @Accept json +// @Produce json +// @param CreateUserRequest body createUserRequest true "User details" +// @Success 201 {object} userResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 403 {object} ErrorResponse "User with given email already exists" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /users [post] // createUser creates a new user func (server *Server) createUser(ctx *gin.Context) { var request createUserRequest @@ -157,6 +169,19 @@ type loginUserResponse struct { User userResponse `json:"user"` } +// @Schemes +// @Summary Login user +// @Description Login user +// @Tags users +// @Accept json +// @Produce json +// @param LoginUserRequest body loginUserRequest true "User credentials" +// @Success 200 {object} loginUserResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 401 {object} ErrorResponse "Incorrect password" +// @Failure 404 {object} ErrorResponse "User with given email does not exist" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /users/login [post] // loginUser handles user login func (server *Server) loginUser(ctx *gin.Context) { var request loginUserRequest @@ -209,6 +234,14 @@ func (server *Server) loginUser(ctx *gin.Context) { ctx.JSON(http.StatusOK, res) } +// @Schemes +// @Summary Get user +// @Description Get details of the logged in user +// @Tags users +// @Produce json +// @Success 200 {object} userResponse +// @Failure 500 {object} ErrorResponse "Any error" +// @Router /users [get] // getUser handles getting user details func (server *Server) getUser(ctx *gin.Context) { authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) @@ -235,6 +268,17 @@ type updateUserRequest struct { SkillsToRemove []int32 `json:"skill_ids_to_remove"` } +// @Schemes +// @Summary Update user +// @Description Update the logged-in user details +// @Tags users +// @Accept json +// @Produce json +// @param UpdateUserRequest body updateUserRequest true "User details to update" +// @Success 200 {object} userResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /users [patch] // updateUser handles user update func (server *Server) updateUser(ctx *gin.Context) { var request updateUserRequest @@ -360,6 +404,22 @@ type updateUserPasswordRequest struct { NewPassword string `json:"new_password" binding:"required,min=6"` } +type updateUserPasswordResponse struct { + Message string `json:"message"` +} + +// @Schemes +// @Summary Update user password +// @Description Change / update password of the logged-in user +// @Tags users +// @Accept json +// @Produce json +// @param UpdateUserPasswordRequest body updateUserPasswordRequest true "Users old and new password" +// @Success 200 {object} updateUserPasswordResponse +// @Failure 400 {object} ErrorResponse "Invalid request body" +// @Failure 401 {object} ErrorResponse "Incorrect password" +// @Failure 500 {object} ErrorResponse "Any other error" +// @Router /users/password [patch] // updateUserPassword handles user password update func (server *Server) updateUserPassword(ctx *gin.Context) { var request updateUserPasswordRequest @@ -399,9 +459,16 @@ func (server *Server) updateUserPassword(ctx *gin.Context) { return } - ctx.JSON(http.StatusOK, gin.H{"message": "password updated successfully"}) + ctx.JSON(http.StatusOK, updateUserPasswordResponse{Message: "password updated successfully"}) } +// @Schemes +// @Summary Delete user +// @Description Delete the logged-in user +// @Tags users +// @Success 204 {null} null +// @Failure 500 {object} ErrorResponse "Any error" +// @Router /users [delete] // deleteUser handles deleting users func (server *Server) deleteUser(ctx *gin.Context) { authPayload := ctx.MustGet(authorizationPayloadKey).(*token.Payload) diff --git a/api/user_test.go b/api/user_test.go index c4ec56c..468e014 100644 --- a/api/user_test.go +++ b/api/user_test.go @@ -285,7 +285,7 @@ func TestCreateUserAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/users" + url := "/api/v1/users" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) require.NoError(t, err) @@ -462,7 +462,7 @@ func TestLoginUserAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/users/login" + url := "/api/v1/users/login" req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader(data)) require.NoError(t, err) @@ -527,7 +527,7 @@ func TestGetUserAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/users" + url := "/api/v1/users" req, err := http.NewRequest(http.MethodGet, url, nil) require.NoError(t, err) @@ -913,7 +913,7 @@ func TestUpdateUserAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/users" + url := "/api/v1/users" req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data)) require.NoError(t, err) @@ -1086,7 +1086,7 @@ func TestUpdateUserPasswordAPI(t *testing.T) { data, err := json.Marshal(tc.body) require.NoError(t, err) - url := "/users/password" + url := "/api/v1/users/password" req, err := http.NewRequest(http.MethodPatch, url, bytes.NewReader(data)) require.NoError(t, err) @@ -1210,7 +1210,7 @@ func TestDeleteUserAPI(t *testing.T) { server := newTestServer(t, store) recorder := httptest.NewRecorder() - url := "/users" + url := "/api/v1/users" req, err := http.NewRequest(http.MethodDelete, url, nil) require.NoError(t, err) diff --git a/docs/docs.go b/docs/docs.go new file mode 100644 index 0000000..b3d794a --- /dev/null +++ b/docs/docs.go @@ -0,0 +1,1433 @@ +// Code generated by swaggo/swag. DO NOT EDIT. + +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": { + "name": "aalug", + "url": "https://github.com/aalug", + "email": "a.a.gulczynski@gmail.com" + }, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/employers": { + "get": { + "description": "Get the details of the authenticated employer", + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Get employer", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "500": { + "description": "Internal error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Create employer", + "parameters": [ + { + "description": "Employer and company details", + "name": "CreateEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createEmployerRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "403": { + "description": "Company with given name or employer with given email already exists", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the logged-in employer", + "tags": [ + "employers" + ], + "summary": "Delete employer", + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "Update the details of the authenticated employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Update employer", + "parameters": [ + { + "description": "Employer details to update", + "name": "UpdateEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateEmployerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/employers/login": { + "post": { + "description": "Login an employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Login employer", + "parameters": [ + { + "description": "Employer credentials", + "name": "LoginEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.loginEmployerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.loginEmployerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Employer with given email or company with given id does not exist", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/employers/password": { + "patch": { + "description": "Update/change logged-in employer password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Update employer password", + "parameters": [ + { + "description": "Employer old and new password", + "name": "UpdateEmployerPasswordRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateEmployerPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.updateEmployerPasswordResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs": { + "get": { + "description": "Filter and list jobs", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Filter and list jobs", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Job title - matches partially (ILIKE)", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "Job industry - exact name", + "name": "industry", + "in": "query" + }, + { + "type": "string", + "description": "Job location - exact name", + "name": "job_location", + "in": "query" + }, + { + "type": "integer", + "description": "Salary min - must be smaller than salary_max", + "name": "salary_min", + "in": "query" + }, + { + "type": "integer", + "description": "Salary max - must be greater than salary_min", + "name": "salary_max", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobsByFiltersRow" + } + } + } + }, + "400": { + "description": "Invalid query", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new job", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Create job", + "parameters": [ + { + "description": "Job details", + "name": "CreateJobRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createJobRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs/company": { + "get": { + "description": "List jobs by company name, id or part of the name.", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "List jobs by company", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "Company name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "Part of the company name", + "name": "name_contains", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobsByCompanyNameRow" + } + } + } + }, + "400": { + "description": "Invalid query. Only one of the three parameters is allowed.", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs/{id}": { + "get": { + "description": "Get details of the job with the given id", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Get job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request query", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Job not found", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the job with the given id", + "tags": [ + "jobs" + ], + "summary": "Delete job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "update the job with the given id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Update job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Job details to update", + "name": "UpdateJobRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateJobRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request query or body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "User making the request not an employer or employer not the owner of the job", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Job not found", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users": { + "get": { + "description": "Get details of the logged in user", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get user", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Create user", + "parameters": [ + { + "description": "User details", + "name": "CreateUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createUserRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "403": { + "description": "User with given email already exists", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the logged-in user", + "tags": [ + "users" + ], + "summary": "Delete user", + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "Update the logged-in user details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Update user", + "parameters": [ + { + "description": "User details to update", + "name": "UpdateUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateUserRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users/login": { + "post": { + "description": "Login user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Login user", + "parameters": [ + { + "description": "User credentials", + "name": "LoginUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.loginUserRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.loginUserResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "User with given email does not exist", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users/password": { + "patch": { + "description": "Change / update password of the logged-in user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Update user password", + "parameters": [ + { + "description": "Users old and new password", + "name": "UpdateUserPasswordRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateUserPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.updateUserPasswordResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "api.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, + "api.Skill": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "skill": { + "type": "string" + }, + "years_of_experience": { + "type": "integer" + } + } + }, + "api.createEmployerRequest": { + "type": "object", + "required": [ + "company_industry", + "company_location", + "company_name", + "email", + "full_name", + "password" + ], + "properties": { + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.createJobRequest": { + "type": "object", + "required": [ + "description", + "industry", + "location", + "required_skills", + "requirements", + "salary_max", + "salary_min", + "title" + ], + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skills": { + "type": "array", + "items": { + "type": "string" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer", + "minimum": 0 + }, + "salary_min": { + "type": "integer", + "minimum": 0 + }, + "title": { + "type": "string" + } + } + }, + "api.createUserRequest": { + "type": "object", + "required": [ + "desired_industry", + "desired_job_title", + "desired_salary_max", + "desired_salary_min", + "email", + "full_name", + "location", + "password" + ], + "properties": { + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer", + "minimum": 0 + }, + "desired_salary_min": { + "type": "integer", + "minimum": 0 + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + }, + "skills": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + }, + "skills_description": { + "type": "string" + } + } + }, + "api.employerResponse": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "employer_created_at": { + "type": "string" + }, + "employer_id": { + "type": "integer" + }, + "full_name": { + "type": "string" + } + } + }, + "api.jobResponse": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skills": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobSkillsByJobIDRow" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "api.loginEmployerRequest": { + "type": "object", + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.loginEmployerResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "employer": { + "$ref": "#/definitions/api.employerResponse" + } + } + }, + "api.loginUserRequest": { + "type": "object", + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.loginUserResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/api.userResponse" + } + } + }, + "api.updateEmployerPasswordRequest": { + "type": "object", + "required": [ + "new_password", + "old_password" + ], + "properties": { + "new_password": { + "type": "string", + "minLength": 6 + }, + "old_password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.updateEmployerPasswordResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api.updateEmployerRequest": { + "type": "object", + "properties": { + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "full_name": { + "type": "string" + } + } + }, + "api.updateJobRequest": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skill_ids_to_remove": { + "type": "array", + "items": { + "type": "integer" + } + }, + "required_skills_to_add": { + "type": "array", + "items": { + "type": "string" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "api.updateUserPasswordRequest": { + "type": "object", + "required": [ + "new_password", + "old_password" + ], + "properties": { + "new_password": { + "type": "string", + "minLength": 6 + }, + "old_password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.updateUserPasswordResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api.updateUserRequest": { + "type": "object", + "properties": { + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer" + }, + "desired_salary_min": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skill_ids_to_remove": { + "type": "array", + "items": { + "type": "integer" + } + }, + "skills_description": { + "type": "string" + }, + "skills_to_add": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + } + } + }, + "api.userResponse": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer" + }, + "desired_salary_min": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skills": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + }, + "skills_description": { + "type": "string" + } + } + }, + "db.ListJobSkillsByJobIDRow": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "skill": { + "type": "string" + } + } + }, + "db.ListJobsByCompanyNameRow": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "db.ListJobsByFiltersRow": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "/api/v1", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/docs/swagger.json b/docs/swagger.json new file mode 100644 index 0000000..e83bea7 --- /dev/null +++ b/docs/swagger.json @@ -0,0 +1,1404 @@ +{ + "swagger": "2.0", + "info": { + "contact": { + "name": "aalug", + "url": "https://github.com/aalug", + "email": "a.a.gulczynski@gmail.com" + } + }, + "basePath": "/api/v1", + "paths": { + "/employers": { + "get": { + "description": "Get the details of the authenticated employer", + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Get employer", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "500": { + "description": "Internal error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Create employer", + "parameters": [ + { + "description": "Employer and company details", + "name": "CreateEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createEmployerRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "403": { + "description": "Company with given name or employer with given email already exists", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the logged-in employer", + "tags": [ + "employers" + ], + "summary": "Delete employer", + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "Update the details of the authenticated employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Update employer", + "parameters": [ + { + "description": "Employer details to update", + "name": "UpdateEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateEmployerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.employerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/employers/login": { + "post": { + "description": "Login an employer", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Login employer", + "parameters": [ + { + "description": "Employer credentials", + "name": "LoginEmployerRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.loginEmployerRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.loginEmployerResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Employer with given email or company with given id does not exist", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/employers/password": { + "patch": { + "description": "Update/change logged-in employer password", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "employers" + ], + "summary": "Update employer password", + "parameters": [ + { + "description": "Employer old and new password", + "name": "UpdateEmployerPasswordRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateEmployerPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.updateEmployerPasswordResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs": { + "get": { + "description": "Filter and list jobs", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Filter and list jobs", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Job title - matches partially (ILIKE)", + "name": "title", + "in": "query" + }, + { + "type": "string", + "description": "Job industry - exact name", + "name": "industry", + "in": "query" + }, + { + "type": "string", + "description": "Job location - exact name", + "name": "job_location", + "in": "query" + }, + { + "type": "integer", + "description": "Salary min - must be smaller than salary_max", + "name": "salary_min", + "in": "query" + }, + { + "type": "integer", + "description": "Salary max - must be greater than salary_min", + "name": "salary_max", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobsByFiltersRow" + } + } + } + }, + "400": { + "description": "Invalid query", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new job", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Create job", + "parameters": [ + { + "description": "Job details", + "name": "CreateJobRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createJobRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs/company": { + "get": { + "description": "List jobs by company name, id or part of the name.", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "List jobs by company", + "parameters": [ + { + "type": "integer", + "description": "Page number", + "name": "page", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Page size", + "name": "page_size", + "in": "query", + "required": true + }, + { + "type": "integer", + "description": "Company ID", + "name": "id", + "in": "query" + }, + { + "type": "string", + "description": "Company name", + "name": "name", + "in": "query" + }, + { + "type": "string", + "description": "Part of the company name", + "name": "name_contains", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobsByCompanyNameRow" + } + } + } + }, + "400": { + "description": "Invalid query. Only one of the three parameters is allowed.", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/jobs/{id}": { + "get": { + "description": "Get details of the job with the given id", + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Get job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request query", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Job not found", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the job with the given id", + "tags": [ + "jobs" + ], + "summary": "Delete job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "update the job with the given id", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "jobs" + ], + "summary": "Update job", + "parameters": [ + { + "type": "integer", + "description": "Job ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Job details to update", + "name": "UpdateJobRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateJobRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.jobResponse" + } + }, + "400": { + "description": "Invalid request query or body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "User making the request not an employer or employer not the owner of the job", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "Job not found", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users": { + "get": { + "description": "Get details of the logged in user", + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Get user", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "post": { + "description": "Create a new user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Create user", + "parameters": [ + { + "description": "User details", + "name": "CreateUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.createUserRequest" + } + } + ], + "responses": { + "201": { + "description": "Created", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "403": { + "description": "User with given email already exists", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "delete": { + "description": "Delete the logged-in user", + "tags": [ + "users" + ], + "summary": "Delete user", + "responses": { + "204": { + "description": "No Content", + "schema": { + "type": "null" + } + }, + "500": { + "description": "Any error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + }, + "patch": { + "description": "Update the logged-in user details", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Update user", + "parameters": [ + { + "description": "User details to update", + "name": "UpdateUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateUserRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.userResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users/login": { + "post": { + "description": "Login user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Login user", + "parameters": [ + { + "description": "User credentials", + "name": "LoginUserRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.loginUserRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.loginUserResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "404": { + "description": "User with given email does not exist", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + }, + "/users/password": { + "patch": { + "description": "Change / update password of the logged-in user", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "users" + ], + "summary": "Update user password", + "parameters": [ + { + "description": "Users old and new password", + "name": "UpdateUserPasswordRequest", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/api.updateUserPasswordRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/api.updateUserPasswordResponse" + } + }, + "400": { + "description": "Invalid request body", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "401": { + "description": "Incorrect password", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + }, + "500": { + "description": "Any other error", + "schema": { + "$ref": "#/definitions/api.ErrorResponse" + } + } + } + } + } + }, + "definitions": { + "api.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, + "api.Skill": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "skill": { + "type": "string" + }, + "years_of_experience": { + "type": "integer" + } + } + }, + "api.createEmployerRequest": { + "type": "object", + "required": [ + "company_industry", + "company_location", + "company_name", + "email", + "full_name", + "password" + ], + "properties": { + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.createJobRequest": { + "type": "object", + "required": [ + "description", + "industry", + "location", + "required_skills", + "requirements", + "salary_max", + "salary_min", + "title" + ], + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skills": { + "type": "array", + "items": { + "type": "string" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer", + "minimum": 0 + }, + "salary_min": { + "type": "integer", + "minimum": 0 + }, + "title": { + "type": "string" + } + } + }, + "api.createUserRequest": { + "type": "object", + "required": [ + "desired_industry", + "desired_job_title", + "desired_salary_max", + "desired_salary_min", + "email", + "full_name", + "location", + "password" + ], + "properties": { + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer", + "minimum": 0 + }, + "desired_salary_min": { + "type": "integer", + "minimum": 0 + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + }, + "skills": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + }, + "skills_description": { + "type": "string" + } + } + }, + "api.employerResponse": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "employer_created_at": { + "type": "string" + }, + "employer_id": { + "type": "integer" + }, + "full_name": { + "type": "string" + } + } + }, + "api.jobResponse": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skills": { + "type": "array", + "items": { + "$ref": "#/definitions/db.ListJobSkillsByJobIDRow" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "api.loginEmployerRequest": { + "type": "object", + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.loginEmployerResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "employer": { + "$ref": "#/definitions/api.employerResponse" + } + } + }, + "api.loginUserRequest": { + "type": "object", + "required": [ + "email", + "password" + ], + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.loginUserResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "user": { + "$ref": "#/definitions/api.userResponse" + } + } + }, + "api.updateEmployerPasswordRequest": { + "type": "object", + "required": [ + "new_password", + "old_password" + ], + "properties": { + "new_password": { + "type": "string", + "minLength": 6 + }, + "old_password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.updateEmployerPasswordResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api.updateEmployerRequest": { + "type": "object", + "properties": { + "company_industry": { + "type": "string" + }, + "company_location": { + "type": "string" + }, + "company_name": { + "type": "string" + }, + "email": { + "type": "string" + }, + "full_name": { + "type": "string" + } + } + }, + "api.updateJobRequest": { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "required_skill_ids_to_remove": { + "type": "array", + "items": { + "type": "integer" + } + }, + "required_skills_to_add": { + "type": "array", + "items": { + "type": "string" + } + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "api.updateUserPasswordRequest": { + "type": "object", + "required": [ + "new_password", + "old_password" + ], + "properties": { + "new_password": { + "type": "string", + "minLength": 6 + }, + "old_password": { + "type": "string", + "minLength": 6 + } + } + }, + "api.updateUserPasswordResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + }, + "api.updateUserRequest": { + "type": "object", + "properties": { + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer" + }, + "desired_salary_min": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skill_ids_to_remove": { + "type": "array", + "items": { + "type": "integer" + } + }, + "skills_description": { + "type": "string" + }, + "skills_to_add": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + } + } + }, + "api.userResponse": { + "type": "object", + "properties": { + "created_at": { + "type": "string" + }, + "desired_industry": { + "type": "string" + }, + "desired_job_title": { + "type": "string" + }, + "desired_salary_max": { + "type": "integer" + }, + "desired_salary_min": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "experience": { + "type": "string" + }, + "full_name": { + "type": "string" + }, + "location": { + "type": "string" + }, + "skills": { + "type": "array", + "items": { + "$ref": "#/definitions/api.Skill" + } + }, + "skills_description": { + "type": "string" + } + } + }, + "db.ListJobSkillsByJobIDRow": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "skill": { + "type": "string" + } + } + }, + "db.ListJobsByCompanyNameRow": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + }, + "db.ListJobsByFiltersRow": { + "type": "object", + "properties": { + "company_id": { + "type": "integer" + }, + "company_name": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "description": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "industry": { + "type": "string" + }, + "location": { + "type": "string" + }, + "requirements": { + "type": "string" + }, + "salary_max": { + "type": "integer" + }, + "salary_min": { + "type": "integer" + }, + "title": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/docs/swagger.yaml b/docs/swagger.yaml new file mode 100644 index 0000000..b350da9 --- /dev/null +++ b/docs/swagger.yaml @@ -0,0 +1,937 @@ +basePath: /api/v1 +definitions: + api.ErrorResponse: + properties: + error: + type: string + type: object + api.Skill: + properties: + id: + type: integer + skill: + type: string + years_of_experience: + type: integer + type: object + api.createEmployerRequest: + properties: + company_industry: + type: string + company_location: + type: string + company_name: + type: string + email: + type: string + full_name: + type: string + password: + minLength: 6 + type: string + required: + - company_industry + - company_location + - company_name + - email + - full_name + - password + type: object + api.createJobRequest: + properties: + description: + type: string + industry: + type: string + location: + type: string + required_skills: + items: + type: string + type: array + requirements: + type: string + salary_max: + minimum: 0 + type: integer + salary_min: + minimum: 0 + type: integer + title: + type: string + required: + - description + - industry + - location + - required_skills + - requirements + - salary_max + - salary_min + - title + type: object + api.createUserRequest: + properties: + desired_industry: + type: string + desired_job_title: + type: string + desired_salary_max: + minimum: 0 + type: integer + desired_salary_min: + minimum: 0 + type: integer + email: + type: string + experience: + type: string + full_name: + type: string + location: + type: string + password: + minLength: 6 + type: string + skills: + items: + $ref: '#/definitions/api.Skill' + type: array + skills_description: + type: string + required: + - desired_industry + - desired_job_title + - desired_salary_max + - desired_salary_min + - email + - full_name + - location + - password + type: object + api.employerResponse: + properties: + company_id: + type: integer + company_industry: + type: string + company_location: + type: string + company_name: + type: string + email: + type: string + employer_created_at: + type: string + employer_id: + type: integer + full_name: + type: string + type: object + api.jobResponse: + properties: + description: + type: string + industry: + type: string + location: + type: string + required_skills: + items: + $ref: '#/definitions/db.ListJobSkillsByJobIDRow' + type: array + requirements: + type: string + salary_max: + type: integer + salary_min: + type: integer + title: + type: string + type: object + api.loginEmployerRequest: + properties: + email: + type: string + password: + minLength: 6 + type: string + required: + - email + - password + type: object + api.loginEmployerResponse: + properties: + access_token: + type: string + employer: + $ref: '#/definitions/api.employerResponse' + type: object + api.loginUserRequest: + properties: + email: + type: string + password: + minLength: 6 + type: string + required: + - email + - password + type: object + api.loginUserResponse: + properties: + access_token: + type: string + user: + $ref: '#/definitions/api.userResponse' + type: object + api.updateEmployerPasswordRequest: + properties: + new_password: + minLength: 6 + type: string + old_password: + minLength: 6 + type: string + required: + - new_password + - old_password + type: object + api.updateEmployerPasswordResponse: + properties: + message: + type: string + type: object + api.updateEmployerRequest: + properties: + company_industry: + type: string + company_location: + type: string + company_name: + type: string + email: + type: string + full_name: + type: string + type: object + api.updateJobRequest: + properties: + description: + type: string + industry: + type: string + location: + type: string + required_skill_ids_to_remove: + items: + type: integer + type: array + required_skills_to_add: + items: + type: string + type: array + requirements: + type: string + salary_max: + type: integer + salary_min: + type: integer + title: + type: string + type: object + api.updateUserPasswordRequest: + properties: + new_password: + minLength: 6 + type: string + old_password: + minLength: 6 + type: string + required: + - new_password + - old_password + type: object + api.updateUserPasswordResponse: + properties: + message: + type: string + type: object + api.updateUserRequest: + properties: + desired_industry: + type: string + desired_job_title: + type: string + desired_salary_max: + type: integer + desired_salary_min: + type: integer + email: + type: string + experience: + type: string + full_name: + type: string + location: + type: string + skill_ids_to_remove: + items: + type: integer + type: array + skills_description: + type: string + skills_to_add: + items: + $ref: '#/definitions/api.Skill' + type: array + type: object + api.userResponse: + properties: + created_at: + type: string + desired_industry: + type: string + desired_job_title: + type: string + desired_salary_max: + type: integer + desired_salary_min: + type: integer + email: + type: string + experience: + type: string + full_name: + type: string + location: + type: string + skills: + items: + $ref: '#/definitions/api.Skill' + type: array + skills_description: + type: string + type: object + db.ListJobSkillsByJobIDRow: + properties: + id: + type: integer + skill: + type: string + type: object + db.ListJobsByCompanyNameRow: + properties: + company_id: + type: integer + company_name: + type: string + created_at: + type: string + description: + type: string + id: + type: integer + industry: + type: string + location: + type: string + requirements: + type: string + salary_max: + type: integer + salary_min: + type: integer + title: + type: string + type: object + db.ListJobsByFiltersRow: + properties: + company_id: + type: integer + company_name: + type: string + created_at: + type: string + description: + type: string + id: + type: integer + industry: + type: string + location: + type: string + requirements: + type: string + salary_max: + type: integer + salary_min: + type: integer + title: + type: string + type: object +info: + contact: + email: a.a.gulczynski@gmail.com + name: aalug + url: https://github.com/aalug +paths: + /employers: + delete: + description: Delete the logged-in employer + responses: + "204": + description: No Content + schema: + type: "null" + "500": + description: Any error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Delete employer + tags: + - employers + get: + description: Get the details of the authenticated employer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.employerResponse' + "500": + description: Internal error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Get employer + tags: + - employers + patch: + consumes: + - application/json + description: Update the details of the authenticated employer + parameters: + - description: Employer details to update + in: body + name: UpdateEmployerRequest + required: true + schema: + $ref: '#/definitions/api.updateEmployerRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.employerResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Update employer + tags: + - employers + post: + consumes: + - application/json + description: Create a new employer + parameters: + - description: Employer and company details + in: body + name: CreateEmployerRequest + required: true + schema: + $ref: '#/definitions/api.createEmployerRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/api.employerResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "403": + description: Company with given name or employer with given email already + exists + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Create employer + tags: + - employers + /employers/login: + post: + consumes: + - application/json + description: Login an employer + parameters: + - description: Employer credentials + in: body + name: LoginEmployerRequest + required: true + schema: + $ref: '#/definitions/api.loginEmployerRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.loginEmployerResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "401": + description: Incorrect password + schema: + $ref: '#/definitions/api.ErrorResponse' + "404": + description: Employer with given email or company with given id does not + exist + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Login employer + tags: + - employers + /employers/password: + patch: + consumes: + - application/json + description: Update/change logged-in employer password + parameters: + - description: Employer old and new password + in: body + name: UpdateEmployerPasswordRequest + required: true + schema: + $ref: '#/definitions/api.updateEmployerPasswordRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.updateEmployerPasswordResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "401": + description: Incorrect password + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Update employer password + tags: + - employers + /jobs: + get: + description: Filter and list jobs + parameters: + - description: Page number + in: query + name: page + required: true + type: integer + - description: Page size + in: query + name: page_size + required: true + type: integer + - description: Job title - matches partially (ILIKE) + in: query + name: title + type: string + - description: Job industry - exact name + in: query + name: industry + type: string + - description: Job location - exact name + in: query + name: job_location + type: string + - description: Salary min - must be smaller than salary_max + in: query + name: salary_min + type: integer + - description: Salary max - must be greater than salary_min + in: query + name: salary_max + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + items: + $ref: '#/definitions/db.ListJobsByFiltersRow' + type: array + type: array + "400": + description: Invalid query + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Filter and list jobs + tags: + - jobs + post: + consumes: + - application/json + description: Create a new job + parameters: + - description: Job details + in: body + name: CreateJobRequest + required: true + schema: + $ref: '#/definitions/api.createJobRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/api.jobResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Create job + tags: + - jobs + /jobs/{id}: + delete: + description: Delete the job with the given id + parameters: + - description: Job ID + in: path + name: id + required: true + type: integer + responses: + "204": + description: No Content + schema: + type: "null" + "500": + description: Any error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Delete job + tags: + - jobs + get: + description: Get details of the job with the given id + parameters: + - description: Job ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.jobResponse' + "400": + description: Invalid request query + schema: + $ref: '#/definitions/api.ErrorResponse' + "404": + description: Job not found + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Get job + tags: + - jobs + patch: + consumes: + - application/json + description: update the job with the given id + parameters: + - description: Job ID + in: path + name: id + required: true + type: integer + - description: Job details to update + in: body + name: UpdateJobRequest + required: true + schema: + $ref: '#/definitions/api.updateJobRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.jobResponse' + "400": + description: Invalid request query or body + schema: + $ref: '#/definitions/api.ErrorResponse' + "401": + description: User making the request not an employer or employer not the + owner of the job + schema: + $ref: '#/definitions/api.ErrorResponse' + "404": + description: Job not found + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Update job + tags: + - jobs + /jobs/company: + get: + description: List jobs by company name, id or part of the name. + parameters: + - description: Page number + in: query + name: page + required: true + type: integer + - description: Page size + in: query + name: page_size + required: true + type: integer + - description: Company ID + in: query + name: id + type: integer + - description: Company name + in: query + name: name + type: string + - description: Part of the company name + in: query + name: name_contains + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + items: + $ref: '#/definitions/db.ListJobsByCompanyNameRow' + type: array + type: array + "400": + description: Invalid query. Only one of the three parameters is allowed. + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: List jobs by company + tags: + - jobs + /users: + delete: + description: Delete the logged-in user + responses: + "204": + description: No Content + schema: + type: "null" + "500": + description: Any error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Delete user + tags: + - users + get: + description: Get details of the logged in user + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.userResponse' + "500": + description: Any error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Get user + tags: + - users + patch: + consumes: + - application/json + description: Update the logged-in user details + parameters: + - description: User details to update + in: body + name: UpdateUserRequest + required: true + schema: + $ref: '#/definitions/api.updateUserRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.userResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Update user + tags: + - users + post: + consumes: + - application/json + description: Create a new user + parameters: + - description: User details + in: body + name: CreateUserRequest + required: true + schema: + $ref: '#/definitions/api.createUserRequest' + produces: + - application/json + responses: + "201": + description: Created + schema: + $ref: '#/definitions/api.userResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "403": + description: User with given email already exists + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Create user + tags: + - users + /users/login: + post: + consumes: + - application/json + description: Login user + parameters: + - description: User credentials + in: body + name: LoginUserRequest + required: true + schema: + $ref: '#/definitions/api.loginUserRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.loginUserResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "401": + description: Incorrect password + schema: + $ref: '#/definitions/api.ErrorResponse' + "404": + description: User with given email does not exist + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Login user + tags: + - users + /users/password: + patch: + consumes: + - application/json + description: Change / update password of the logged-in user + parameters: + - description: Users old and new password + in: body + name: UpdateUserPasswordRequest + required: true + schema: + $ref: '#/definitions/api.updateUserPasswordRequest' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/api.updateUserPasswordResponse' + "400": + description: Invalid request body + schema: + $ref: '#/definitions/api.ErrorResponse' + "401": + description: Incorrect password + schema: + $ref: '#/definitions/api.ErrorResponse' + "500": + description: Any other error + schema: + $ref: '#/definitions/api.ErrorResponse' + summary: Update user password + tags: + - users +swagger: "2.0" diff --git a/go.mod b/go.mod index fe332a3..cc2494d 100644 --- a/go.mod +++ b/go.mod @@ -12,33 +12,44 @@ require ( github.com/o1egl/paseto v1.0.0 github.com/spf13/viper v1.16.0 github.com/stretchr/testify v1.8.4 + github.com/swaggo/swag v1.16.1 golang.org/x/crypto v0.11.0 ) require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/PuerkitoBio/purell v1.2.0 // indirect + github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/aead/chacha20poly1305 v0.0.0-20170617001512-233f39982aeb // indirect github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635 // indirect - github.com/bytedance/sonic v1.9.2 // indirect - github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect + github.com/bytedance/sonic v1.10.0-rc2 // indirect + github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect + github.com/chenzhuoyu/iasm v0.9.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/gin-contrib/sse v0.1.0 // indirect + github.com/go-openapi/jsonpointer v0.20.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/spec v0.20.9 // indirect + github.com/go-openapi/swag v0.22.4 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.14.1 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.19 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pelletier/go-toml/v2 v2.0.9 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/afero v1.9.5 // indirect @@ -46,13 +57,17 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.2 // indirect + github.com/swaggo/files v1.0.1 // indirect + github.com/swaggo/gin-swagger v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.11 // indirect golang.org/x/arch v0.4.0 // indirect golang.org/x/net v0.12.0 // indirect golang.org/x/sys v0.10.0 // indirect golang.org/x/text v0.11.0 // indirect + golang.org/x/tools v0.11.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 85798f2..89c26f5 100644 --- a/go.sum +++ b/go.sum @@ -38,6 +38,14 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= +github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/PuerkitoBio/purell v1.2.0 h1:/Jdm5QfyM8zdlqT6WVZU4cfP23sot6CEHA4CS49Ezig= +github.com/PuerkitoBio/purell v1.2.0/go.mod h1:OhLRTaaIzhvIyofkJfB24gokC7tM42Px5UhoT32THBk= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= +github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/aead/chacha20poly1305 v0.0.0-20170617001512-233f39982aeb h1:6Z/wqhPFZ7y5ksCEV/V5MXOazLaeu/EW97CU5rz8NWk= @@ -47,10 +55,17 @@ github.com/aead/poly1305 v0.0.0-20180717145839-3fee0db0b635/go.mod h1:lmLxL+FV29 github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= +github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= +github.com/bytedance/sonic v1.10.0-rc2 h1:oDfRZ+4m6AYCOC0GFeOCeYqvBmucy1isvouS2K0cPzo= +github.com/bytedance/sonic v1.10.0-rc2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= +github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= +github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo= +github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -83,6 +98,27 @@ github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SU github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= +github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= +github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= +github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= @@ -164,6 +200,8 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= @@ -172,6 +210,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= @@ -188,6 +227,12 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= @@ -198,11 +243,14 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/o1egl/paseto v1.0.0 h1:bwpvPu2au176w4IBlhbyUv/S5VPptERIA99Oap5qUd0= github.com/o1egl/paseto v1.0.0/go.mod h1:5HxsZPmw/3RI2pAwGo1HhOOwSdvBpcuVzO7uDkm+CLU= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0= +github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -243,6 +291,12 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.16.1 h1:fTNRhKstPKxcnoKsytm4sahr8FaYzUcT7i1/3nd/fBg= +github.com/swaggo/swag v1.16.1/go.mod h1:9/LMvHycG3NFHfR6LwvikHv5iFvmPADQ359cKikGxto= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= @@ -254,6 +308,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -271,6 +326,7 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= @@ -308,6 +364,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -340,7 +399,10 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -363,6 +425,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -397,18 +460,23 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -417,6 +485,7 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -470,6 +539,11 @@ golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -568,14 +642,17 @@ google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -586,6 +663,7 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= diff --git a/main.go b/main.go index 4514cfa..c1a243a 100644 --- a/main.go +++ b/main.go @@ -21,6 +21,10 @@ func main() { store := db.NewStore(conn) + // @BasePath /api/v1 + // @contact.name aalug + // @contact.url https://github.com/aalug + // @contact.email a.a.gulczynski@gmail.com server, err := api.NewServer(config, store) if err != nil { log.Fatal("cannot create server: ", err)