mmews-n4 db478c3452
Support language N4JS (2nd) (#15397)
* n4js initial commit

* incorporate feedback from user

* add tests

* fix media type in case of DELETE method

* fix media type

* some minor fixes

* options fix for booleans

* small fixes

* generated files by ./bin/utils/ensure-up-to-date

* remove String::toLowerCase due to de.thetaphi:forbiddenapis

* adjust test expectation

* fix test expectations

* fix test expectation

* add note to section 'Languages/Generators'

* remove file according to review

* replace tabs by spaces

* replace tabs by spaces (2)

* update two generated files

* remove test file

* move statement
2023-05-03 20:50:21 +08:00

114 lines
3.2 KiB
Plaintext

/**
* Implemented by client
*/
export public interface ~ApiExecuterI {
public <R, E> async exec(
method: string,
path: string,
pathParams: ~Object+,
queryParams: ~Object+,
headerParams: ~Object+,
payloadContentType: string,
body: any+) : Promise<R, Object|ApiError<E>>;
}
export public interface ~ApiError<T> {
public resultBody?: T;
}
export public function checkRequiredParams(apiName: string, params: ~Object+) : void {
for (const key of Object.keys(params)) {
const arg = params[key];
if (arg == null) {
throw new Error('Required parameter ' + key + ' was null or undefined when calling ' + apiName + '.');
}
}
}
export public function <T> cleanCopyBody(t : T+, ...properties: string) : ~T {
const copy : ~T+ = {};
for (const prop in properties) {
copy[prop] = t.prop;
}
return copy;
}
/**
* Default implementation of ApiExecuterI
*
* The following dependencies are necessary:
* - n4js-runtime-esnext
* - n4js-runtime-es2015
* - n4js-runtime-html5
*/
export public class FetchApiExec implements ApiExecuterI {
public apiOrigin: string;
const jsonTypes = ["application/json", "application/problem+json"];
@Override
public <R, E> async exec(
method: string,
path: string,
pathParams: ~Object+,
queryParams: ~Object+,
headerParams: ~Object+,
payloadContentType: string,
body: any+
): Promise<R, Object|ApiError<E>> {
if (pathParams) {
for (const [k, v] of Object.entries(pathParams)) {
path = path.replace(`{${k}}`, encodeURIComponent(String(v)));
}
}
const query: string[] = [];
if (queryParams) {
for (const [k, v] of Object.entries(queryParams)) {
query.push(`${k}=${encodeURIComponent(String(v))}`);
}
}
let url = `${this.apiOrigin}${path}`;
if (query.length) {
url += `?${query.join("&")}`;
}
const headers: Object+ = {};
if (payloadContentType) {
headers["content-type"] = payloadContentType;
if (this.constructor.jsonTypes.includes(payloadContentType)) {
body = JSON.stringify(body);
}
}
Object.assign(headers, headerParams);
return await this.<R,E>fetchExec(url, {
method,
headers,
body,
});
}
protected <R, E> async fetchExec(url: string, reqInit: RequestInit): Promise<R, Object|ApiError<E>> {
const resp = await fetch(url, reqInit);
if (resp.status !== 204) {
const contentType = (resp.headers.get("content-type") || "").split(";")[0];
const body = this.constructor.jsonTypes.includes(contentType)
? await resp.json()
: await resp.text();
if (!resp.ok) {
await this.handleError(resp, body);
}
return body as R;
}
return null;
}
protected <E> async handleError(resp: Response, body): Promise<undefined, ApiError<E>> {
throw {body: body};
}
}