[WebApp] Protocal22-API 사용예제 (GoLang)

[WebApp] Protocal22-API 사용예제2 

 

 

 시작하기 전에 

 이 문서는 Dabory OwnerKey API for WebApp을 사용해 main app과 guest app 개발시 필요한 참고 정보를 안내합니다. 

 

  WebApp 사용예제 

 2. WebApp 사용 예제 

 📌 GateToken 발급 스케줄러 

 package main

func main() {

	// 새로운 고루틴(Goroutine) 실행: 백그라운드에서 주기적으로 실행됨

	go func() {

		for {

			// 1. UpdateGateTokenIfNeeded() 함수 호출 (GateToken 발급 및 업데이트)

			err := controllers_func.UpdateGateTokenIfNeeded()

			

			// 2. 만약 에러가 발생하면 로그를 남김

			if err != nil {

				e.ErrLog("UpdateGateTokenIfNeeded Error", err)

			}

			// 3. 2초 동안 대기 후 반복 (즉, 2초마다 실행됨)

			time.Sleep(2 * time.Second)

		}

	}()

	// 주의: main 함수가 종료되면 고루틴도 종료됨

	select {} // main 함수가 종료되지 않도록 무한 대기

}

 

 📌 "OwnerKey"를 활용한 GateToken, BackUrl 반환 

 Host의 dabory-app/gate-token-get을 호출 -> Host -> main_api (GateToken) 반환 

 

// GateToken을 요청하는 함수

func UpdateGateTokenIfNeeded() error {

	myOwnerKey := "My_OwnerKey" //OwnerKey (GateToken 발급 주체 선정을 위해 사용)

	// GateToken을 요청 (OwnerKey를 사용하여 요청)

	err := locals.GuestGateTokenGets(myOwnerKey)

	if err != nil {

		fmt.Println("GateToken 요청 실패:", err)

		return err

	}

	return nil

}

type AppApi struct {

	ApiUrl string

	GateToken string

}

var GAppApis [2]AppApi // GateToken, ApiUrl 저장 장소 

func GuestGateTokenGets(myOnwerKey string) error { 

	appType := 0 //Dbupdate

	// 0:keypair, 1:Dbu // "SsoConnString" Must be Deprecated

	var err error

	if myOnwerKey != "" { 

		// e.LogStr("lskdjqfals", e.LogFuncName()+"; GuestGateTokenOwner with OwnerKey: "+myOnwerKey)

		_, _, err = GuestGateTokenOwner(appType, "https://host_domain_URL.com", myOnwerKey) // app type -> OwnerCode

 // Host Domain URL, OwnerKey를 매개변수로 던짐

		if err != nil {

			return e.ErrLog(e.FuncRun("23rfsr3qrase", e.CurrFuncName()), err)

		}

	} 

	return nil

}

func GuestGateTokenOwner(appType int, pivotUrl string, ownerKey string) (string, string, error) { // HOST URL/dabory-app -> pivot URL

	var appTypeCode string

	if appType == 0 {

		appTypeCode = "keypair"

	} else if appType == 1 {

		appTypeCode = "dbupdate"

	}

	if GAppApis[appType].GateToken != "" { // 할당되어 있는 경우 (이미 GateToken이 있는 경우)

		// fmt.Println("34092ujfa : "+"Using GateToken in ARRAY to access : ", GAppApis[0].GateToken)

	} else { // (GateToken이 없는 경우 발급 로직)

		fmt.Println("34092ujfa : " + "isn't exist GateToken in ARRAY to access ")

		vGt := &GateTokenGetReq{

			OwnerKey: ownerKey,

		}

		bodyBytes, _ := json.Marshal(vGt)

		frontUrl := pivotUrl + "/dabory-app/gate-token-get" 

		msgBytes, staInt, err := HttpResponseSimplePost("POST", frontUrl, bodyBytes) 

 // Strong -> Host Lalavel로 Http 요청 -> Lalavel -> main_api로 GateToken 요청

		e.LogStr("23rfsr3qr-GateTokenGetReq", e.LogFuncName()+"; Raravel frontUrl : "+frontUrl)

		if err != nil {

			return "", "", e.ErrLog(e.FuncRun("45425fd34sd-The HTTP request "+frontUrl, e.CurrFuncName()), err)

		}

		if staInt != 200 {

			TrackFailure() // 요청 실패 시 실패 기록 추가

			fmt.Println("GateToken 요청 실패:", err, "(최근 1시간 내 실패 횟수:", len(failTimestamps), ")", "반환 Code : ", staInt)

			// 최근 1시간 동안 실패 횟수가 maxFailures(3) 이상이면 프로그램 종료

			if len(failTimestamps) >= maxFailures {

				fmt.Println("1시간 내 GateToken 요청이", maxFailures, "번 실패 -> 스케줄러를 종료")

				os.Exit(1) // 프로그램 종료

			}

			return "", "", errors.New(e.FuncRun("87ty344ra3-Request Fail "+string(msgBytes), e.CurrFuncName()))

		}

		failTimestamps = []int64{} // 성공 시 실패 기록 초기화

		ret := &struct {

			ApiUrl string 

			GateToken string

		}{}

		if err := json.Unmarshal(msgBytes, ret); err != nil { // GateToken과 BackendUrl을 ret 구조체에 할당

			return "", "", e.ErrLog(e.FuncRun("45425fd34sd-Json Format "+frontUrl, e.CurrFuncName()), err)

		}

 // 새로 받은 GateToken을 전역 변수에 저장

		GAppApis[appType].ApiUrl = ret.ApiUrl

		GAppApis[appType].GateToken = ret.GateToken

		e.OkLog("Just Added GateToken in ARRAY to access AppType: " + appTypeCode)

		e.OkLog("Just Added GateToken in ARRAY to access AppType: " + ret.GateToken)

		e.OkLog("Just Added GateToken in ARRAY to access AppType: " + ret.ApiUrl) // main_api URL

	}

	return GAppApis[appType].ApiUrl, GAppApis[appType].GateToken, nil

}

 

 

 

 📌 발급받은 GateToken을 사용하여 main_api 요청 

 // 🔹 API 요청을 수행하는 함수

func process() {

	// 1. GateToken과 API URL 가져오기

	apiUrl := locals.GAppApis[0].ApiUrl // API 요청을 보낼 기본 URL

	gateToken := locals.GAppApis[0].GateToken // API 요청 시 필요한 인증 토큰

	// 2. 요청할 API 엔드포인트 설정 (credit-page 요청)

	mainApiURL := apiUrl + "/credit-page"

	// 3. 요청 바디 구성 (전달할 데이터)

	requestBody := map[string]interface{}{

		"PageVars": map[string]interface{}{

			"Fields": "credit_no", 

			"Limit": 1, 

			"Desc": "id", 

			"MyFilter": "", 

			"QueryCnt": 0, 

			"Query": "", 

			"Asc": "", 

			"Offset": 0, 

			"ReturnJson": "", 

		},

	}

	// 4. API 요청 실행 (GateToken 포함)

	Body, err := RequestWithGateToken(mainApiURL, gateToken, requestBody)

	if err != nil {

		// 요청 실패 시 에러 로그 출력

		e.ErrLog("API 요청 실패: ", err)

		return

	}

	// 5. 응답 데이터 출력

	fmt.Println("API 응답 데이터:", string(Body))

}

 

 

 

 

 📌 저장된 GateToken으로 요청 (만료된 GateToken 재 발급) 

 // GateToken을 사용하여 API 요청을 보내는 함수

func RequestWithGateToken(mainApiURL string, gateToken string, requestBody map[string]interface{}) ([]byte, error) {

	// 1. HTTP 요청 보내기 (기존 GateToken 사용)

	resp, body, err := SendHttpRequest(mainApiURL, gateToken, requestBody)

	if err != nil {

		fmt.Println("HTTP 요청 실패:", err)

		return nil, err

	}

	defer resp.Body.Close()

	fmt.Println("응답 본문:", string(body)) // API 응답 출력

	// 2. 응답 코드가 505라면 -> GateToken 만료 (새로운 GateToken 발급 필요)

	if resp.StatusCode == 505 {

		fmt.Println("GateToken 만료! 새로운 GateToken 발급 시도..")

		// 기존 만료된 GateToken 초기화

		locals.GAppApis[0] = locals.AppApi{}

		// 스케줄러가 새로운 GateToken이 얻어올 때까지 대기 (최대 5초마다 확인)

		for locals.GAppApis[0].GateToken == "" {

			fmt.Println("새로운 GateToken 발급 중..")

			time.Sleep(5 * time.Second)

		}

		fmt.Println("새로운 GateToken 발급 완료!")

		// 새로운 GateToken으로 API 재요청

		newGateToken := locals.GAppApis[0].GateToken

		resp, body, err := SendHttpRequest(mainApiURL, newGateToken, requestBody)

		if err != nil {

			fmt.Println("HTTP 요청 실패:", err)

			return nil, err

		}

		defer resp.Body.Close()

		// 새로운 요청 응답 확인

		if resp.StatusCode == 200 {

			e.OkLog("새로운 GateToken을 사용한 HTTP 요청 성공!")

			return body, nil

		} else {

			return nil, fmt.Errorf("새로운 GateToken 요청 실패, 상태 코드: %d", resp.StatusCode)

		}

	}

	// 기존 GateToken으로 요청 성공한 경우

	e.OkLog("기존 GateToken을 사용한 HTTP 요청 성공!")

	return body, nil

}

// HTTP 요청을 보내는 함수

func SendHttpRequest(mainApiURL string, gateToken string, requestBody map[string]interface{}) (*http.Response, []byte, error) {

	// 1. JSON 데이터로 변환

	jsonData, err := json.Marshal(requestBody)

	if err != nil {

		fmt.Println("JSON 변환 실패:", err)

		return nil, nil, err

	}

	// 2. HTTP 요청 생성 (POST 요청)

	req, err := http.NewRequest("POST", mainApiURL, bytes.NewBuffer(jsonData))

	if err != nil {

		fmt.Println("HTTP 요청 생성 실패:", err)

		return nil, nil, err

	}

	// 3. HTTP 헤더 설정 (GateToken 포함)

	req.Header.Set("Content-Type", "application/json")

	req.Header.Set("GateToken", gateToken)

	// 4. HTTP 요청 실행

	client := &http.Client{}

	resp, err := client.Do(req)

	if err != nil {

		fmt.Println("HTTP 요청 실패:", err)

		return nil, nil, err

	}

	// 5. 응답 데이터 읽기

	body, err := io.ReadAll(resp.Body)

	if err != nil {

		fmt.Println("응답 본문 읽기 실패:", err)

		return nil, nil, err

	}

	// 6. 응답 로그 출력

	fmt.Println("응답 코드:", resp.StatusCode)

	fmt.Println("응답 본문:", string(body))

	return resp, body, nil

}