Restructured rest api

This commit is contained in:
SamTV12345 2024-09-14 16:36:02 +02:00
parent 08f199178d
commit 644cb9b39f
5 changed files with 113 additions and 11 deletions

View file

@ -82,6 +82,12 @@
"expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling" "expressCreateServer": "ep_etherpad-lite/node/hooks/express/errorhandling"
} }
}, },
{
"name": "restApi",
"hooks": {
"expressCreateServer": "ep_etherpad-lite/node/handler/RestAPI"
}
},
{ {
"name": "socketio", "name": "socketio",
"hooks": { "hooks": {

View file

@ -24,10 +24,10 @@ import {MapArrayType} from "../types/MapType";
const api = require('../db/API'); const api = require('../db/API');
const padManager = require('../db/PadManager'); const padManager = require('../db/PadManager');
import createHTTPError from 'http-errors'; import createHTTPError from 'http-errors';
import {Http2ServerRequest, Http2ServerResponse} from "node:http2"; import {Http2ServerRequest} from "node:http2";
import {publicKeyExported} from "../security/OAuth2Provider"; import {publicKeyExported} from "../security/OAuth2Provider";
import {jwtVerify} from "jose"; import {jwtVerify} from "jose";
import {apikey} from './APIKeyHandler' import {APIFields, apikey} from './APIKeyHandler'
// a list of all functions // a list of all functions
const version:MapArrayType<any> = {}; const version:MapArrayType<any> = {};
@ -141,6 +141,13 @@ version['1.3.0'] = {
setText: ['padID', 'text', 'authorId'], setText: ['padID', 'text', 'authorId'],
}; };
version['2.2.2'] = {
...version['1.3.0'],
}
// set the latest available API version here // set the latest available API version here
exports.latestApiVersion = '1.3.0'; exports.latestApiVersion = '1.3.0';
@ -148,13 +155,6 @@ exports.latestApiVersion = '1.3.0';
exports.version = version; exports.version = version;
type APIFields = {
apikey: string;
api_key: string;
padID: string;
padName: string;
authorization: string;
}
/** /**
* Handles an HTTP API call * Handles an HTTP API call

View file

@ -7,6 +7,16 @@ const settings = require('../utils/Settings');
const apiHandlerLogger = log4js.getLogger('APIHandler'); const apiHandlerLogger = log4js.getLogger('APIHandler');
export type APIFields = {
apikey: string;
api_key: string;
padID: string;
padName: string;
authorization: string;
}
// ensure we have an apikey // ensure we have an apikey
export let apikey:string|null = null; export let apikey:string|null = null;
const apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || './APIKEY.txt'); const apikeyFilename = absolutePaths.makeAbsolute(argv.apikey || './APIKEY.txt');

View file

@ -0,0 +1,84 @@
import {ArgsExpressType} from "../types/ArgsExpressType";
import {MapArrayType} from "../types/MapType";
import {IncomingForm} from "formidable";
import {ErrorCaused} from "../types/ErrorCaused";
import createHTTPError from "http-errors";
const apiHandler = require('./APIHandler')
type RestAPIMapping = {
apiVersion: string;
functionName: string
}
const mapping = new Map<string, Record<string,RestAPIMapping>>
export const expressCreateServer = async (hookName: string, {app}: ArgsExpressType) => {
mapping.set('GET', {})
mapping.set('POST', {})
mapping.set('PUT', {})
mapping.set('DELETE', {})
mapping.set('PATCH', {})
// Version 1
mapping.get('POST')!["/groups"] = {apiVersion: '1', functionName: 'createGroup'}
mapping.get('GET')!["/pads"] = {apiVersion: '1', functionName: 'listPads'}
mapping.get('POST')!["/groups/createIfNotExistsFor"] = {apiVersion: '1', functionName: 'createGroupIfNotExistsFor'};
app.use('/api/2', async (req, res, next) => {
const method = req.method
const pathToFunction = req.path
// parse fields from request
const {headers, params, query} = req;
// read form data if method was POST
let formData: MapArrayType<any> = {};
if (method === 'post') {
const form = new IncomingForm();
formData = (await form.parse(req))[0];
for (const k of Object.keys(formData)) {
if (formData[k] instanceof Array) {
formData[k] = formData[k][0];
}
}
}
const fields = Object.assign({}, headers, params, query, formData);
if (mapping.has(method) && pathToFunction in mapping.get(method)!) {
const {apiVersion, functionName} = mapping.get(method)![pathToFunction]!
// pass to api handler
let data;
try {
data = await apiHandler.handle(apiVersion, functionName, fields, req, res);
} catch (err) {
const errCaused = err as ErrorCaused
// convert all errors to http errors
if (createHTTPError.isHttpError(err)) {
// pass http errors thrown by handler forward
throw err;
} else if (errCaused.name === 'apierror') {
// parameters were wrong and the api stopped execution, pass the error
// convert to http error
throw new createHTTPError.BadRequest(errCaused.message);
} else {
// an unknown error happened
// log it and throw internal error
console.error(errCaused.stack || errCaused.toString());
throw new createHTTPError.InternalServerError('internal error');
}
}
// return in common format
const response = {code: 0, message: 'ok', data: data || null};
console.debug(`RESPONSE, ${functionName}, ${JSON.stringify(response)}`);
// return the response data
res.json(response);
} else {
res.json({code: 1, message: 'not found'});
}
})
}

View file

@ -1,5 +1,7 @@
import {Express} from "express";
export type ArgsExpressType = { export type ArgsExpressType = {
app:any, app:Express,
io: any, io: any,
server:any server:any
} }