package handlers import ( "strconv" "strings" "time" "github.com/gofiber/fiber/v2" patientdata "wucher/internal/domain/patient_data" "wucher/internal/shared/pkg/apperrorsx" "wucher/internal/shared/pkg/uuidv7" "wucher/internal/transport/http/dto" "wucher/internal/transport/http/jsonapi" "wucher/internal/transport/http/response" "wucher/internal/transport/http/validators" ) type PatientDataHandler struct { svc patientdata.Service validate *validators.Validator } func NewPatientDataHandler(svc patientdata.Service) *PatientDataHandler { return &PatientDataHandler{ svc: svc, validate: validators.New(), } } // CreatePatientData godoc // @Summary Create patient data // @Description Create a PatientData record. // @Tags PatientData - PatientData // @Accept json // @Produce json // @Param request body dto.PatientDataCreateRequest true "JSON:API PatientData create request" // @Success 201 {object} dto.PatientDataResponse // @Failure 422 {object} dto.ErrorResponse // @Failure 400 {object} dto.ErrorResponse // @Router /api/v1/patient-data/create [post] func (h *PatientDataHandler) Create(c *fiber.Ctx) error { var req dto.PatientDataCreateRequest if err := c.BodyParser(&req); err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "Invalid JSON", Detail: safeInternalDetail(), }}) } if errs := h.validate.ValidateStruct(req); errs != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, errs) } familyName := strings.TrimSpace(req.Data.Attributes.FamilyName) if familyName == "" { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "family_name is required", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/family_name"}, }}) } firstName := strings.TrimSpace(req.Data.Attributes.FirstName) if firstName == "" { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "first_name is required", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/first_name"}, }}) } row := &patientdata.PatientData{ FamilyName: familyName, FirstName: firstName, Gender: req.Data.Attributes.Gender, Street: strings.TrimSpace(stringOrDefault(req.Data.Attributes.Street, "")), SVNR: strings.TrimSpace(stringOrDefault(req.Data.Attributes.SVNR, "")), Email: strings.TrimSpace(stringOrDefault(req.Data.Attributes.Email, "")), Phone: strings.TrimSpace(stringOrDefault(req.Data.Attributes.Phone, "")), CreatedBy: actorUserID(c), UpdatedBy: actorUserID(c), } if req.Data.Attributes.CoInsured != nil { row.CoInsured = *req.Data.Attributes.CoInsured } if req.Data.Attributes.BirthDate != nil { bd, err := time.Parse("2006-01-02", strings.TrimSpace(*req.Data.Attributes.BirthDate)) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "birth_date must be in YYYY-MM-DD format", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/birth_date"}, }}) } row.BirthDate = &bd } if req.Data.Attributes.OPCId != nil { parsed, err := uuidv7.ParseString(strings.TrimSpace(*req.Data.Attributes.OPCId)) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "opc_id is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/opc_id"}, }}) } row.OPCId = parsed } if req.Data.Attributes.InsurancePatientDataId != nil { parsed, err := uuidv7.ParseString(strings.TrimSpace(*req.Data.Attributes.InsurancePatientDataId)) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "insurance_patient_data_id is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/insurance_patient_data_id"}, }}) } row.InsurancePatientDataId = parsed } if err := h.svc.Create(c.UserContext(), row); err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "Create failed", Detail: safeInternalDetail(), }}) } created, err := h.svc.GetByID(c.UserContext(), row.ID) if err == nil && created != nil { return response.Write(c, fiber.StatusCreated, patientDataResource(created)) } return response.Write(c, fiber.StatusCreated, patientDataResource(row)) } // GetPatientData godoc // @Summary Get patient data by ID // @Description Get a single PatientData record by UUID. // @Tags PatientData - PatientData // @Produce json // @Param uuid path string true "PatientData UUID (UUIDv7)" // @Success 200 {object} dto.PatientDataResponse // @Failure 422 {object} dto.ErrorResponse // @Failure 404 {object} dto.ErrorResponse // @Router /api/v1/patient-data/get/{uuid} [get] func (h *PatientDataHandler) Get(c *fiber.Ctx) error { uuidStr := c.Params("uuid") id, err := uuidv7.ParseString(uuidStr) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "uuid is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/path/uuid"}, }}) } row, err := h.svc.GetByID(c.UserContext(), id) if err != nil || row == nil { return writePatientDataErrors(c, fiber.StatusNotFound, []jsonapi.ErrorObject{{ Status: "404", Title: "Not found", Detail: "patient data not found", }}) } return response.Write(c, fiber.StatusOK, patientDataResource(row)) } // UpdatePatientData godoc // @Summary Update patient data (partial) // @Description Patch PatientData by ID. // @Tags PatientData - PatientData // @Accept json // @Produce json // @Param uuid path string true "PatientData UUID (UUIDv7)" // @Param request body dto.PatientDataUpdateRequest true "JSON:API PatientData update request" // @Success 200 {object} dto.PatientDataResponse // @Failure 422 {object} dto.ErrorResponse // @Failure 404 {object} dto.ErrorResponse // @Router /api/v1/patient-data/update/{uuid} [patch] func (h *PatientDataHandler) Update(c *fiber.Ctx) error { uuidStr := c.Params("uuid") id, err := uuidv7.ParseString(uuidStr) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "uuid is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/path/uuid"}, }}) } var req dto.PatientDataUpdateRequest if err := c.BodyParser(&req); err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "Invalid JSON", Detail: safeInternalDetail(), }}) } if errs := h.validate.ValidateStruct(req); errs != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, errs) } if strings.TrimSpace(req.Data.ID) == "" { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "id is required", Source: &jsonapi.ErrorSource{Pointer: "/data/id"}, }}) } if req.Data.ID != uuidStr { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "id does not match path uuid", Source: &jsonapi.ErrorSource{Pointer: "/data/id"}, }}) } attrs := req.Data.Attributes if attrs.FamilyName == nil && attrs.FirstName == nil && attrs.OPCId == nil && attrs.BirthDate == nil && attrs.Gender == nil && attrs.Street == nil && attrs.SVNR == nil && attrs.Email == nil && attrs.Phone == nil && attrs.CoInsured == nil && attrs.InsurancePatientDataId == nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "at least one attribute must be provided", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes"}, }}) } existing, err := h.svc.GetByID(c.UserContext(), id) if err != nil || existing == nil { return writePatientDataErrors(c, fiber.StatusNotFound, []jsonapi.ErrorObject{{ Status: "404", Title: "Not found", Detail: "patient data not found", }}) } if attrs.FamilyName != nil { v := strings.TrimSpace(*attrs.FamilyName) if v == "" { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "family_name cannot be empty", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/family_name"}, }}) } existing.FamilyName = v } if attrs.FirstName != nil { v := strings.TrimSpace(*attrs.FirstName) if v == "" { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "first_name cannot be empty", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/first_name"}, }}) } existing.FirstName = v } if attrs.Gender != nil { if !patientdata.IsValidGender(*attrs.Gender) { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "gender must be male or female", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/gender"}, }}) } existing.Gender = *attrs.Gender } if attrs.Street != nil { existing.Street = strings.TrimSpace(*attrs.Street) } if attrs.SVNR != nil { existing.SVNR = strings.TrimSpace(*attrs.SVNR) } if attrs.Email != nil { existing.Email = strings.TrimSpace(*attrs.Email) } if attrs.Phone != nil { existing.Phone = strings.TrimSpace(*attrs.Phone) } if attrs.CoInsured != nil { existing.CoInsured = *attrs.CoInsured } if attrs.BirthDate != nil { bd, parseErr := time.Parse("2006-01-02", strings.TrimSpace(*attrs.BirthDate)) if parseErr != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "birth_date must be in YYYY-MM-DD format", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/birth_date"}, }}) } existing.BirthDate = &bd } if attrs.OPCId != nil { parsed, parseErr := uuidv7.ParseString(strings.TrimSpace(*attrs.OPCId)) if parseErr != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "opc_id is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/opc_id"}, }}) } existing.OPCId = parsed } if attrs.InsurancePatientDataId != nil { parsed, parseErr := uuidv7.ParseString(strings.TrimSpace(*attrs.InsurancePatientDataId)) if parseErr != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "insurance_patient_data_id is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/insurance_patient_data_id"}, }}) } existing.InsurancePatientDataId = parsed } existing.UpdatedBy = actorUserID(c) if err := h.svc.Update(c.UserContext(), existing); err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "Update failed", Detail: safeInternalDetail(), }}) } updated, err := h.svc.GetByID(c.UserContext(), existing.ID) if err == nil && updated != nil { return response.Write(c, fiber.StatusOK, patientDataResource(updated)) } return response.Write(c, fiber.StatusOK, patientDataResource(existing)) } // DeletePatientData godoc // @Summary Delete patient data // @Description Soft delete PatientData by ID. // @Tags PatientData - PatientData // @Produce json // @Param uuid path string true "PatientData UUID (UUIDv7)" // @Success 200 {object} dto.GenericDeleteResponse // @Failure 422 {object} dto.ErrorResponse // @Failure 400 {object} dto.ErrorResponse // @Failure 404 {object} dto.ErrorResponse // @Router /api/v1/patient-data/delete/{uuid} [delete] func (h *PatientDataHandler) Delete(c *fiber.Ctx) error { uuidStr := c.Params("uuid") id, err := uuidv7.ParseString(uuidStr) if err != nil { return writePatientDataErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{ Status: "422", Title: "Validation error", Detail: "uuid is invalid UUID", Source: &jsonapi.ErrorSource{Pointer: "/path/uuid"}, }}) } if err := h.svc.Delete(c.UserContext(), id, actorUserID(c)); err != nil { return writeDeleteError(c, err) } return response.Write(c, fiber.StatusOK, jsonapi.Resource{ Type: "patient_data_delete", Attributes: map[string]any{ "deleted": true, }, }) } // ListPatientData godoc // @Summary List patient data // @Description JSON:API list with pagination, filtering and sorting. Sort values: family_name, -family_name, first_name, -first_name, birth_date, -birth_date, gender, -gender, created_at, -created_at, updated_at, -updated_at. // @Tags PatientData - PatientData // @Produce json // @Param filter[search] query string false "Search by family_name/first_name/svnr/email/phone/street" // @Param page[number] query int false "Page number (default 1)" // @Param page[size] query int false "Page size (default 20, max 100)" // @Param sort query string false "Sort order" // @Success 200 {object} dto.PatientDataListResponse // @Router /api/v1/patient-data/get-all [get] func (h *PatientDataHandler) List(c *fiber.Ctx) error { filter := c.Query("filter[search]") if filter == "" { filter = c.Query("search") } pageNumber := parseIntDefault(c.Query("page[number]"), 0) if pageNumber <= 0 { pageNumber = parseIntDefault(c.Query("page"), 1) } pageSize := parseIntDefault(c.Query("page[size]"), 0) if pageSize <= 0 { pageSize = parseIntDefault(c.Query("limit"), 0) } if pageSize <= 0 { pageSize = parseIntDefault(c.Query("size"), 20) } if pageSize > 100 { pageSize = 100 } if pageSize < 1 { pageSize = 20 } if pageNumber < 1 { pageNumber = 1 } offset := (pageNumber - 1) * pageSize _ = offset sort := c.Query("sort") rows, total, err := h.svc.List(c.UserContext(), filter, sort, 0, 0) if err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "List failed", Detail: safeInternalDetail(), }}) } data := make([]dto.PatientDataResource, 0, len(rows)) for i := range rows { data = append(data, patientDataResource(&rows[i])) } meta := map[string]any{ "page_number": pageNumber, "page_size": pageSize, "total": total, } return response.WriteWithMeta(c, fiber.StatusOK, data, meta) } // ListPatientDataDatatable godoc // @Summary List patient data (datatable) // @Description Datatable response with simple pagination params. // @Tags PatientData - PatientData // @Produce json // @Param page query int false "Page number (default 1)" // @Param size query int false "Page size (default 20, max 100)" // @Param limit query int false "Page size override (same as size)" // @Param draw query int false "Draw counter (optional)" // @Param search query string false "Search by family_name/first_name/svnr/email/phone/street" // @Param sort query string false "Sort order" // @Success 200 {object} dto.PatientDataDataTableResponse // @Router /api/v1/patient-data/get-all/dt [get] func (h *PatientDataHandler) ListDatatable(c *fiber.Ctx) error { pageNumber := parseIntDefault(c.Query("page"), 1) if pageNumber < 1 { pageNumber = 1 } length := parseIntDefault(c.Query("limit"), 0) if length <= 0 { length = parseIntDefault(c.Query("size"), 20) } if length > 100 { length = 100 } if length < 1 { length = 20 } start := (pageNumber - 1) * length draw := parseIntDefault(c.Query("draw"), pageNumber) search := c.Query("search") sort := c.Query("sort") rows, total, err := h.svc.List(c.UserContext(), search, sort, length, start) if err != nil { return writePatientDataErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{ Status: "400", Title: "List failed", Detail: safeInternalDetail(), }}) } data := make([]dto.PatientDataResource, 0, len(rows)) for i := range rows { data = append(data, patientDataResource(&rows[i])) } meta := map[string]any{ "draw": draw, "records_total": total, "records_filtered": total, } return response.WriteWithMeta(c, fiber.StatusOK, data, meta) } // computeAge calculates the age in whole years from birthDate to now. func computeAge(birthDate time.Time) int { now := time.Now().UTC() years := now.Year() - birthDate.Year() if now.Month() < birthDate.Month() || (now.Month() == birthDate.Month() && now.Day() < birthDate.Day()) { years-- } return years } func patientDataResource(row *patientdata.PatientData) dto.PatientDataResource { attrs := dto.PatientDataAttributes{ FamilyName: row.FamilyName, FirstName: row.FirstName, OPCId: idString(row.OPCId), Gender: row.Gender, Street: row.Street, SVNR: row.SVNR, Email: row.Email, Phone: row.Phone, CoInsured: row.CoInsured, InsurancePatientDataId: idString(row.InsurancePatientDataId), CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339), CreatedBy: uuidStringOrEmpty(row.CreatedBy), UpdatedAt: row.UpdatedAt.UTC().Format(time.RFC3339), UpdatedBy: uuidStringOrEmpty(row.UpdatedBy), DeletedAt: timeStringOrEmpty(row.DeletedAt), DeletedBy: uuidStringOrEmpty(row.DeletedBy), } if row.OPC != nil { attrs.OPC = &dto.PatientDataOPC{ ID: idString(row.OPC.ID), Title: row.OPC.Title, } } if row.InsurancePatientData != nil { insurance := &dto.PatientDataInsuranceDetail{ ID: idString(row.InsurancePatientData.ID), HealthInsuranceCompanyID: idString(row.InsurancePatientData.HealthInsuranceCompaniesId), FederalStateID: idString(row.InsurancePatientData.FederalStateId), } if row.InsurancePatientData.HealthInsuranceCompanies != nil { insurance.HealthInsuranceCompany = &dto.InsurancePatientDataHealthInsuranceCompany{ ID: idString(row.InsurancePatientData.HealthInsuranceCompanies.ID), Name: row.InsurancePatientData.HealthInsuranceCompanies.Name, State: row.InsurancePatientData.HealthInsuranceCompanies.State, Address: row.InsurancePatientData.HealthInsuranceCompanies.Address, MobileNumber: row.InsurancePatientData.HealthInsuranceCompanies.MobileNumber, Email: row.InsurancePatientData.HealthInsuranceCompanies.Email, } } if row.InsurancePatientData.FederalState != nil { insurance.FederalState = &dto.InsurancePatientDataFederalState{ ID: idString(row.InsurancePatientData.FederalState.ID), Name: row.InsurancePatientData.FederalState.Name, } } attrs.InsurancePatientData = insurance } if row.BirthDate != nil { attrs.BirthDate = row.BirthDate.Format("2006-01-02") age := computeAge(*row.BirthDate) attrs.Age = &age } return dto.PatientDataResource{ Type: "patient_data", ID: idString(row.ID), Attributes: attrs, } } func writePatientDataErrors(c *fiber.Ctx, status int, errs []jsonapi.ErrorObject) error { enriched := make([]jsonapi.ErrorObject, 0, len(errs)) statusStr := strconv.Itoa(status) for i := range errs { e := errs[i] e.Status = statusStr if strings.TrimSpace(e.Code) == "" || strings.TrimSpace(e.ErrorCode) == "" { code, errorCode := inferPatientDataErrorCode(status, e.Title, e.Detail) if strings.TrimSpace(e.Code) == "" { e.Code = code } if strings.TrimSpace(e.ErrorCode) == "" { e.ErrorCode = errorCode } } enriched = append(enriched, e) } return response.WriteErrors(c, status, enriched) } func inferPatientDataErrorCode(status int, title, detail string) (string, string) { lowerTitle := strings.ToLower(strings.TrimSpace(title)) lowerDetail := strings.ToLower(strings.TrimSpace(detail)) switch status { case fiber.StatusNotFound: return apperrorsx.CodePatientDataNotFound, apperrorsx.ErrPatientDataNotFound.ErrorCode case fiber.StatusConflict: return apperrorsx.CodePatientDataRelationDelete, apperrorsx.ErrPatientDataRelationDelete.ErrorCode case fiber.StatusUnprocessableEntity: switch { case strings.Contains(lowerDetail, "uuid is invalid"): return apperrorsx.CodePatientDataInvalidUUID, apperrorsx.ErrPatientDataInvalidUUID.ErrorCode case strings.Contains(lowerDetail, "id is required"): return apperrorsx.CodePatientDataIDRequired, apperrorsx.ErrPatientDataIDRequired.ErrorCode case strings.Contains(lowerDetail, "id does not match"): return apperrorsx.CodePatientDataIDMismatch, apperrorsx.ErrPatientDataIDMismatch.ErrorCode case strings.Contains(lowerDetail, "at least one attribute"): return apperrorsx.CodePatientDataAttributesRequired, apperrorsx.ErrPatientDataAttributesRequired.ErrorCode case strings.Contains(lowerDetail, "family_name is required"), strings.Contains(lowerDetail, "family_name cannot be empty"): return apperrorsx.CodePatientDataFamilyNameRequired, apperrorsx.ErrPatientDataFamilyNameRequired.ErrorCode case strings.Contains(lowerDetail, "first_name is required"), strings.Contains(lowerDetail, "first_name cannot be empty"): return apperrorsx.CodePatientDataFirstNameRequired, apperrorsx.ErrPatientDataFirstNameRequired.ErrorCode case strings.Contains(lowerDetail, "birth_date must be"): return apperrorsx.CodePatientDataBirthDateInvalid, apperrorsx.ErrPatientDataBirthDateInvalid.ErrorCode case strings.Contains(lowerDetail, "gender must be"): return apperrorsx.CodePatientDataGenderInvalid, apperrorsx.ErrPatientDataGenderInvalid.ErrorCode case strings.Contains(lowerDetail, "opc_id is invalid"): return apperrorsx.CodePatientDataOPCIDInvalid, apperrorsx.ErrPatientDataOPCIDInvalid.ErrorCode case strings.Contains(lowerDetail, "insurance_patient_data_id is invalid"): return apperrorsx.CodePatientDataInsurancePatientDataIDInvalid, apperrorsx.ErrPatientDataInsurancePatientDataIDInvalid.ErrorCode default: return apperrorsx.CodePatientDataInvalidPayload, apperrorsx.ErrPatientDataInvalidPayload.ErrorCode } case fiber.StatusBadRequest: switch { case strings.Contains(lowerTitle, "invalid json"): return apperrorsx.CodePatientDataInvalidJSON, apperrorsx.ErrPatientDataInvalidJSON.ErrorCode case strings.Contains(lowerTitle, "create failed"): return apperrorsx.CodePatientDataCreateFailed, apperrorsx.ErrPatientDataCreateFailed.ErrorCode case strings.Contains(lowerTitle, "update failed"): return apperrorsx.CodePatientDataUpdateFailed, apperrorsx.ErrPatientDataUpdateFailed.ErrorCode case strings.Contains(lowerTitle, "delete failed"): return apperrorsx.CodePatientDataDeleteFailed, apperrorsx.ErrPatientDataDeleteFailed.ErrorCode case strings.Contains(lowerTitle, "list failed"): return apperrorsx.CodePatientDataListFailed, apperrorsx.ErrPatientDataListFailed.ErrorCode default: return apperrorsx.CodePatientDataInvalidPayload, apperrorsx.ErrPatientDataInvalidPayload.ErrorCode } default: return apperrorsx.CodeInternalServerError, apperrorsx.ErrInternal.ErrorCode } }