forked from devsam/core
refac, feat: API 호출 구조 재작성
- api.php에서 param path 강제 - api.php에서 GET param 허용 - SammoAPI 호출자를 axios에서 fetch 기반(ky)로 변경 - SammoAPI에서 단순 POST대신 REST에 따라 지정 가능하도록 재구성 - SammoAPI에서 NumVar, StrVar를 PathParam으로 변경하도록 변경 - API CallType들을 def/API로 분리 시작 - 일부 API를 시험삼아 변경(login)
This commit is contained in:
@@ -8,5 +8,9 @@ require(__DIR__ . '/vendor/autoload.php');
|
|||||||
if (!class_exists('\\sammo\\RootDB')) {
|
if (!class_exists('\\sammo\\RootDB')) {
|
||||||
Json::dieWithReason('No DB');
|
Json::dieWithReason('No DB');
|
||||||
}
|
}
|
||||||
|
$eParams = $_GET;
|
||||||
|
if(key_exists('path', $eParams)){
|
||||||
|
unset($eParams['path']);
|
||||||
|
}
|
||||||
|
|
||||||
APIHelper::launch(dirname(__FILE__), $_GET['path']??null);
|
APIHelper::launch(dirname(__FILE__), $_GET['path']??'', $eParams, true);
|
||||||
+6
-1
@@ -5,4 +5,9 @@ namespace sammo;
|
|||||||
include "lib.php";
|
include "lib.php";
|
||||||
include "func.php";
|
include "func.php";
|
||||||
|
|
||||||
APIHelper::launch(dirname(__FILE__), $_GET['path']??null);
|
$eParams = $_GET;
|
||||||
|
if(key_exists('path', $eParams)){
|
||||||
|
unset($eParams['path']);
|
||||||
|
}
|
||||||
|
|
||||||
|
APIHelper::launch(dirname(__FILE__), $_GET['path']??'', $eParams, true);
|
||||||
+40
-34
@@ -1,65 +1,71 @@
|
|||||||
import type { InvalidResponse, ReserveBulkCommandResponse } from "./defs";
|
import type { BettingDetailResponse, ReserveBulkCommandResponse } from "./defs";
|
||||||
import type { Args } from "./processing/args";
|
import type { Args } from "./processing/args";
|
||||||
import { callSammoAPI, done, type CallbackT, type RawArgType, type ValidResponse } from "./util/callSammoAPI";
|
import { callSammoAPI, extractHttpMethod, GET, PATCH, POST, PUT, type APITail, type APICallT, type RawArgType, type ValidResponse, type InvalidResponse } from "./util/callSammoAPI";
|
||||||
export type { ValidResponse, InvalidResponse };
|
export type { ValidResponse, InvalidResponse };
|
||||||
import { APIPathGen } from "./util/APIPathGen.js";
|
import { APIPathGen, NumVar } from "./util/APIPathGen.js";
|
||||||
|
|
||||||
const apiRealPath = {
|
const apiRealPath = {
|
||||||
Betting: {
|
Betting: {
|
||||||
Bet: done,
|
Bet: PUT,
|
||||||
GetBettingDetail: done,
|
GetBettingDetail: NumVar('betting_id',
|
||||||
GetBettingList: done,
|
GET as APICallT<undefined, BettingDetailResponse>
|
||||||
|
),
|
||||||
|
GetBettingList: GET,
|
||||||
},
|
},
|
||||||
Command: {
|
Command: {
|
||||||
GetReservedCommand: done,
|
GetReservedCommand: GET as APICallT<undefined>,
|
||||||
PushCommand: done,
|
PushCommand: PATCH,
|
||||||
RepeatCommand: done,
|
RepeatCommand: PATCH,
|
||||||
ReserveCommand: done,
|
ReserveCommand: PUT,
|
||||||
ReserveBulkCommand: done as CallbackT<{
|
ReserveBulkCommand: PUT as APICallT<{
|
||||||
turnList: number[],
|
turnList: number[],
|
||||||
action: string,
|
action: string,
|
||||||
arg: Args
|
arg: Args
|
||||||
}[], ReserveBulkCommandResponse>,
|
}[], ReserveBulkCommandResponse>,
|
||||||
},
|
},
|
||||||
General: {
|
General: {
|
||||||
Join: done,
|
Join: POST,
|
||||||
},
|
},
|
||||||
InheritAction: {
|
InheritAction: {
|
||||||
BuyHiddenBuff: done,
|
BuyHiddenBuff: PUT,
|
||||||
BuyRandomUnique: done,
|
BuyRandomUnique: PUT,
|
||||||
BuySpecificUnique: done,
|
BuySpecificUnique: PUT,
|
||||||
ResetSpecialWar: done,
|
ResetSpecialWar: PUT,
|
||||||
ResetTurnTime: done,
|
ResetTurnTime: PUT,
|
||||||
SetNextSpecialWar: done,
|
SetNextSpecialWar: PUT,
|
||||||
},
|
},
|
||||||
Misc: { UploadImage: done },
|
Misc: { UploadImage: POST },
|
||||||
NationCommand: {
|
NationCommand: {
|
||||||
GetReservedCommand: done,
|
GetReservedCommand: GET,
|
||||||
PushCommand: done,
|
PushCommand: PATCH,
|
||||||
RepeatCommand: done,
|
RepeatCommand: PATCH,
|
||||||
ReserveCommand: done,
|
ReserveCommand: PUT,
|
||||||
ReserveBulkCommand: done as CallbackT<{
|
ReserveBulkCommand: PUT as APICallT<{
|
||||||
turnList: number[],
|
turnList: number[],
|
||||||
action: string,
|
action: string,
|
||||||
arg: Args
|
arg: Args
|
||||||
}[], ReserveBulkCommandResponse>,
|
}[], ReserveBulkCommandResponse>,
|
||||||
},
|
},
|
||||||
Nation: {
|
Nation: {
|
||||||
SetNotice: done,
|
SetNotice: PUT,
|
||||||
SetScoutMsg: done,
|
SetScoutMsg: PUT,
|
||||||
SetBill: done,
|
SetBill: PUT,
|
||||||
SetRate: done,
|
SetRate: PUT,
|
||||||
SetSecretLimit: done,
|
SetSecretLimit: PUT,
|
||||||
SetBlockWar: done,
|
SetBlockWar: PUT,
|
||||||
SetBlockScout: done,
|
SetBlockScout: PUT,
|
||||||
},
|
},
|
||||||
|
Test: NumVar('id', {
|
||||||
|
SetThis: PUT,
|
||||||
|
})
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const SammoAPI = APIPathGen(apiRealPath, (path: string[]) => {
|
export const SammoAPI = APIPathGen(apiRealPath, (path: string[], tail: APITail, pathParam) => {
|
||||||
|
const method = extractHttpMethod(tail);
|
||||||
return (args?: RawArgType, returnError?: boolean) => {
|
return (args?: RawArgType, returnError?: boolean) => {
|
||||||
if (returnError) {
|
if (returnError) {
|
||||||
return callSammoAPI(path.join('/'), args, true);
|
return callSammoAPI(method, path.join('/'), args, pathParam, true);
|
||||||
}
|
}
|
||||||
return callSammoAPI(path.join('/'), args);
|
return callSammoAPI(method, path.join('/'), args, pathParam);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
+14
-10
@@ -1,21 +1,25 @@
|
|||||||
import type { InvalidResponse } from "./defs";
|
import type { AutoLoginFailed, AutoLoginNonceResponse, AutoLoginResponse } from "./defs/API/Login";
|
||||||
import { APIPathGen } from "./util/APIPathGen";
|
import { APIPathGen } from "./util/APIPathGen";
|
||||||
import { callSammoAPI, done, type ValidResponse } from "./util/callSammoAPI";
|
import { callSammoAPI, extractHttpMethod, GET, POST, type APICallT, type APITail, type InvalidResponse, type RawArgType, type ValidResponse } from "./util/callSammoAPI";
|
||||||
export type { ValidResponse, InvalidResponse };
|
export type { ValidResponse, InvalidResponse };
|
||||||
|
|
||||||
const apiRealPath = {
|
const apiRealPath = {
|
||||||
Login: {
|
Login: {
|
||||||
LoginByID: done,
|
LoginByID: POST,
|
||||||
LoginByToken: done,
|
LoginByToken: POST as APICallT<{
|
||||||
ReqNonce: done,
|
hashedToken: string,
|
||||||
|
token_id: number,
|
||||||
|
}, AutoLoginResponse, AutoLoginFailed>,
|
||||||
|
ReqNonce: GET as APICallT<undefined, AutoLoginNonceResponse, AutoLoginFailed>
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const SammoRootAPI = APIPathGen(apiRealPath, (path: string[]) => {
|
export const SammoRootAPI = APIPathGen(apiRealPath, (path: string[], tail: APITail, pathParam) => {
|
||||||
return (args?: Record<string, unknown>, returnError?: boolean) => {
|
const method = extractHttpMethod(tail);
|
||||||
|
return (args?: RawArgType, returnError?: boolean) => {
|
||||||
if (returnError) {
|
if (returnError) {
|
||||||
return callSammoAPI(path.join('/'), args, true);
|
return callSammoAPI(method, path.join('/'), args, pathParam, true);
|
||||||
}
|
}
|
||||||
return callSammoAPI(path.join('/'), args);
|
return callSammoAPI(method, path.join('/'), args, pathParam);
|
||||||
};
|
};
|
||||||
}) as typeof apiRealPath;
|
});
|
||||||
@@ -129,21 +129,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BettingInfo, ToastType } from "@/defs";
|
import type { BettingDetailResponse, BettingInfo, ToastType } from "@/defs";
|
||||||
import { SammoAPI, type ValidResponse } from "@/SammoAPI";
|
import { SammoAPI } from "@/SammoAPI";
|
||||||
import { joinYearMonth } from "@/util/joinYearMonth";
|
import { joinYearMonth } from "@/util/joinYearMonth";
|
||||||
import { parseYearMonth } from "@/util/parseYearMonth";
|
import { parseYearMonth } from "@/util/parseYearMonth";
|
||||||
import { isString, range, sum } from "lodash";
|
import { isString, range, sum } from "lodash";
|
||||||
import { ref, type PropType, watch } from "vue";
|
import { ref, type PropType, watch } from "vue";
|
||||||
|
|
||||||
type BettingDetailResponse = ValidResponse & {
|
|
||||||
bettingInfo: BettingInfo;
|
|
||||||
bettingDetail: [string, number][];
|
|
||||||
myBetting: [string, number][];
|
|
||||||
remainPoint: number;
|
|
||||||
year: number;
|
|
||||||
month: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
bettingID: {
|
bettingID: {
|
||||||
@@ -287,9 +279,7 @@ function calcReward() {
|
|||||||
|
|
||||||
async function loadBetting(bettingID: number) {
|
async function loadBetting(bettingID: number) {
|
||||||
try {
|
try {
|
||||||
const result = await SammoAPI.Betting.GetBettingDetail<BettingDetailResponse>({
|
const result = await SammoAPI.Betting.GetBettingDetail[bettingID]();
|
||||||
betting_id: bettingID,
|
|
||||||
});
|
|
||||||
year.value = result.year;
|
year.value = result.year;
|
||||||
month.value = result.month;
|
month.value = result.month;
|
||||||
yearMonth.value = joinYearMonth(result.year, result.month);
|
yearMonth.value = joinYearMonth(result.year, result.month);
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
|
||||||
|
export type LoginResponse = {
|
||||||
|
result: true,
|
||||||
|
nextToken: [number, string] | undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoginFailed = {
|
||||||
|
result: false,
|
||||||
|
reqOTP: boolean,
|
||||||
|
reason: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LoginResponseWithKakao = LoginResponse | LoginFailed;
|
||||||
|
|
||||||
|
export type OTPResponse = {
|
||||||
|
result: true,
|
||||||
|
validUntil: string,
|
||||||
|
} | {
|
||||||
|
result: false,
|
||||||
|
reset: boolean,
|
||||||
|
reason: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type AutoLoginNonceResponse = {
|
||||||
|
result: true,
|
||||||
|
loginNonce: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AutoLoginResponse = {
|
||||||
|
result: true,
|
||||||
|
nextToken: [number, string] | undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AutoLoginFailed = {
|
||||||
|
result: false,
|
||||||
|
silent: boolean,
|
||||||
|
reason: string,
|
||||||
|
}
|
||||||
@@ -1,10 +1,7 @@
|
|||||||
import type { Args } from "./processing/args";
|
import type { Args } from "@/processing/args";
|
||||||
|
import type { ValidResponse, InvalidResponse } from "@/util/callSammoAPI";
|
||||||
export type InvalidResponse = {
|
|
||||||
result: false;
|
|
||||||
reason: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
export type { ValidResponse, InvalidResponse };
|
||||||
export type BasicGeneralListResponse = {
|
export type BasicGeneralListResponse = {
|
||||||
result: true,
|
result: true,
|
||||||
nationID: number,
|
nationID: number,
|
||||||
@@ -266,3 +263,13 @@ export type BettingInfo = {
|
|||||||
candidates: SelectItem[];
|
candidates: SelectItem[];
|
||||||
winner?: number[];
|
winner?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type BettingDetailResponse = ValidResponse & {
|
||||||
|
bettingInfo: BettingInfo;
|
||||||
|
bettingDetail: [string, number][];
|
||||||
|
myBetting: [string, number][];
|
||||||
|
remainPoint: number;
|
||||||
|
year: number;
|
||||||
|
month: number;
|
||||||
|
};
|
||||||
+4
-43
@@ -8,51 +8,12 @@ import { setAxiosXMLHttpRequest } from '@util/setAxiosXMLHttpRequest';
|
|||||||
import { unwrap_any } from '@util/unwrap_any';
|
import { unwrap_any } from '@util/unwrap_any';
|
||||||
import { sha512 } from 'js-sha512';
|
import { sha512 } from 'js-sha512';
|
||||||
import { unwrap } from '@util/unwrap';
|
import { unwrap } from '@util/unwrap';
|
||||||
import type { InvalidResponse } from '@/defs';
|
|
||||||
import { delay } from '@util/delay';
|
import { delay } from '@util/delay';
|
||||||
import { Modal } from 'bootstrap';
|
import { Modal } from 'bootstrap';
|
||||||
import '@/gateway/common';
|
import '@/gateway/common';
|
||||||
import { isString } from 'lodash';
|
import { isString } from 'lodash';
|
||||||
import { SammoRootAPI } from '@/SammoRootAPI';
|
import { SammoRootAPI, type InvalidResponse } from '@/SammoRootAPI';
|
||||||
|
import type { LoginFailed, LoginResponse, LoginResponseWithKakao, OTPResponse } from '@/defs/API/Login';
|
||||||
type LoginResponse = {
|
|
||||||
result: true,
|
|
||||||
nextToken: [number, string] | undefined,
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginFailed = {
|
|
||||||
result: false,
|
|
||||||
reqOTP: boolean,
|
|
||||||
reason: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginResponseWithKakao = LoginResponse | LoginFailed;
|
|
||||||
|
|
||||||
type OTPResponse = {
|
|
||||||
result: true,
|
|
||||||
validUntil: string,
|
|
||||||
} | {
|
|
||||||
result: false,
|
|
||||||
reset: boolean,
|
|
||||||
reason: string,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
type AutoLoginNonceResponse = {
|
|
||||||
result: true,
|
|
||||||
loginNonce: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
type AutoLoginResponse = {
|
|
||||||
result: true,
|
|
||||||
nextToken: [number, string] | undefined,
|
|
||||||
}
|
|
||||||
|
|
||||||
type AutoLoginFailed = {
|
|
||||||
result: false,
|
|
||||||
silent: boolean,
|
|
||||||
reason: string,
|
|
||||||
}
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
getOAuthToken: (mode: string, scope_list: string[]) => void;
|
getOAuthToken: (mode: string, scope_list: string[]) => void;
|
||||||
@@ -101,7 +62,7 @@ async function tryAutoLogin() {
|
|||||||
|
|
||||||
const [tokenID, token] = tokenInfo;
|
const [tokenID, token] = tokenInfo;
|
||||||
|
|
||||||
const result = await SammoRootAPI.Login.ReqNonce<AutoLoginNonceResponse, AutoLoginFailed>({}, true);
|
const result = await SammoRootAPI.Login.ReqNonce(undefined, true);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
//api 에러.
|
//api 에러.
|
||||||
@@ -116,7 +77,7 @@ async function tryAutoLogin() {
|
|||||||
const nonce = result.loginNonce;
|
const nonce = result.loginNonce;
|
||||||
|
|
||||||
const hashedToken = sha512(token + nonce);
|
const hashedToken = sha512(token + nonce);
|
||||||
const loginResult = await SammoRootAPI.Login.LoginByToken<AutoLoginResponse, AutoLoginFailed>({
|
const loginResult = await SammoRootAPI.Login.LoginByToken({
|
||||||
'hashedToken': hashedToken,
|
'hashedToken': hashedToken,
|
||||||
'token_id': tokenID,
|
'token_id': tokenID,
|
||||||
}, true);
|
}, true);
|
||||||
|
|||||||
Vendored
+9
-5
@@ -1,21 +1,25 @@
|
|||||||
export function APIPathGen<T>(obj: T, callback: (path: string[])=>unknown): T;
|
export function APIPathGen<T, V>(
|
||||||
|
obj: T,
|
||||||
|
callback: (path: string[], tail: V, pathParam?: Record<string, string | number>) => unknown,
|
||||||
|
pathParam?: Record<string, string | number>
|
||||||
|
): T;
|
||||||
|
|
||||||
export function StrVar<PathType extends string>(): <NextCall>(next: NextCall)=>{
|
export function StrVar<PathType extends string>(paramKey: string): <NextCall>(next: NextCall) => {
|
||||||
[v in PathType]: NextCall
|
[v in PathType]: NextCall
|
||||||
};
|
};
|
||||||
|
|
||||||
export function NumVar<NextCall>(next: NextCall):{
|
export function NumVar<NextCall>(paramKey: string, next: NextCall): {
|
||||||
[v: number]: NextCall
|
[v: number]: NextCall
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const apiPath = {
|
const apiPath = {
|
||||||
SomePath: someFunc,
|
SomePath: someFunc,
|
||||||
User: StrVar<'a'|'b'>()({
|
User: StrVar<'a'|'b'>('name')({
|
||||||
Update: someFunc,
|
Update: someFunc,
|
||||||
Delete: someFunc,
|
Delete: someFunc,
|
||||||
}),
|
}),
|
||||||
NationInfo: NumVar({
|
NationInfo: NumVar('id', {
|
||||||
show: someFunc
|
show: someFunc
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export function APIPathGen(obj, callback, path) {
|
export function APIPathGen(obj, callback, path, pathParams) {
|
||||||
return new Proxy(obj, {
|
return new Proxy(obj, {
|
||||||
get(target, key) {
|
get(target, key) {
|
||||||
let nextPath;
|
let nextPath;
|
||||||
@@ -9,12 +9,21 @@ export function APIPathGen(obj, callback, path) {
|
|||||||
nextPath = [...path, key.toString()];
|
nextPath = [...path, key.toString()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pathParams !== undefined) {
|
||||||
|
pathParams = { ...pathParams };
|
||||||
|
}
|
||||||
|
|
||||||
const varType = target.__nextVarType;
|
const varType = target.__nextVarType;
|
||||||
|
const varKey = target.__nextVarKey;
|
||||||
let next;
|
let next;
|
||||||
if (varType !== undefined) {
|
if (varType !== undefined && varKey !== undefined) {
|
||||||
if (typeof key !== varType) {
|
if (typeof key !== varType) {
|
||||||
throw `${key} is not ${varType}`;
|
throw `${key} is not ${varType}`;
|
||||||
}
|
}
|
||||||
|
if(pathParams === undefined){
|
||||||
|
pathParams = {}
|
||||||
|
}
|
||||||
|
pathParams[varKey] = key;
|
||||||
next = target.next;
|
next = target.next;
|
||||||
}
|
}
|
||||||
else if (key in target) {
|
else if (key in target) {
|
||||||
@@ -25,26 +34,28 @@ export function APIPathGen(obj, callback, path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof (next) === 'function') {
|
if (typeof (next) === 'function') {
|
||||||
return callback(nextPath);
|
return callback(nextPath, next, pathParams);
|
||||||
}
|
}
|
||||||
return APIPathGen(next, callback, nextPath);
|
return APIPathGen(next, callback, nextPath, pathParams);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//generic 인자로 '자동'을 주려면 생략해야하므로 2단 호출
|
//generic 인자로 '자동'을 주려면 생략해야하므로 2단 호출
|
||||||
export function StrVar() {
|
export function StrVar(key) {
|
||||||
return (next) => {
|
return (next) => {
|
||||||
return {
|
return {
|
||||||
__nextVarType: 'string',
|
__nextVarType: 'string',
|
||||||
|
__nextVarKey: key,
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NumVar(next) {
|
export function NumVar(key, next) {
|
||||||
return {
|
return {
|
||||||
__nextVarType: 'number',
|
__nextVarType: 'number',
|
||||||
|
__nextVarKey: key,
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+90
-22
@@ -1,35 +1,64 @@
|
|||||||
import axios from "axios";
|
import ky from 'ky';
|
||||||
import { isArray } from "lodash";
|
import { isArray, isEmpty } from "lodash";
|
||||||
import type { InvalidResponse } from '@/defs';
|
|
||||||
|
|
||||||
export type ValidResponse = {
|
export type ValidResponse = {
|
||||||
result: true
|
result: true
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RawArgType = Record<string, unknown>|Record<string, unknown>[];
|
export type InvalidResponse = {
|
||||||
|
result: false;
|
||||||
|
reason: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface CallbackT<ArgType extends RawArgType, ResultType extends ValidResponse = ValidResponse, ErrorType extends InvalidResponse = InvalidResponse>{
|
|
||||||
|
export type RawArgType = Record<string, unknown> | Record<string, unknown>[] | undefined;
|
||||||
|
|
||||||
|
export interface APICallT<ArgType extends RawArgType, ResultType extends ValidResponse = ValidResponse, ErrorType extends InvalidResponse = InvalidResponse> {
|
||||||
(args?: ArgType): Promise<ResultType>;
|
(args?: ArgType): Promise<ResultType>;
|
||||||
(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function callSammoAPI<ResultType extends ValidResponse>(path: string | string[], args?: Record<string, unknown> | Record<string, unknown>[]): Promise<ResultType>;
|
type HttpMethod = 'get' | 'post' | 'put' | 'patch' | 'head' | 'delete';
|
||||||
export async function callSammoAPI<ResultType extends ValidResponse>(path: string | string[], args: Record<string, unknown> | Record<string, unknown>[] | undefined, returnError: false): Promise<ResultType>;
|
export type APITail = typeof GET | typeof POST | typeof PUT | typeof PATCH | typeof HEAD | typeof DELETE;
|
||||||
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args: Record<string, unknown> | Record<string, unknown>[] | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
|
||||||
|
|
||||||
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(path: string | string[], args?: Record<string, unknown> | Record<string, unknown>[], returnError = false): Promise<ResultType | ErrorType> {
|
const httpMethodMap = new Map<APITail, HttpMethod>([
|
||||||
|
[GET, 'get'],
|
||||||
|
[POST, 'post'],
|
||||||
|
[PUT, 'put'],
|
||||||
|
[PATCH, 'patch'],
|
||||||
|
[HEAD, 'head'],
|
||||||
|
[DELETE, 'delete'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function extractHttpMethod(tail: APITail): HttpMethod {
|
||||||
|
return httpMethodMap.get(tail) ?? 'post';
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function callSammoAPI<ResultType extends ValidResponse>(method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record<string, string | number> | undefined): Promise<ResultType>;
|
||||||
|
export async function callSammoAPI<ResultType extends ValidResponse>(method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record<string, string | number> | undefined, returnError: false): Promise<ResultType>;
|
||||||
|
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record<string, string | number> | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function callSammoAPI<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(method: HttpMethod, path: string | string[], args: RawArgType, paramArgs: Record<string, string | number> | undefined, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
if (isArray(path)) {
|
if (isArray(path)) {
|
||||||
path = path.join('/');
|
path = path.join('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await axios({
|
if (args && isEmpty(args)) {
|
||||||
url: `api.php?path=${path}`,
|
args = undefined;
|
||||||
method: "post",
|
}
|
||||||
responseType: "json",
|
|
||||||
data: args
|
const result = await ky('api.php', {
|
||||||
});
|
searchParams: {
|
||||||
const result: ErrorType | ResultType = response.data;
|
...paramArgs,
|
||||||
|
path,
|
||||||
|
},
|
||||||
|
method,
|
||||||
|
json: args,
|
||||||
|
headers: {
|
||||||
|
'content-type': 'application/json'
|
||||||
|
}
|
||||||
|
}).json() as ErrorType | ResultType;
|
||||||
|
|
||||||
if (!result.result) {
|
if (!result.result) {
|
||||||
if (returnError) {
|
if (returnError) {
|
||||||
return result;
|
return result;
|
||||||
@@ -39,11 +68,50 @@ export async function callSammoAPI<ResultType extends ValidResponse, ErrorType e
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function done<ResultType extends ValidResponse>(args?: RawArgType): Promise<ResultType>;
|
export async function GET<ResultType extends ValidResponse, ArgType extends undefined = undefined>(args?: ArgType): Promise<ResultType>;
|
||||||
export async function done<ResultType extends ValidResponse>(args: RawArgType | undefined, returnError: false): Promise<ResultType>;
|
export async function GET<ResultType extends ValidResponse, ArgType extends undefined = undefined>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
export async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args: RawArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
export async function GET<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function GET<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call GET. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('get', [], args, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
export async function done<ResultType extends ValidResponse, ErrorType extends InvalidResponse>(args?: RawArgType, returnError = false): Promise<ResultType | ErrorType> {
|
export async function POST<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType): Promise<ResultType>;
|
||||||
console.error(`Can't directly call. ${args}, ${returnError}. Use auto-generated path API.`);
|
export async function POST<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
return callSammoAPI<ResultType, ErrorType>([], args, true);
|
export async function POST<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function POST<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call POST. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('post', [], args, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PUT<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType): Promise<ResultType>;
|
||||||
|
export async function PUT<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
|
export async function PUT<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function PUT<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call PUT. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('put', [], args, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function PATCH<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType): Promise<ResultType>;
|
||||||
|
export async function PATCH<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
|
export async function PATCH<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function PATCH<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call PATCH. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('patch', [], args, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function HEAD<ResultType extends ValidResponse, ArgType extends undefined = undefined>(args?: ArgType): Promise<ResultType>;
|
||||||
|
export async function HEAD<ResultType extends ValidResponse, ArgType extends undefined = undefined>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
|
export async function HEAD<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function HEAD<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends undefined = undefined>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call HEAD. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('head', [], args, undefined, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function DELETE<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType): Promise<ResultType>;
|
||||||
|
export async function DELETE<ResultType extends ValidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: false): Promise<ResultType>;
|
||||||
|
export async function DELETE<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args: ArgType | undefined, returnError: true): Promise<ResultType | ErrorType>;
|
||||||
|
export async function DELETE<ResultType extends ValidResponse, ErrorType extends InvalidResponse, ArgType extends RawArgType = RawArgType>(args?: ArgType, returnError = false): Promise<ResultType | ErrorType> {
|
||||||
|
console.error(`Can't directly call DELETE. ${args}, ${returnError}. Use auto-generated path API.`);
|
||||||
|
return callSammoAPI<ResultType, ErrorType>('patch', [], args, undefined, true);
|
||||||
}
|
}
|
||||||
Generated
+17
@@ -63,6 +63,7 @@
|
|||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"js-sha512": "^0.8.0",
|
"js-sha512": "^0.8.0",
|
||||||
|
"ky": "^0.30.0",
|
||||||
"linkifyjs": "^3.0",
|
"linkifyjs": "^3.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mini-css-extract-plugin": "^2.6.0",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
@@ -6417,6 +6418,17 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ky": {
|
||||||
|
"version": "0.30.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz",
|
||||||
|
"integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sindresorhus/ky?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/levn": {
|
"node_modules/levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
@@ -15122,6 +15134,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz",
|
||||||
"integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ=="
|
"integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ=="
|
||||||
},
|
},
|
||||||
|
"ky": {
|
||||||
|
"version": "0.30.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ky/-/ky-0.30.0.tgz",
|
||||||
|
"integrity": "sha512-X/u76z4JtDVq10u1JA5UQfatPxgPaVDMYTrgHyiTpGN2z4TMEJkIHsoSBBSg9SWZEIXTKsi9kHgiQ9o3Y/4yog=="
|
||||||
|
},
|
||||||
"levn": {
|
"levn": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
|
||||||
|
|||||||
@@ -76,6 +76,7 @@
|
|||||||
"file-loader": "^6.2.0",
|
"file-loader": "^6.2.0",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"js-sha512": "^0.8.0",
|
"js-sha512": "^0.8.0",
|
||||||
|
"ky": "^0.30.0",
|
||||||
"linkifyjs": "^3.0",
|
"linkifyjs": "^3.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mini-css-extract-plugin": "^2.6.0",
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
|
|||||||
+12
-20
@@ -21,41 +21,33 @@ class APIHelper
|
|||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function launch(string $rootPath, ?string $actionPath = null)
|
public static function launch(string $rootPath, string $actionPath, array $eParams = [], bool $loadRawInput = true)
|
||||||
{
|
{
|
||||||
//TODO: path를 php://input에서 받는게 아니라 api.php?~~~~~ 로 받아오는것이 etag 캐시 측면에서 훨씬 나을 듯!
|
if($loadRawInput){
|
||||||
try {
|
try {
|
||||||
$rawInput = file_get_contents('php://input');
|
$rawInput = file_get_contents('php://input');
|
||||||
$input = Json::decode($rawInput);
|
$input = Json::decode($rawInput);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
Json::dieWithReason($e->getMessage());
|
Json::dieWithReason($e->getMessage());
|
||||||
|
$input = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
$input = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($actionPath !== null) {
|
if(!$actionPath){
|
||||||
|
Json::dieWithReason('path가 지정되지 않았습니다.');
|
||||||
|
}
|
||||||
if ($input && !is_array($input)) {
|
if ($input && !is_array($input)) {
|
||||||
Json::dieWithReason('args가 array가 아닙니다.' . gettype($input));
|
Json::dieWithReason('args가 array가 아닙니다.' . gettype($input));
|
||||||
}
|
}
|
||||||
if (!$input) {
|
if (!$input) {
|
||||||
$input = [];
|
$input = [];
|
||||||
}
|
}
|
||||||
$actionArgs = $input;
|
|
||||||
} else {
|
|
||||||
if (!$input) {
|
|
||||||
Json::dieWithReason("input이 비어있습니다. {$rawInput}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!key_exists('path', $input)) {
|
|
||||||
Json::dieWithReason('path가 지정되지 않았습니다.');
|
|
||||||
}
|
|
||||||
$actionPath = $input['path'];
|
|
||||||
|
|
||||||
if (key_exists('args', $input) && !is_array($input['args'])) {
|
|
||||||
Json::dieWithReason('args가 array가 아닙니다.' . gettype($input['args']));
|
|
||||||
}
|
|
||||||
$actionArgs = $input['args'] ?? null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
//NOTE: array_merge([], {})의 상황이 가능함.
|
||||||
|
$actionArgs = array_merge($input, $eParams);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$obj = buildAPIExecutorClass($actionPath, $rootPath, $actionArgs);
|
$obj = buildAPIExecutorClass($actionPath, $rootPath, $actionArgs);
|
||||||
|
|||||||
Reference in New Issue
Block a user