perbaikan handles bpjs

This commit is contained in:
2025-08-29 18:17:53 +07:00
parent 0545bd2298
commit 3951fd87a7
7 changed files with 825 additions and 2478 deletions

View File

@@ -699,313 +699,6 @@ const docTemplate = `{
} }
} }
} }
},
"/peserta/:nokartu": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get participant eligibility information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"peserta"
],
"summary": "Get Peserta data",
"parameters": [
{
"type": "string",
"description": "Nokartu",
"name": "nokartu",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.PesertaResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/rujukan/:norujukan": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get referral information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"rujukan"
],
"summary": "Get Rujukan data",
"parameters": [
{
"type": "string",
"description": "Norujukan",
"name": "norujukan",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.RujukanResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/sep": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Create Sep",
"parameters": [
{
"description": "Sep data",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/reference.SEPRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/sep/:nosep": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Get Sep data",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
},
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Update Sep",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
},
{
"description": "Sep data",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/reference.SEPRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
},
"delete": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Delete Sep",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.BaseResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
} }
}, },
"definitions": { "definitions": {
@@ -1434,404 +1127,6 @@ const docTemplate = `{
} }
} }
}, },
"reference.BaseResponse": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.ErrorResponse": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"errors": {
"type": "object",
"additionalProperties": true
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"reference.PesertaData": {
"type": "object",
"properties": {
"aktif": {
"type": "string"
},
"asuransi": {
"type": "string"
},
"cob": {
"type": "string"
},
"kdCabang": {
"type": "string"
},
"kdJnsPst": {
"type": "string"
},
"ketAktif": {
"type": "string"
},
"klsRawat": {
"type": "string"
},
"mr": {
"type": "object",
"properties": {
"nmMR": {
"type": "string"
},
"noMR": {
"type": "string"
},
"sex": {
"type": "string"
},
"tglLahir": {
"type": "string"
},
"tglMeninggal": {
"type": "string"
}
}
},
"nama": {
"type": "string"
},
"nik": {
"type": "string"
},
"nmCabang": {
"type": "string"
},
"nmJnsPst": {
"type": "string"
},
"noKartu": {
"type": "string"
},
"noKtp": {
"type": "string"
},
"noSKTM": {
"type": "string"
},
"pisa": {
"type": "string"
},
"sex": {
"type": "string"
},
"statusPeserta": {
"type": "string"
},
"tglLahir": {
"type": "string"
},
"tglTAT": {
"type": "string"
},
"tglTMT": {
"type": "string"
},
"tglTunggak": {
"type": "string"
}
}
},
"reference.PesertaResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.PesertaData"
},
"message": {
"type": "string"
},
"metaData": {},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.RujukanData": {
"type": "object",
"properties": {
"diagnosa": {
"type": "object",
"properties": {
"kdDiagnosa": {
"type": "string"
},
"nmDiagnosa": {
"type": "string"
}
}
},
"kelasRawat": {
"type": "string"
},
"nama": {
"type": "string"
},
"noKartu": {
"type": "string"
},
"noRujukan": {
"type": "string"
},
"pelayanan": {
"type": "string"
},
"poliRujukan": {
"type": "object",
"properties": {
"kdPoli": {
"type": "string"
},
"nmPoli": {
"type": "string"
}
}
},
"provPerujuk": {
"type": "object",
"properties": {
"kdProvider": {
"type": "string"
},
"nmProvider": {
"type": "string"
}
}
},
"statusRujukan": {
"type": "string"
},
"tglRujukan": {
"type": "string"
}
}
},
"reference.RujukanResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.RujukanData"
},
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/reference.RujukanData"
}
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.SEPData": {
"type": "object",
"properties": {
"catatan": {
"type": "string"
},
"diagnosa": {
"type": "string"
},
"informasi": {
"type": "object",
"properties": {
"dpjpLayan": {
"type": "string"
},
"noSKDP": {
"type": "string"
},
"noTelp": {
"type": "string"
},
"subSpesialis": {
"type": "string"
}
}
},
"jnsPelayanan": {
"type": "string"
},
"klsRawat": {
"type": "string"
},
"noMR": {
"type": "string"
},
"noSep": {
"type": "string"
},
"peserta": {
"$ref": "#/definitions/reference.PesertaData"
},
"poli": {
"type": "string"
},
"rujukan": {
"$ref": "#/definitions/reference.SEPRujukan"
},
"tglSep": {
"type": "string"
}
}
},
"reference.SEPRequest": {
"type": "object",
"required": [
"diagnosa",
"jnsPelayanan",
"klsRawat",
"noKartu",
"noMR",
"poli",
"ppkPelayanan",
"tglSep",
"user"
],
"properties": {
"catatan": {
"type": "string"
},
"diagnosa": {
"type": "string"
},
"jnsPelayanan": {
"type": "string",
"enum": [
"1",
"2"
]
},
"klsRawat": {
"type": "string",
"enum": [
"1",
"2",
"3"
]
},
"noKartu": {
"type": "string"
},
"noMR": {
"type": "string"
},
"noTelp": {
"type": "string"
},
"poli": {
"type": "string"
},
"ppkPelayanan": {
"type": "string"
},
"request_id": {
"type": "string"
},
"rujukan": {
"$ref": "#/definitions/reference.SEPRujukan"
},
"tglSep": {
"type": "string"
},
"timestamp": {
"type": "string"
},
"user": {
"type": "string"
}
}
},
"reference.SEPResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.SEPData"
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.SEPRujukan": {
"type": "object",
"required": [
"asalRujukan",
"noRujukan",
"ppkRujukan",
"tglRujukan"
],
"properties": {
"asalRujukan": {
"type": "string",
"enum": [
"1",
"2"
]
},
"noRujukan": {
"type": "string"
},
"ppkRujukan": {
"type": "string"
},
"tglRujukan": {
"type": "string"
}
}
},
"sql.NullString": { "sql.NullString": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -696,313 +696,6 @@
} }
} }
} }
},
"/peserta/:nokartu": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get participant eligibility information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"peserta"
],
"summary": "Get Peserta data",
"parameters": [
{
"type": "string",
"description": "Nokartu",
"name": "nokartu",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.PesertaResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/rujukan/:norujukan": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Get referral information",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"rujukan"
],
"summary": "Get Rujukan data",
"parameters": [
{
"type": "string",
"description": "Norujukan",
"name": "norujukan",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.RujukanResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/sep": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Create Sep",
"parameters": [
{
"description": "Sep data",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/reference.SEPRequest"
}
}
],
"responses": {
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
},
"/sep/:nosep": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Get Sep data",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
},
"put": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Update Sep",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
},
{
"description": "Sep data",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/reference.SEPRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.SEPResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
},
"delete": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "Manage SEP (Surat Eligibilitas Peserta)",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"vclaim",
"sep"
],
"summary": "Delete Sep",
"parameters": [
{
"type": "string",
"description": "Nosep",
"name": "nosep",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/reference.BaseResponse"
}
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/reference.ErrorResponse"
}
}
}
}
} }
}, },
"definitions": { "definitions": {
@@ -1431,404 +1124,6 @@
} }
} }
}, },
"reference.BaseResponse": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.ErrorResponse": {
"type": "object",
"properties": {
"code": {
"type": "string"
},
"errors": {
"type": "object",
"additionalProperties": true
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
}
}
},
"reference.PesertaData": {
"type": "object",
"properties": {
"aktif": {
"type": "string"
},
"asuransi": {
"type": "string"
},
"cob": {
"type": "string"
},
"kdCabang": {
"type": "string"
},
"kdJnsPst": {
"type": "string"
},
"ketAktif": {
"type": "string"
},
"klsRawat": {
"type": "string"
},
"mr": {
"type": "object",
"properties": {
"nmMR": {
"type": "string"
},
"noMR": {
"type": "string"
},
"sex": {
"type": "string"
},
"tglLahir": {
"type": "string"
},
"tglMeninggal": {
"type": "string"
}
}
},
"nama": {
"type": "string"
},
"nik": {
"type": "string"
},
"nmCabang": {
"type": "string"
},
"nmJnsPst": {
"type": "string"
},
"noKartu": {
"type": "string"
},
"noKtp": {
"type": "string"
},
"noSKTM": {
"type": "string"
},
"pisa": {
"type": "string"
},
"sex": {
"type": "string"
},
"statusPeserta": {
"type": "string"
},
"tglLahir": {
"type": "string"
},
"tglTAT": {
"type": "string"
},
"tglTMT": {
"type": "string"
},
"tglTunggak": {
"type": "string"
}
}
},
"reference.PesertaResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.PesertaData"
},
"message": {
"type": "string"
},
"metaData": {},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.RujukanData": {
"type": "object",
"properties": {
"diagnosa": {
"type": "object",
"properties": {
"kdDiagnosa": {
"type": "string"
},
"nmDiagnosa": {
"type": "string"
}
}
},
"kelasRawat": {
"type": "string"
},
"nama": {
"type": "string"
},
"noKartu": {
"type": "string"
},
"noRujukan": {
"type": "string"
},
"pelayanan": {
"type": "string"
},
"poliRujukan": {
"type": "object",
"properties": {
"kdPoli": {
"type": "string"
},
"nmPoli": {
"type": "string"
}
}
},
"provPerujuk": {
"type": "object",
"properties": {
"kdProvider": {
"type": "string"
},
"nmProvider": {
"type": "string"
}
}
},
"statusRujukan": {
"type": "string"
},
"tglRujukan": {
"type": "string"
}
}
},
"reference.RujukanResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.RujukanData"
},
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/reference.RujukanData"
}
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.SEPData": {
"type": "object",
"properties": {
"catatan": {
"type": "string"
},
"diagnosa": {
"type": "string"
},
"informasi": {
"type": "object",
"properties": {
"dpjpLayan": {
"type": "string"
},
"noSKDP": {
"type": "string"
},
"noTelp": {
"type": "string"
},
"subSpesialis": {
"type": "string"
}
}
},
"jnsPelayanan": {
"type": "string"
},
"klsRawat": {
"type": "string"
},
"noMR": {
"type": "string"
},
"noSep": {
"type": "string"
},
"peserta": {
"$ref": "#/definitions/reference.PesertaData"
},
"poli": {
"type": "string"
},
"rujukan": {
"$ref": "#/definitions/reference.SEPRujukan"
},
"tglSep": {
"type": "string"
}
}
},
"reference.SEPRequest": {
"type": "object",
"required": [
"diagnosa",
"jnsPelayanan",
"klsRawat",
"noKartu",
"noMR",
"poli",
"ppkPelayanan",
"tglSep",
"user"
],
"properties": {
"catatan": {
"type": "string"
},
"diagnosa": {
"type": "string"
},
"jnsPelayanan": {
"type": "string",
"enum": [
"1",
"2"
]
},
"klsRawat": {
"type": "string",
"enum": [
"1",
"2",
"3"
]
},
"noKartu": {
"type": "string"
},
"noMR": {
"type": "string"
},
"noTelp": {
"type": "string"
},
"poli": {
"type": "string"
},
"ppkPelayanan": {
"type": "string"
},
"request_id": {
"type": "string"
},
"rujukan": {
"$ref": "#/definitions/reference.SEPRujukan"
},
"tglSep": {
"type": "string"
},
"timestamp": {
"type": "string"
},
"user": {
"type": "string"
}
}
},
"reference.SEPResponse": {
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/reference.SEPData"
},
"message": {
"type": "string"
},
"request_id": {
"type": "string"
},
"status": {
"type": "string"
},
"timestamp": {
"type": "string"
}
}
},
"reference.SEPRujukan": {
"type": "object",
"required": [
"asalRujukan",
"noRujukan",
"ppkRujukan",
"tglRujukan"
],
"properties": {
"asalRujukan": {
"type": "string",
"enum": [
"1",
"2"
]
},
"noRujukan": {
"type": "string"
},
"ppkRujukan": {
"type": "string"
},
"tglRujukan": {
"type": "string"
}
}
},
"sql.NullString": { "sql.NullString": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -292,272 +292,6 @@ definitions:
message: message:
type: string type: string
type: object type: object
reference.BaseResponse:
properties:
message:
type: string
request_id:
type: string
status:
type: string
timestamp:
type: string
type: object
reference.ErrorResponse:
properties:
code:
type: string
errors:
additionalProperties: true
type: object
message:
type: string
request_id:
type: string
status:
type: string
type: object
reference.PesertaData:
properties:
aktif:
type: string
asuransi:
type: string
cob:
type: string
kdCabang:
type: string
kdJnsPst:
type: string
ketAktif:
type: string
klsRawat:
type: string
mr:
properties:
nmMR:
type: string
noMR:
type: string
sex:
type: string
tglLahir:
type: string
tglMeninggal:
type: string
type: object
nama:
type: string
nik:
type: string
nmCabang:
type: string
nmJnsPst:
type: string
noKartu:
type: string
noKtp:
type: string
noSKTM:
type: string
pisa:
type: string
sex:
type: string
statusPeserta:
type: string
tglLahir:
type: string
tglTAT:
type: string
tglTMT:
type: string
tglTunggak:
type: string
type: object
reference.PesertaResponse:
properties:
data:
$ref: '#/definitions/reference.PesertaData'
message:
type: string
metaData: {}
request_id:
type: string
status:
type: string
timestamp:
type: string
type: object
reference.RujukanData:
properties:
diagnosa:
properties:
kdDiagnosa:
type: string
nmDiagnosa:
type: string
type: object
kelasRawat:
type: string
nama:
type: string
noKartu:
type: string
noRujukan:
type: string
pelayanan:
type: string
poliRujukan:
properties:
kdPoli:
type: string
nmPoli:
type: string
type: object
provPerujuk:
properties:
kdProvider:
type: string
nmProvider:
type: string
type: object
statusRujukan:
type: string
tglRujukan:
type: string
type: object
reference.RujukanResponse:
properties:
data:
$ref: '#/definitions/reference.RujukanData'
list:
items:
$ref: '#/definitions/reference.RujukanData'
type: array
message:
type: string
request_id:
type: string
status:
type: string
timestamp:
type: string
type: object
reference.SEPData:
properties:
catatan:
type: string
diagnosa:
type: string
informasi:
properties:
dpjpLayan:
type: string
noSKDP:
type: string
noTelp:
type: string
subSpesialis:
type: string
type: object
jnsPelayanan:
type: string
klsRawat:
type: string
noMR:
type: string
noSep:
type: string
peserta:
$ref: '#/definitions/reference.PesertaData'
poli:
type: string
rujukan:
$ref: '#/definitions/reference.SEPRujukan'
tglSep:
type: string
type: object
reference.SEPRequest:
properties:
catatan:
type: string
diagnosa:
type: string
jnsPelayanan:
enum:
- "1"
- "2"
type: string
klsRawat:
enum:
- "1"
- "2"
- "3"
type: string
noKartu:
type: string
noMR:
type: string
noTelp:
type: string
poli:
type: string
ppkPelayanan:
type: string
request_id:
type: string
rujukan:
$ref: '#/definitions/reference.SEPRujukan'
tglSep:
type: string
timestamp:
type: string
user:
type: string
required:
- diagnosa
- jnsPelayanan
- klsRawat
- noKartu
- noMR
- poli
- ppkPelayanan
- tglSep
- user
type: object
reference.SEPResponse:
properties:
data:
$ref: '#/definitions/reference.SEPData'
message:
type: string
request_id:
type: string
status:
type: string
timestamp:
type: string
type: object
reference.SEPRujukan:
properties:
asalRujukan:
enum:
- "1"
- "2"
type: string
noRujukan:
type: string
ppkRujukan:
type: string
tglRujukan:
type: string
required:
- asalRujukan
- noRujukan
- ppkRujukan
- tglRujukan
type: object
sql.NullString: sql.NullString:
properties: properties:
string: string:
@@ -1033,203 +767,6 @@ paths:
summary: Generate token directly summary: Generate token directly
tags: tags:
- Token - Token
/peserta/:nokartu:
get:
consumes:
- application/json
description: Get participant eligibility information
parameters:
- description: Nokartu
in: path
name: nokartu
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/reference.PesertaResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Get Peserta data
tags:
- vclaim
- peserta
/rujukan/:norujukan:
get:
consumes:
- application/json
description: Get referral information
parameters:
- description: Norujukan
in: path
name: norujukan
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/reference.RujukanResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Get Rujukan data
tags:
- vclaim
- rujukan
/sep:
post:
consumes:
- application/json
description: Manage SEP (Surat Eligibilitas Peserta)
parameters:
- description: Sep data
in: body
name: request
required: true
schema:
$ref: '#/definitions/reference.SEPRequest'
produces:
- application/json
responses:
"201":
description: Created
schema:
$ref: '#/definitions/reference.SEPResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Create Sep
tags:
- vclaim
- sep
/sep/:nosep:
delete:
consumes:
- application/json
description: Manage SEP (Surat Eligibilitas Peserta)
parameters:
- description: Nosep
in: path
name: nosep
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/reference.BaseResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Delete Sep
tags:
- vclaim
- sep
get:
consumes:
- application/json
description: Manage SEP (Surat Eligibilitas Peserta)
parameters:
- description: Nosep
in: path
name: nosep
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/reference.SEPResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Get Sep data
tags:
- vclaim
- sep
put:
consumes:
- application/json
description: Manage SEP (Surat Eligibilitas Peserta)
parameters:
- description: Nosep
in: path
name: nosep
required: true
type: string
- description: Sep data
in: body
name: request
required: true
schema:
$ref: '#/definitions/reference.SEPRequest'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/reference.SEPResponse'
"400":
description: Bad Request
schema:
$ref: '#/definitions/reference.ErrorResponse'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/reference.ErrorResponse'
security:
- ApiKeyAuth: []
summary: Update Sep
tags:
- vclaim
- sep
schemes: schemes:
- http - http
- https - https

View File

@@ -1,256 +1,282 @@
// Code generated by generate-dynamic-handler.go; DO NOT EDIT.
// Code generated by generate-handler.go; DO NOT EDIT. // Generated at: 2025-08-29 13:02:57
// Generated at: 2025-08-29 04:42:52
// Service: VClaim (vclaim) // Service: VClaim (vclaim)
// Description: BPJS VClaim service for eligibility and SEP management
package handlers package handlers
import ( import (
"context" "context"
"net/http" "net/http"
"time" "time"
"api-service/internal/models/reference"
"github.com/gin-gonic/gin" "api-service/internal/config"
"github.com/google/uuid" "api-service/internal/models/reference"
services "api-service/internal/services/bpjs"
"api-service/pkg/logger"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
) )
type VClaimHandler struct {} // VClaimHandler handles VClaim BPJS services
type VClaimHandler struct {
func NewVClaimHandler() *VClaimHandler { service reference.VClaimService
return &VClaimHandler{} validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
} }
// VClaimHandlerConfig contains configuration for VClaimHandler
type VClaimHandlerConfig struct {
BpjsConfig config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// NewVClaimHandler creates a new VClaimHandler
func NewVClaimHandler(cfg VClaimHandlerConfig) *VClaimHandler {
baseService := services.NewService(cfg.BpjsConfig)
adapter := services.NewVClaimAdapter(baseService)
return &VClaimHandler{
service: adapter,
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
}
// // GetPESERTA retrieves Peserta data
// @Summary Get Get Participant Info data
// @Summary Get Peserta data
// @Description Get participant eligibility information // @Description Get participant eligibility information
// @Tags vclaim,peserta // @Tags vclaim,peserta
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param nokartu path string true "nokartu"
// @Security ApiKeyAuth // @Param nokartu path string true "nokartu"
// @Success 200 {object} reference.PesertaResponse // @Success 200 {object} reference.PesertaResponse
// @Failure 400 {object} reference.ErrorResponse // @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse // @Failure 500 {object} reference.ErrorResponse
// @Router /Peserta/:nokartu [get] // @Router /peserta/:nokartu [get]
func (h *VClaimHandler) GetGet Participant Info(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(30)*time.Second) func (h *VClaimHandler) GetPESERTA(c *gin.Context) {
defer cancel() ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
reqID := c.GetHeader("X-Request-ID") defer cancel()
if reqID == "" {
reqID = uuid.New().String() // Generate request ID if not present
c.Header("X-Request-ID", reqID) requestID := c.GetHeader("X-Request-ID")
} if requestID == "" {
requestID = uuid.New().String()
nokartu := c.Param("nokartu") c.Header("X-Request-ID", requestID)
}
// TODO: Panggil service layer, mapping response, error handling dsb.
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": reqID}) h.logger.Info("Processing GetPeserta request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/peserta/:nokartu",
"nokartu": c.Param("nokartu"),
})
// Extract path parameters
nokartu := c.Param("nokartu")
if nokartu == "" {
h.logger.Error("Missing required parameter nokartu", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter nokartu",
RequestID: requestID,
})
return
}
// Call service method
var response reference.PesertaResponse
result, err := h.service.GetPeserta(ctx, nokartu)
if err != nil {
h.logger.Error("Failed to get Peserta", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Assign result to response
response.Status = "success"
response.RequestID = requestID
response.Data = result
c.JSON(http.StatusOK, response)
} }
// GetSEP retrieves Sep data
// @Summary Get Sep data
//
// @Summary Get SEP Management data
// @Description Manage SEP (Surat Eligibilitas Peserta) // @Description Manage SEP (Surat Eligibilitas Peserta)
// @Tags vclaim,sep // @Tags vclaim,sep
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param nosep path string true "nosep"
// @Security ApiKeyAuth // @Param nosep path string true "nosep"
// @Success 200 {object} reference.SEPResponse // @Success 200 {object} reference.SEPResponse
// @Failure 400 {object} reference.ErrorResponse // @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse // @Failure 500 {object} reference.ErrorResponse
// @Router /SEP/:nosep [get] // @Router /sep/:nosep [get]
func (h *VClaimHandler) GetSEP Management(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(30)*time.Second) func (h *VClaimHandler) GetSEP(c *gin.Context) {
defer cancel() ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
reqID := c.GetHeader("X-Request-ID") defer cancel()
if reqID == "" {
reqID = uuid.New().String() // Generate request ID if not present
c.Header("X-Request-ID", reqID) requestID := c.GetHeader("X-Request-ID")
} if requestID == "" {
requestID = uuid.New().String()
nosep := c.Param("nosep") c.Header("X-Request-ID", requestID)
}
// TODO: Panggil service layer, mapping response, error handling dsb.
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": reqID}) h.logger.Info("Processing GetSep request", map[string]interface{}{
"request_id": requestID,
"endpoint": "/sep/:nosep",
"nosep": c.Param("nosep"),
})
// Extract path parameters
nosep := c.Param("nosep")
if nosep == "" {
h.logger.Error("Missing required parameter nosep", map[string]interface{}{
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter nosep",
RequestID: requestID,
})
return
}
// Call service method
var response reference.SEPResponse
result, err := h.service.GetSEP(ctx, nosep)
if err != nil {
h.logger.Error("Failed to get Sep", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Assign result to response
response.Status = "success"
response.RequestID = requestID
response.Data = result
c.JSON(http.StatusOK, response)
} }
// CreateSEP creates new Sep
// // @Summary Create Sep
// @Summary Create SEP Management data
// @Description Manage SEP (Surat Eligibilitas Peserta) // @Description Manage SEP (Surat Eligibilitas Peserta)
// @Tags vclaim,sep // @Tags vclaim,sep
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Security ApiKeyAuth
// @Param request body reference.SEPRequest true "SEP Management data" // @Param request body reference.SEPRequest true "Sep data"
// @Success 201 {object} reference.SEPResponse // @Success 201 {object} reference.SEPResponse
// @Failure 400 {object} reference.ErrorResponse // @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse // @Failure 500 {object} reference.ErrorResponse
// @Router /sep [post] // @Router /sep [post]
func (h *VClaimHandler) CreateSEP Management(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(30)*time.Second) func (h *VClaimHandler) CreateSEP(c *gin.Context) {
defer cancel() ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
reqID := c.GetHeader("X-Request-ID") defer cancel()
if reqID == "" {
reqID = uuid.New().String() requestID := c.GetHeader("X-Request-ID")
c.Header("X-Request-ID", reqID) if requestID == "" {
} requestID = uuid.New().String()
var req reference.SEPRequest c.Header("X-Request-ID", requestID)
if err := c.ShouldBindJSON(&req); err != nil { }
c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error(), "request_id": reqID})
return h.logger.Info("Processing CreateSep request", map[string]interface{}{
} "request_id": requestID,
// TODO: Panggil service layer, validasi, error handling dsb. })
c.JSON(http.StatusCreated, gin.H{"status": "success", "request_id": reqID})
var req reference.SEPRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.logger.Error("Invalid request body", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// Validate request
if err := h.validator.Struct(&req); err != nil {
h.logger.Error("Validation failed", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
// Call service method
var response reference.SEPResponse
result, err := h.service.CreateSEP(ctx, &req)
if err != nil {
h.logger.Error("Failed to create Sep", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Assign result to response
response.Status = "success"
response.RequestID = requestID
response.Data = result
c.JSON(http.StatusCreated, response)
} }
//
// @Summary Update SEP Management data
// @Description Update Manage SEP (Surat Eligibilitas Peserta)
// @Tags vclaim,sep
// @Accept json
// @Produce json
// @Param nosep path string true "nosep"
// @Security ApiKeyAuth
// @Param request body reference.SEPRequest true "SEP Management data"
// @Success 200 {object} reference.SEPResponse
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router /sep/:nosep [put]
func (h *VClaimHandler) UpdateSEP Management(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
nosep := c.Param("nosep")
if nosep == "" {
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter nosep",
RequestID: requestID,
})
return
}
var req reference.SEPRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Invalid request body: " + err.Error(),
RequestID: requestID,
})
return
}
// TODO: Validasi, panggil service update
// result, err := h.service.UpdateSEP Management(ctx, nosep, &req)
// if err != nil {
// c.JSON(http.StatusInternalServerError, ...)
// return
// }
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": requestID})
}
//
// @Summary Delete SEP Management data
// @Description Delete Manage SEP (Surat Eligibilitas Peserta)
// @Tags vclaim,sep
// @Accept json
// @Produce json
// @Param nosep path string true "nosep"
// @Security ApiKeyAuth
// @Success 204 {object} nil
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router /sep/:nosep [delete]
func (h *VClaimHandler) DeleteSEP Management(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
nosep := c.Param("nosep")
if nosep == "" {
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter nosep",
RequestID: requestID,
})
return
}
// TODO: Panggil service delete
// err := h.service.DeleteSEP Management(ctx, nosep, )
// if err != nil {
// c.JSON(http.StatusInternalServerError, ...)
// return
// }
c.Status(http.StatusNoContent)
}
//
// @Summary Get Get Referral Info data
// @Description Get referral information
// @Tags vclaim,rujukan
// @Accept json
// @Produce json
// @Param norujukan path string true "norujukan"
// @Security ApiKeyAuth
// @Success 200 {object} reference.RujukanResponse
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router /rujukan/:norujukan [get]
func (h *VClaimHandler) GetGet Referral Info(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration(30)*time.Second)
defer cancel()
reqID := c.GetHeader("X-Request-ID")
if reqID == "" {
reqID = uuid.New().String()
c.Header("X-Request-ID", reqID)
}
norujukan := c.Param("norujukan")
// TODO: Panggil service layer, mapping response, error handling dsb.
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": reqID})
}

View File

@@ -0,0 +1,187 @@
package services
import (
"context"
"fmt"
"api-service/internal/models/reference"
)
// VClaimAdapter adapts the generic VClaimService to implement the reference.VClaimService interface
type VClaimAdapter struct {
service VClaimService
}
// NewVClaimAdapter creates a new VClaimAdapter
func NewVClaimAdapter(service VClaimService) *VClaimAdapter {
return &VClaimAdapter{
service: service,
}
}
// Get implements VClaimService.Get
func (a *VClaimAdapter) Get(ctx context.Context, endpoint string, result interface{}) error {
return a.service.Get(ctx, endpoint, result)
}
// Post implements VClaimService.Post
func (a *VClaimAdapter) Post(ctx context.Context, endpoint string, payload interface{}, result interface{}) error {
return a.service.Post(ctx, endpoint, payload, result)
}
// Put implements VClaimService.Put
func (a *VClaimAdapter) Put(ctx context.Context, endpoint string, payload interface{}, result interface{}) error {
return a.service.Put(ctx, endpoint, payload, result)
}
// Delete implements VClaimService.Delete
func (a *VClaimAdapter) Delete(ctx context.Context, endpoint string, result interface{}) error {
return a.service.Delete(ctx, endpoint, result)
}
// GetRawResponse implements VClaimService.GetRawResponse
func (a *VClaimAdapter) GetRawResponse(ctx context.Context, endpoint string) (*ResponDTOVclaim, error) {
return a.service.GetRawResponse(ctx, endpoint)
}
// PostRawResponse implements VClaimService.PostRawResponse
func (a *VClaimAdapter) PostRawResponse(ctx context.Context, endpoint string, payload interface{}) (*ResponDTOVclaim, error) {
return a.service.PostRawResponse(ctx, endpoint, payload)
}
// GetPeserta implements reference.VClaimService.GetPeserta
func (a *VClaimAdapter) GetPeserta(ctx context.Context, noKartu string) (*reference.PesertaData, error) {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response reference.PesertaData `json:"response"`
}
endpoint := fmt.Sprintf("/Peserta/%s", noKartu)
err := a.service.Get(ctx, endpoint, &response)
if err != nil {
return nil, err
}
if response.MetaData.Code != "200" {
return nil, fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return &response.Response, nil
}
// GetSEP implements reference.VClaimService.GetSEP
func (a *VClaimAdapter) GetSEP(ctx context.Context, noSep string) (*reference.SEPData, error) {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response reference.SEPData `json:"response"`
}
endpoint := fmt.Sprintf("/SEP/%s", noSep)
err := a.service.Get(ctx, endpoint, &response)
if err != nil {
return nil, err
}
if response.MetaData.Code != "200" {
return nil, fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return &response.Response, nil
}
// CreateSEP implements reference.VClaimService.CreateSEP
func (a *VClaimAdapter) CreateSEP(ctx context.Context, req *reference.SEPRequest) (*reference.SEPData, error) {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response reference.SEPData `json:"response"`
}
endpoint := "/SEP/2.0/insert"
err := a.service.Post(ctx, endpoint, req, &response)
if err != nil {
return nil, err
}
if response.MetaData.Code != "200" {
return nil, fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return &response.Response, nil
}
// UpdateSEP implements reference.VClaimService.UpdateSEP
func (a *VClaimAdapter) UpdateSEP(ctx context.Context, noSep string, req *reference.SEPRequest) (*reference.SEPData, error) {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response reference.SEPData `json:"response"`
}
endpoint := fmt.Sprintf("/SEP/%s", noSep)
err := a.service.Put(ctx, endpoint, req, &response)
if err != nil {
return nil, err
}
if response.MetaData.Code != "200" {
return nil, fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return &response.Response, nil
}
// DeleteSEP implements reference.VClaimService.DeleteSEP
func (a *VClaimAdapter) DeleteSEP(ctx context.Context, noSep string) error {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
}
endpoint := fmt.Sprintf("/SEP/%s", noSep)
err := a.service.Delete(ctx, endpoint, &response)
if err != nil {
return err
}
if response.MetaData.Code != "200" {
return fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return nil
}
// GetRujukan implements reference.VClaimService.GetRujukan
func (a *VClaimAdapter) GetRujukan(ctx context.Context, noRujukan string) (*reference.RujukanData, error) {
var response struct {
MetaData struct {
Code string `json:"code"`
Message string `json:"message"`
} `json:"metaData"`
Response reference.RujukanData `json:"response"`
}
endpoint := fmt.Sprintf("/Rujukan/%s", noRujukan)
err := a.service.Get(ctx, endpoint, &response)
if err != nil {
return nil, err
}
if response.MetaData.Code != "200" {
return nil, fmt.Errorf("BPJS API error: %s - %s", response.MetaData.Code, response.MetaData.Message)
}
return &response.Response, nil
}

View File

@@ -1,11 +1,9 @@
# services-config-complete.yaml # services-config-simple.yaml
global: global:
module_name: "api-service" module_name: "api-service"
output_dir: "internal/handlers" output_dir: "internal/handlers"
package_prefix: "api-service"
enable_swagger: true enable_swagger: true
enable_logging: true enable_logging: true
enable_metrics: true
services: services:
vclaim: vclaim:
@@ -16,29 +14,20 @@ services:
base_url: "https://apijkn.bpjs-kesehatan.go.id/vclaim-rest" base_url: "https://apijkn.bpjs-kesehatan.go.id/vclaim-rest"
timeout: 30 timeout: 30
retry_count: 3 retry_count: 3
middleware:
- "RequestLogger"
- "ResponseLogger"
- "RateLimiter"
dependencies:
- "database"
- "redis"
endpoints: endpoints:
peserta: peserta:
methods: ["GET"] methods: ["GET"]
get_path: "/Peserta/:nokartu" get_path: "/peserta/:nokartu"
model: "PesertaRequest" model: "PesertaRequest"
response_model: "PesertaResponse" response_model: "PesertaResponse"
description: "Get participant eligibility information" description: "Get participant eligibility information"
summary: "Get Participant Info" summary: "Get Participant Info"
tags: ["vclaim", "peserta"] tags: ["vclaim", "peserta"]
require_auth: true
rate_limit: 100
cache_enabled: true cache_enabled: true
cache_ttl: 300 cache_ttl: 300
sep: sep:
methods: ["GET", "POST", "PUT", "DELETE"] methods: ["GET", "POST", "PUT", "DELETE"]
get_path: "/SEP/:nosep" get_path: "/sep/:nosep"
post_path: "/sep" post_path: "/sep"
put_path: "/sep/:nosep" put_path: "/sep/:nosep"
delete_path: "/sep/:nosep" delete_path: "/sep/:nosep"
@@ -47,24 +36,26 @@ services:
description: "Manage SEP (Surat Eligibilitas Peserta)" description: "Manage SEP (Surat Eligibilitas Peserta)"
summary: "SEP Management" summary: "SEP Management"
tags: ["vclaim", "sep"] tags: ["vclaim", "sep"]
require_auth: true
rate_limit: 50
cache_enabled: true cache_enabled: true
cache_ttl: 180 cache_ttl: 180
custom_headers:
X-Service: "VClaim"
X-Version: "2.0"
rujukan:
methods: ["GET"]
get_path: "/rujukan/:norujukan"
model: "RujukanRequest"
response_model: "RujukanResponse"
description: "Get referral information"
summary: "Get Referral Info"
tags: ["vclaim", "rujukan"]
require_auth: true
rate_limit: 100
cache_enabled: true
cache_ttl: 600
eclaim:
name: "EClaim"
category: "eclaim"
package: "eclaim"
description: "BPJS EClaim service for claim processing"
base_url: "https://apijkn.bpjs-kesehatan.go.id/new-eclaim-rest"
timeout: 60
retry_count: 2
endpoints:
klaim:
methods: ["GET", "POST", "PUT"]
get_path: "/klaim/:noklaim"
post_path: "/klaim"
put_path: "/klaim/:noklaim"
model: "KlaimRequest"
response_model: "KlaimResponse"
description: "Manage insurance claims"
summary: "Claim Management"
tags: ["eclaim", "klaim"]
cache_enabled: false

View File

@@ -1,25 +1,24 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync"
"text/template" "text/template"
"time" "time"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
) )
/* ---------- Model Konfig ---------- */ // ServiceConfig represents the main configuration structure
type ServiceConfig struct { type ServiceConfig struct {
Services map[string]Service `yaml:"services"` Services map[string]Service `yaml:"services"`
Global GlobalConfig `yaml:"global,omitempty"` Global GlobalConfig `yaml:"global,omitempty"`
} }
// GlobalConfig contains global configuration
type GlobalConfig struct { type GlobalConfig struct {
ModuleName string `yaml:"module_name"` ModuleName string `yaml:"module_name"`
OutputDir string `yaml:"output_dir"` OutputDir string `yaml:"output_dir"`
@@ -29,6 +28,7 @@ type GlobalConfig struct {
EnableMetrics bool `yaml:"enable_metrics"` EnableMetrics bool `yaml:"enable_metrics"`
} }
// Service represents individual service configuration
type Service struct { type Service struct {
Name string `yaml:"name"` Name string `yaml:"name"`
Category string `yaml:"category"` Category string `yaml:"category"`
@@ -38,10 +38,11 @@ type Service struct {
Timeout int `yaml:"timeout"` Timeout int `yaml:"timeout"`
RetryCount int `yaml:"retry_count"` RetryCount int `yaml:"retry_count"`
Endpoints map[string]Endpoint `yaml:"endpoints"` Endpoints map[string]Endpoint `yaml:"endpoints"`
Middleware []string `yaml:"middleware,omitempty"` Middleware []string `yaml:"middleware,omitempty"` // FIXED: Changed to []string
Dependencies []string `yaml:"dependencies,omitempty"` Dependencies []string `yaml:"dependencies,omitempty"` // FIXED: Changed to []string
} }
// Endpoint represents endpoint configuration
type Endpoint struct { type Endpoint struct {
Methods []string `yaml:"methods"` Methods []string `yaml:"methods"`
GetPath string `yaml:"get_path,omitempty"` GetPath string `yaml:"get_path,omitempty"`
@@ -58,11 +59,10 @@ type Endpoint struct {
RateLimit int `yaml:"rate_limit,omitempty"` RateLimit int `yaml:"rate_limit,omitempty"`
CacheEnabled bool `yaml:"cache_enabled"` CacheEnabled bool `yaml:"cache_enabled"`
CacheTTL int `yaml:"cache_ttl,omitempty"` CacheTTL int `yaml:"cache_ttl,omitempty"`
CustomHeaders map[string]string `yaml:"custom_headers,omitempty"` CustomHeaders map[string]string `yaml:"custom_headers,omitempty"` // ADDED: Missing field
} }
/* ---------- Data Template ---------- */ // TemplateData holds data for generating handlers
type TemplateData struct { type TemplateData struct {
ServiceName string ServiceName string
ServiceLower string ServiceLower string
@@ -82,338 +82,342 @@ type TemplateData struct {
HasSwagger bool HasSwagger bool
HasAuth bool HasAuth bool
HasCache bool HasCache bool
Dependencies []string Dependencies []string // FIXED: Changed to []string
Middleware []string Middleware []string // FIXED: Changed to []string
GlobalConfig GlobalConfig GlobalConfig GlobalConfig
} }
// EndpointData represents processed endpoint data
type EndpointData struct { type EndpointData struct {
Name string Name string
NameLower string NameLower string
NameUpper string NameUpper string
NameCamel string NameCamel string
Methods []string Methods []string
GetPath string GetPath string
PostPath string PostPath string
PutPath string PutPath string
DeletePath string DeletePath string
PatchPath string PatchPath string
Model string Model string
ResponseModel string ResponseModel string
Description string Description string
Summary string Summary string
Tags []string Tags []string
HasGet bool HasGet bool
HasPost bool HasPost bool
HasPut bool HasPut bool
HasDelete bool HasDelete bool
HasPatch bool HasPatch bool
RequireAuth bool RequireAuth bool
RateLimit int RateLimit int
CacheEnabled bool CacheEnabled bool
CacheTTL int CacheTTL int
PathParams []string PathParams []string
CustomHeaders map[string]string QueryParams []string
RequiredFields []string
OptionalFields []string
CustomHeaders map[string]string
} }
/* ---------- Template Handler ---------- */ // Template remains the same as before...
const handlerTemplate = ` const handlerTemplate = `
// Code generated by generate-handler.go; DO NOT EDIT. // Code generated by generate-dynamic-handler.go; DO NOT EDIT.
// Generated at: {{.Timestamp}} // Generated at: {{.Timestamp}}
// Service: {{.ServiceName}} ({{.Category}}) // Service: {{.ServiceName}} ({{.Category}})
// Description: {{.Description}}
package handlers package handlers
import ( import (
"context" "context"
"net/http" "fmt"
"time" "net/http"
"{{.ModuleName}}/internal/models/reference" "strconv"
"github.com/gin-gonic/gin" "strings"
"github.com/google/uuid" "time"
"{{.ModuleName}}/internal/config"
"{{.ModuleName}}/internal/models/reference"
"{{.ModuleName}}/internal/services/bpjs"
"{{.ModuleName}}/pkg/logger"
"github.com/gin-gonic/gin"
"github.com/go-playground/validator/v10"
"github.com/google/uuid"
) )
type {{.ServiceName}}Handler struct {} // {{.ServiceName}}Handler handles {{.ServiceName}} BPJS services
type {{.ServiceName}}Handler struct {
service services.{{.ServiceName}}Service
validator *validator.Validate
logger logger.Logger
config config.BpjsConfig
}
func New{{.ServiceName}}Handler() *{{.ServiceName}}Handler { // {{.ServiceName}}HandlerConfig contains configuration for {{.ServiceName}}Handler
return &{{.ServiceName}}Handler{} type {{.ServiceName}}HandlerConfig struct {
BpjsConfig config.BpjsConfig
Logger logger.Logger
Validator *validator.Validate
}
// New{{.ServiceName}}Handler creates a new {{.ServiceName}}Handler
func New{{.ServiceName}}Handler(cfg {{.ServiceName}}HandlerConfig) *{{.ServiceName}}Handler {
return &{{.ServiceName}}Handler{
service: services.NewService(cfg.BpjsConfig),
validator: cfg.Validator,
logger: cfg.Logger,
config: cfg.BpjsConfig,
}
} }
{{range .Endpoints}} {{range .Endpoints}}
{{if .HasGet}} {{if .HasGet}}
// // Get{{.NameUpper}} retrieves {{.Name}} data
{{if $.HasSwagger}}
// @Summary Get {{.Name}} data // @Summary Get {{.Name}} data
// @Description {{.Description}} // @Description {{.Description}}
// @Tags {{join .Tags ","}} // @Tags {{join .Tags ","}}
// @Accept json // @Accept json
// @Produce json // @Produce json
{{range .PathParams}}// @Param {{.}} path string true "{{.}}" {{if .RequireAuth}}
// @Security ApiKeyAuth
{{end}} {{end}}
{{if .RequireAuth}}// @Security ApiKeyAuth {{range .PathParams}}
// @Param {{.}} path string true "{{.}}"
{{end}} {{end}}
// @Success 200 {object} reference.{{.ResponseModel}} // @Success 200 {object} reference.{{.ResponseModel}}
// @Failure 400 {object} reference.ErrorResponse // @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse // @Failure 500 {object} reference.ErrorResponse
// @Router {{.GetPath}} [get] // @Router {{.GetPath}} [get]
func (h *{{$.ServiceName}}Handler) Get{{.Name}}(c *gin.Context) { {{end}}
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration({{$.Timeout}})*time.Second) func (h *{{$.ServiceName}}Handler) Get{{.NameUpper}}(c *gin.Context) {
defer cancel() ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
reqID := c.GetHeader("X-Request-ID") defer cancel()
if reqID == "" {
reqID = uuid.New().String() // Generate request ID if not present
c.Header("X-Request-ID", reqID) requestID := c.GetHeader("X-Request-ID")
} if requestID == "" {
{{range .PathParams}} requestID = uuid.New().String()
{{.}} := c.Param("{{.}}") c.Header("X-Request-ID", requestID)
{{end}} }
// TODO: Panggil service layer, mapping response, error handling dsb.
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": reqID}) {{if $.HasLogger}}
h.logger.Info("Processing Get{{.Name}} request", map[string]interface{}{
"request_id": requestID,
"endpoint": "{{.GetPath}}",
{{range .PathParams}}
"{{.}}": c.Param("{{.}}"),
{{end}}
})
{{end}}
// Extract path parameters
{{range .PathParams}}
{{.}} := c.Param("{{.}}")
if {{.}} == "" {
{{if $.HasLogger}}
h.logger.Error("Missing required parameter {{.}}", map[string]interface{}{
"request_id": requestID,
})
{{end}}
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter {{.}}",
RequestID: requestID,
})
return
}
{{end}}
// Call service method
var response reference.{{.ResponseModel}}
{{if .PathParams}}
result, err := h.service.Get{{.NameUpper}}(ctx{{range .PathParams}}, {{.}}{{end}})
{{else}}
result, err := h.service.Get{{.NameUpper}}(ctx)
{{end}}
if err != nil {
{{if $.HasLogger}}
h.logger.Error("Failed to get {{.Name}}", map[string]interface{}{
"error": err.Error(),
"request_id": requestID,
})
{{end}}
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// Ensure response has proper fields
response.Status = "success"
response.RequestID = requestID
c.JSON(http.StatusOK, response)
} }
{{end}} {{end}}
{{if .HasPost}} {{if .HasPost}}
// // Create{{.NameUpper}} creates new {{.Name}}
// @Summary Create {{.Name}} data {{if $.HasSwagger}}
// @Summary Create {{.Name}}
// @Description {{.Description}} // @Description {{.Description}}
// @Tags {{join .Tags ","}} // @Tags {{join .Tags ","}}
// @Accept json // @Accept json
// @Produce json // @Produce json
{{if .RequireAuth}}// @Security ApiKeyAuth {{if .RequireAuth}}
// @Security ApiKeyAuth
{{end}} {{end}}
// @Param request body reference.{{.Model}} true "{{.Name}} data" // @Param request body reference.{{.Model}} true "{{.Name}} data"
// @Success 201 {object} reference.{{.ResponseModel}} // @Success 201 {object} reference.{{.ResponseModel}}
// @Failure 400 {object} reference.ErrorResponse // @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse // @Failure 500 {object} reference.ErrorResponse
// @Router {{.PostPath}} [post] // @Router {{.PostPath}} [post]
func (h *{{$.ServiceName}}Handler) Create{{.Name}}(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), time.Duration({{$.Timeout}})*time.Second)
defer cancel()
reqID := c.GetHeader("X-Request-ID")
if reqID == "" {
reqID = uuid.New().String()
c.Header("X-Request-ID", reqID)
}
var req reference.{{.Model}}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error(), "request_id": reqID})
return
}
// TODO: Panggil service layer, validasi, error handling dsb.
c.JSON(http.StatusCreated, gin.H{"status": "success", "request_id": reqID})
}
{{end}} {{end}}
{{if .HasPut}} func (h *{{$.ServiceName}}Handler) Create{{.NameUpper}}(c *gin.Context) {
// ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
// @Summary Update {{.Name}} data defer cancel()
// @Description Update {{.Description}}
// @Tags {{join .Tags ","}}
// @Accept json
// @Produce json
{{range .PathParams}}// @Param {{.}} path string true "{{.}}"
{{end}}
{{if .RequireAuth}}// @Security ApiKeyAuth
{{end}}
// @Param request body reference.{{.Model}} true "{{.Name}} data"
// @Success 200 {object} reference.{{.ResponseModel}}
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router {{.PutPath}} [put]
func (h *{{$.ServiceName}}Handler) Update{{.Name}}(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
{{range .PathParams}} requestID := c.GetHeader("X-Request-ID")
{{.}} := c.Param("{{.}}") if requestID == "" {
if {{.}} == "" { requestID = uuid.New().String()
c.JSON(http.StatusBadRequest, reference.ErrorResponse{ c.Header("X-Request-ID", requestID)
Status: "error", }
Message: "Missing required parameter {{.}}",
RequestID: requestID,
})
return
}
{{end}}
var req reference.{{.Model}} {{if $.HasLogger}}
if err := c.ShouldBindJSON(&req); err != nil { h.logger.Info("Processing Create{{.Name}} request", map[string]interface{}{
c.JSON(http.StatusBadRequest, reference.ErrorResponse{ "request_id": requestID,
Status: "error", })
Message: "Invalid request body: " + err.Error(), {{end}}
RequestID: requestID,
})
return
}
// TODO: Validasi, panggil service update var req reference.{{.Model}}
// result, err := h.service.Update{{.Name}}(ctx, {{range .PathParams}}{{.}}, {{end}}&req) if err := c.ShouldBindJSON(&req); err != nil {
// if err != nil { {{if $.HasLogger}}
// c.JSON(http.StatusInternalServerError, ...) h.logger.Error("Invalid request body", map[string]interface{}{
// return "error": err.Error(),
// } "request_id": requestID,
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": requestID}) })
} {{end}}
{{end}} c.JSON(http.StatusBadRequest, reference.ErrorResponse{
{{if .HasPatch}} Status: "error",
// Message: "Invalid request body: " + err.Error(),
// @Summary Patch {{.Name}} data RequestID: requestID,
// @Description Patch {{.Description}} })
// @Tags {{join .Tags ","}} return
// @Accept json }
// @Produce json
{{range .PathParams}}// @Param {{.}} path string true "{{.}}"
{{end}}
{{if .RequireAuth}}// @Security ApiKeyAuth
{{end}}
// @Param request body reference.{{.Model}} true "Partial {{.Name}} data"
// @Success 200 {object} reference.{{.ResponseModel}}
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router {{.PatchPath}} [patch]
func (h *{{$.ServiceName}}Handler) Patch{{.Name}}(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
{{range .PathParams}} // Validate request
{{.}} := c.Param("{{.}}") if err := h.validator.Struct(&req); err != nil {
if {{.}} == "" { {{if $.HasLogger}}
c.JSON(http.StatusBadRequest, reference.ErrorResponse{ h.logger.Error("Validation failed", map[string]interface{}{
Status: "error", "error": err.Error(),
Message: "Missing required parameter {{.}}", "request_id": requestID,
RequestID: requestID, })
}) {{end}}
return c.JSON(http.StatusBadRequest, reference.ErrorResponse{
} Status: "error",
{{end}} Message: "Validation failed: " + err.Error(),
RequestID: requestID,
})
return
}
var req reference.{{.Model}} // Call service method
if err := c.ShouldBindJSON(&req); err != nil { var response reference.{{.ResponseModel}}
c.JSON(http.StatusBadRequest, reference.ErrorResponse{ result, err := h.service.Create{{.NameUpper}}(ctx, &req)
Status: "error", if err != nil {
Message: "Invalid request body: " + err.Error(), {{if $.HasLogger}}
RequestID: requestID, h.logger.Error("Failed to create {{.Name}}", map[string]interface{}{
}) "error": err.Error(),
return "request_id": requestID,
} })
{{end}}
c.JSON(http.StatusInternalServerError, reference.ErrorResponse{
Status: "error",
Message: "Internal server error",
RequestID: requestID,
})
return
}
// TODO: Validasi, panggil service patch // Ensure response has proper fields
// result, err := h.service.Patch{{.Name}}(ctx, {{range .PathParams}}{{.}}, {{end}}&req) response.Status = "success"
// if err != nil { response.RequestID = requestID
// c.JSON(http.StatusInternalServerError, ...) c.JSON(http.StatusCreated, response)
// return
// }
c.JSON(http.StatusOK, gin.H{"status": "success", "request_id": requestID})
}
{{end}}
{{if .HasDelete}}
//
// @Summary Delete {{.Name}} data
// @Description Delete {{.Description}}
// @Tags {{join .Tags ","}}
// @Accept json
// @Produce json
{{range .PathParams}}// @Param {{.}} path string true "{{.}}"
{{end}}
{{if .RequireAuth}}// @Security ApiKeyAuth
{{end}}
// @Success 204 {object} nil
// @Failure 400 {object} reference.ErrorResponse
// @Failure 500 {object} reference.ErrorResponse
// @Router {{.DeletePath}} [delete]
func (h *{{$.ServiceName}}Handler) Delete{{.Name}}(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), {{$.Timeout}}*time.Second)
defer cancel()
requestID := c.GetHeader("X-Request-ID")
if requestID == "" {
requestID = uuid.New().String()
c.Header("X-Request-ID", requestID)
}
{{range .PathParams}}
{{.}} := c.Param("{{.}}")
if {{.}} == "" {
c.JSON(http.StatusBadRequest, reference.ErrorResponse{
Status: "error",
Message: "Missing required parameter {{.}}",
RequestID: requestID,
})
return
}
{{end}}
// TODO: Panggil service delete
// err := h.service.Delete{{.Name}}(ctx, {{range .PathParams}}{{.}}, {{end}})
// if err != nil {
// c.JSON(http.StatusInternalServerError, ...)
// return
// }
c.Status(http.StatusNoContent)
} }
{{end}} {{end}}
{{end}} {{end}}
` `
/* ---------- Main ---------- */
func main() { func main() {
flag.Usage = usage if len(os.Args) < 2 {
outFlag := flag.String("o", "", "override output directory") printUsage()
serviceFlag := flag.String("s", "", "generate only selected service name")
tmplFlag := flag.String("tmpl", "", "custom handler template path")
flag.Parse()
if flag.NArg() < 1 {
usage()
os.Exit(1) os.Exit(1)
} }
configFile := flag.Arg(0) configFile := os.Args[1]
var targetService string
if len(os.Args) > 2 {
targetService = os.Args[2]
}
// Load configuration
config, err := loadConfig(configFile) config, err := loadConfig(configFile)
if err != nil { if err != nil {
fmt.Printf("❌ Error loading config: %v\n", err) fmt.Printf("❌ Error loading config: %v\n", err)
os.Exit(1) os.Exit(1)
} }
outDir := firstNonEmpty(*outFlag, config.Global.OutputDir, "internal/handlers") fmt.Println("🚀 Starting BPJS Dynamic Handler Generation...")
templatePath := firstNonEmpty(*tmplFlag, "") fmt.Printf("📁 Config file: %s\n", configFile)
if targetService != "" {
// Template setup fmt.Printf("🎯 Target service: %s\n", targetService)
var tmpl *template.Template
if templatePath != "" {
tmpl, err = template.New("handler").Funcs(templateFuncMap()).ParseFiles(templatePath)
} else {
tmpl, err = template.New("handler").Funcs(templateFuncMap()).Parse(handlerTemplate)
}
if err != nil {
fmt.Printf("❌ Error parsing template: %v\n", err)
os.Exit(1)
} }
var wg sync.WaitGroup generated := 0
for svcName, svc := range config.Services { errors := 0
if *serviceFlag != "" && svcName != *serviceFlag {
// Generate handlers
for serviceName, service := range config.Services {
if targetService != "" && serviceName != targetService {
continue continue
} }
wg.Add(1)
go func(serviceName string, service Service) { fmt.Printf("🔧 Generating handler for service: %s (%s)\n", service.Name, service.Category)
defer wg.Done() err := generateHandler(serviceName, service, config.Global)
err := generateHandler(serviceName, service, config.Global, outDir, tmpl) if err != nil {
if err != nil { fmt.Printf("❌ Error generating handler for %s: %v\n", serviceName, err)
fmt.Printf("❌ Error generating handler for %s: %v\n", serviceName, err) errors++
} else { continue
fmt.Printf("✅ Generated handler: %s_handler.go\n", strings.ToLower(serviceName)) }
} fmt.Printf("✅ Generated handler: %s_handler.go\n", strings.ToLower(serviceName))
}(svcName, svc) generated++
} }
wg.Wait()
// Summary
fmt.Println("\n📊 Generation Summary:")
fmt.Printf(" ✅ Successfully generated: %d handlers\n", generated)
if errors > 0 {
fmt.Printf(" ❌ Failed: %d handlers\n", errors)
}
if generated > 0 {
fmt.Println("🎉 Generation completed successfully!")
}
}
func printUsage() {
fmt.Println("BPJS Dynamic Handler Generator")
fmt.Println()
fmt.Println("Usage:")
fmt.Println(" go run generate-dynamic-handler.go <config-file> [service-name]")
fmt.Println()
fmt.Println("Examples:")
fmt.Println(" go run generate-dynamic-handler.go services-config.yaml")
fmt.Println(" go run generate-dynamic-handler.go services-config.yaml vclaim")
} }
func loadConfig(filename string) (*ServiceConfig, error) { func loadConfig(filename string) (*ServiceConfig, error) {
@@ -427,104 +431,140 @@ func loadConfig(filename string) (*ServiceConfig, error) {
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to parse YAML config: %w", err) return nil, fmt.Errorf("failed to parse YAML config: %w", err)
} }
// Set default values
if config.Global.ModuleName == "" { if config.Global.ModuleName == "" {
config.Global.ModuleName = "api-service" config.Global.ModuleName = "api-service"
} }
if config.Global.OutputDir == "" { if config.Global.OutputDir == "" {
config.Global.OutputDir = "internal/handlers" config.Global.OutputDir = "internal/handlers"
} }
return &config, nil return &config, nil
} }
func generateHandler(serviceName string, service Service, globalConfig GlobalConfig, outDir string, tmpl *template.Template) error { func generateHandler(serviceName string, service Service, globalConfig GlobalConfig) error {
td := prepareTemplateData(serviceName, service, globalConfig) // Prepare template data
if err := os.MkdirAll(outDir, 0o755); err != nil { templateData := TemplateData{
return fmt.Errorf("failed to create output directory: %w", err) ServiceName: service.Name,
} ServiceLower: strings.ToLower(service.Name),
filename := filepath.Join(outDir, fmt.Sprintf("%s_handler.go", td.ServiceLower)) ServiceUpper: strings.ToUpper(service.Name),
file, err := os.Create(filename) Category: service.Category,
if err != nil { Package: service.Package,
return fmt.Errorf("failed to create handler file: %w", err) Description: service.Description,
} BaseURL: service.BaseURL,
defer file.Close() Timeout: getOrDefault(service.Timeout, 30),
return tmpl.Execute(file, td) RetryCount: getOrDefault(service.RetryCount, 3),
}
func prepareTemplateData(serviceName string, svc Service, globalConfig GlobalConfig) TemplateData {
td := TemplateData{
ServiceName: svc.Name,
ServiceLower: strings.ToLower(svc.Name),
ServiceUpper: strings.ToUpper(svc.Name),
Category: svc.Category,
Package: svc.Package,
Description: svc.Description,
BaseURL: svc.BaseURL,
Timeout: getOrDefault(svc.Timeout, 30),
RetryCount: getOrDefault(svc.RetryCount, 3),
Timestamp: time.Now().Format("2006-01-02 15:04:05"), Timestamp: time.Now().Format("2006-01-02 15:04:05"),
ModuleName: globalConfig.ModuleName, ModuleName: globalConfig.ModuleName,
HasValidator: true, HasValidator: true,
HasLogger: globalConfig.EnableLogging, HasLogger: globalConfig.EnableLogging,
HasMetrics: globalConfig.EnableMetrics, HasMetrics: globalConfig.EnableMetrics,
HasSwagger: globalConfig.EnableSwagger, HasSwagger: globalConfig.EnableSwagger,
Dependencies: svc.Dependencies, Dependencies: service.Dependencies, // Now []string
Middleware: svc.Middleware, Middleware: service.Middleware, // Now []string
GlobalConfig: globalConfig, GlobalConfig: globalConfig,
} }
for _, ep := range svc.Endpoints {
ed := processEndpoint(ep) // Check for advanced features
if ed.RequireAuth { for _, endpoint := range service.Endpoints {
td.HasAuth = true if endpoint.RequireAuth {
templateData.HasAuth = true
} }
if ed.CacheEnabled { if endpoint.CacheEnabled {
td.HasCache = true templateData.HasCache = true
} }
td.Endpoints = append(td.Endpoints, ed)
} }
return td
// Process endpoints
for endpointName, endpoint := range service.Endpoints {
endpointData := processEndpoint(endpointName, endpoint)
templateData.Endpoints = append(templateData.Endpoints, endpointData)
}
// Create output directory
outputDir := globalConfig.OutputDir
if outputDir == "" {
outputDir = "internal/handlers"
}
if err := os.MkdirAll(outputDir, 0755); err != nil {
return fmt.Errorf("failed to create output directory: %w", err)
}
// Generate handler file
filename := filepath.Join(outputDir, fmt.Sprintf("%s_handler.go", strings.ToLower(serviceName)))
// Create template with custom functions
tmpl := template.New("handler").Funcs(template.FuncMap{
"contains": strings.Contains,
"join": strings.Join,
"title": strings.Title,
"trimPrefix": strings.TrimPrefix,
})
tmpl, err := tmpl.Parse(handlerTemplate)
if err != nil {
return fmt.Errorf("failed to parse template: %w", err)
}
file, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to create file: %w", err)
}
defer file.Close()
err = tmpl.Execute(file, templateData)
if err != nil {
return fmt.Errorf("failed to execute template: %w", err)
}
return nil
} }
func processEndpoint(ep Endpoint) EndpointData { func processEndpoint(name string, endpoint Endpoint) EndpointData {
data := EndpointData{ data := EndpointData{
Name: strings.Title(ep.Summary), Name: strings.Title(name),
NameLower: strings.ToLower(ep.Summary), NameLower: strings.ToLower(name),
NameUpper: strings.ToUpper(ep.Summary), NameUpper: strings.ToUpper(name),
NameCamel: toCamelCase(ep.Summary), NameCamel: toCamelCase(name),
Methods: ep.Methods, Methods: endpoint.Methods,
GetPath: ep.GetPath, GetPath: endpoint.GetPath,
PostPath: ep.PostPath, PostPath: endpoint.PostPath,
PutPath: ep.PutPath, PutPath: endpoint.PutPath,
DeletePath: ep.DeletePath, DeletePath: endpoint.DeletePath,
PatchPath: ep.PatchPath, PatchPath: endpoint.PatchPath,
Model: ep.Model, Model: endpoint.Model,
ResponseModel: ep.ResponseModel, ResponseModel: endpoint.ResponseModel,
Description: ep.Description, Description: endpoint.Description,
Summary: ep.Summary, Summary: endpoint.Summary,
Tags: ep.Tags, Tags: endpoint.Tags,
RequireAuth: ep.RequireAuth, RequireAuth: endpoint.RequireAuth,
RateLimit: ep.RateLimit, RateLimit: endpoint.RateLimit,
CacheEnabled: ep.CacheEnabled, CacheEnabled: endpoint.CacheEnabled,
CacheTTL: getOrDefault(ep.CacheTTL, 300), CacheTTL: getOrDefault(endpoint.CacheTTL, 300),
CustomHeaders: ep.CustomHeaders, CustomHeaders: endpoint.CustomHeaders,
} }
for _, method := range ep.Methods {
// Set method flags and extract path parameters
for _, method := range endpoint.Methods {
switch strings.ToUpper(method) { switch strings.ToUpper(method) {
case "GET": case "GET":
data.HasGet = true data.HasGet = true
data.PathParams = extractPathParams(ep.GetPath) data.PathParams = extractPathParams(endpoint.GetPath)
case "POST": case "POST":
data.HasPost = true data.HasPost = true
case "PUT": case "PUT":
data.HasPut = true data.HasPut = true
data.PathParams = extractPathParams(ep.PutPath) data.PathParams = extractPathParams(endpoint.PutPath)
case "DELETE": case "DELETE":
data.HasDelete = true data.HasDelete = true
data.PathParams = extractPathParams(ep.DeletePath) data.PathParams = extractPathParams(endpoint.DeletePath)
case "PATCH": case "PATCH":
data.HasPatch = true data.HasPatch = true
data.PathParams = extractPathParams(ep.PatchPath) data.PathParams = extractPathParams(endpoint.PatchPath)
} }
} }
return data return data
} }
@@ -532,6 +572,7 @@ func extractPathParams(path string) []string {
if path == "" { if path == "" {
return nil return nil
} }
var params []string var params []string
parts := strings.Split(path, "/") parts := strings.Split(path, "/")
for _, part := range parts { for _, part := range parts {
@@ -539,6 +580,7 @@ func extractPathParams(path string) []string {
params = append(params, strings.TrimPrefix(part, ":")) params = append(params, strings.TrimPrefix(part, ":"))
} }
} }
return params return params
} }
@@ -546,13 +588,16 @@ func toCamelCase(str string) string {
words := strings.FieldsFunc(str, func(c rune) bool { words := strings.FieldsFunc(str, func(c rune) bool {
return c == '_' || c == '-' || c == ' ' return c == '_' || c == '-' || c == ' '
}) })
if len(words) == 0 { if len(words) == 0 {
return str return str
} }
result := strings.Title(strings.ToLower(words[0]))
result := strings.ToLower(words[0])
for _, word := range words[1:] { for _, word := range words[1:] {
result += strings.Title(strings.ToLower(word)) result += strings.Title(strings.ToLower(word))
} }
return result return result
} }
@@ -562,32 +607,3 @@ func getOrDefault(value, defaultValue int) int {
} }
return value return value
} }
func firstNonEmpty(vals ...string) string {
for _, v := range vals {
if v != "" {
return v
}
}
return ""
}
func templateFuncMap() template.FuncMap {
return template.FuncMap{
"contains": strings.Contains,
"join": strings.Join,
"title": strings.Title,
"trimPrefix": strings.TrimPrefix,
}
}
func usage() {
fmt.Println("BPJS Dynamic Handler Generator")
fmt.Println(`Usage:
go run generate-handler.go [flags] <yaml-config-file>
Flags:
-o Output directory
-s Single service name
-tmpl Custom handler template path
`)
}