Skip to content

Commit

Permalink
add API docs using swagger(#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Gulczynski committed Jul 25, 2023
1 parent f4f3811 commit b6eb4f1
Show file tree
Hide file tree
Showing 13 changed files with 4,153 additions and 47 deletions.
71 changes: 69 additions & 2 deletions api/employer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 6 additions & 6 deletions api/employer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down
87 changes: 87 additions & 0 deletions api/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
Expand Down
14 changes: 7 additions & 7 deletions api/job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down
Loading

0 comments on commit b6eb4f1

Please sign in to comment.