feat(misskey-js): multipart/form-dataのリクエストに対応 (#14147)

* feat(misskey-js): multipart/form-dataのリクエストに対応

* lint

* add test

* Update Changelog

* テストを厳しくする

* lint

* multipart/form-dataではnullのプロパティを弾くように
This commit is contained in:
かっこかり
2024-07-07 14:08:18 +09:00
committed by GitHub
parent 984d582796
commit f119f8c2cc
7 changed files with 537 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
import './autogen/apiClientJSDoc.js';
import { SwitchCaseResponseType } from './api.types.js';
import type { Endpoints } from './api.types.js';
import { endpointReqTypes } from './autogen/endpoint.js';
import type { SwitchCaseResponseType, Endpoints } from './api.types.js';
export type {
SwitchCaseResponseType,
@@ -23,7 +23,7 @@ export function isAPIError(reason: Record<PropertyKey, unknown>): reason is APIE
export type FetchLike = (input: string, init?: {
method?: string;
body?: string;
body?: Blob | FormData | string;
credentials?: RequestCredentials;
cache?: RequestCache;
headers: { [key in string]: string }
@@ -49,20 +49,55 @@ export class APIClient {
this.fetch = opts.fetch ?? ((...args) => fetch(...args));
}
private assertIsRecord<T>(obj: T): obj is T & Record<string, any> {
return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
}
public request<E extends keyof Endpoints, P extends Endpoints[E]['req']>(
endpoint: E,
params: P = {} as P,
credential?: string | null,
): Promise<SwitchCaseResponseType<E, P>> {
return new Promise((resolve, reject) => {
this.fetch(`${this.origin}/api/${endpoint}`, {
method: 'POST',
body: JSON.stringify({
let mediaType = 'application/json';
if (endpoint in endpointReqTypes) {
mediaType = endpointReqTypes[endpoint];
}
let payload: FormData | string = '{}';
if (mediaType === 'application/json') {
payload = JSON.stringify({
...params,
i: credential !== undefined ? credential : this.credential,
}),
});
} else if (mediaType === 'multipart/form-data') {
payload = new FormData();
const i = credential !== undefined ? credential : this.credential;
if (i != null) {
payload.append('i', i);
}
if (this.assertIsRecord(params)) {
for (const key in params) {
const value = params[key];
if (value == null) continue;
if (value instanceof File || value instanceof Blob) {
payload.append(key, value);
} else if (typeof value === 'object') {
payload.append(key, JSON.stringify(value));
} else {
payload.append(key, value);
}
}
}
}
this.fetch(`${this.origin}/api/${endpoint}`, {
method: 'POST',
body: payload,
headers: {
'Content-Type': 'application/json',
'Content-Type': endpointReqTypes[endpoint],
},
credentials: 'omit',
cache: 'no-cache',