From 39a71429f30eac508f68c5450d71f448f6c2f828 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 30 Mar 2018 15:17:39 -0600 Subject: [PATCH] Add documentation for the backend APIs --- src/api/ApiError.ts | 26 +++++++++++++++++-- src/api/Webserver.ts | 8 +++++- src/api/admin/AdminAppserviceService.ts | 3 +++ src/api/admin/AdminIntegrationsService.ts | 4 +++ src/api/admin/AdminNebService.ts | 3 +++ src/api/admin/AdminService.ts | 15 +++++++++++ src/api/admin/AdminUpstreamService.ts | 4 +++ src/api/dimension/DimensionHealthService.ts | 3 +++ .../dimension/DimensionIntegrationsService.ts | 19 ++++++++++++++ src/api/dimension/DimensionWebhookService.ts | 3 +++ src/api/matrix/MatrixAppServiceApiService.ts | 3 +++ src/api/scalar/ScalarService.ts | 11 ++++++++ src/api/scalar/ScalarWidgetService.ts | 3 +++ 13 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/api/ApiError.ts b/src/api/ApiError.ts index 1df7964..46db457 100644 --- a/src/api/ApiError.ts +++ b/src/api/ApiError.ts @@ -1,10 +1,32 @@ +/** + * Thrown when there is a problem with a given API call. This is special-cased in the responder + * to create a JSON error response with the status code given. + */ export class ApiError { + /** + * The HTTP status code to return + */ public statusCode: number; - public jsonResponse: any; + + /** + * An object to be returned as JSON to the caller + */ + public jsonResponse: object; + + /** + * The internal error code to describe what went wrong + */ public errorCode: string; - constructor(statusCode: number, json: any, errCode = "D_UNKNOWN") { + /** + * Creates a new API error + * @param {number} statusCode The HTTP status code to return + * @param {string|object} json An object to be returned as JSON or a message to be returned (which is + * then converted to JSON as {message: "your_message"}) + * @param {string} errCode The internal error code to describe what went wrong + */ + constructor(statusCode: number, json: string | object, errCode = "D_UNKNOWN") { // Because typescript is just plain dumb // https://stackoverflow.com/questions/31626231/custom-error-class-in-typescript Error.apply(this, ["ApiError"]); diff --git a/src/api/Webserver.ts b/src/api/Webserver.ts index 61729fd..2394706 100644 --- a/src/api/Webserver.ts +++ b/src/api/Webserver.ts @@ -8,6 +8,9 @@ import * as _ from "lodash"; import config from "../config"; import { ApiError } from "./ApiError"; +/** + * Web server for Dimension. Handles the API routes for the admin, scalar, dimension, and matrix APIs. + */ export default class Webserver { private app: express.Application; @@ -69,7 +72,10 @@ export default class Webserver { }); } - start() { + /** + * Starts the webserver, bootstrapping the various API handlers + */ + public start() { this.app.listen(config.web.port, config.web.address); LogService.info("Webserver", "API and UI listening on " + config.web.address + ":" + config.web.port); } diff --git a/src/api/admin/AdminAppserviceService.ts b/src/api/admin/AdminAppserviceService.ts index 16aac81..ad4ca05 100644 --- a/src/api/admin/AdminAppserviceService.ts +++ b/src/api/admin/AdminAppserviceService.ts @@ -17,6 +17,9 @@ interface AppserviceCreateRequest { userPrefix: string; } +/** + * Administrative API for managing the appservices that Dimension operates. + */ @Path("/api/v1/dimension/admin/appservices") export class AdminAppserviceService { diff --git a/src/api/admin/AdminIntegrationsService.ts b/src/api/admin/AdminIntegrationsService.ts index 47beddd..402172e 100644 --- a/src/api/admin/AdminIntegrationsService.ts +++ b/src/api/admin/AdminIntegrationsService.ts @@ -14,6 +14,10 @@ interface SetOptionsRequest { options: any; } +/** + * Administrative API for managing the integrations for Dimension. This is to enable/disable integrations + * and set basic options. See the NEB APIs for configuring go-neb instances. + */ @Path("/api/v1/dimension/admin/integrations") export class AdminIntegrationsService { diff --git a/src/api/admin/AdminNebService.ts b/src/api/admin/AdminNebService.ts index 06d1911..81e8bb5 100644 --- a/src/api/admin/AdminNebService.ts +++ b/src/api/admin/AdminNebService.ts @@ -20,6 +20,9 @@ interface SetEnabledRequest { } +/** + * Administrative API for configuring go-neb instances. + */ @Path("/api/v1/dimension/admin/neb") export class AdminNebService { diff --git a/src/api/admin/AdminService.ts b/src/api/admin/AdminService.ts index 1652358..6564273 100644 --- a/src/api/admin/AdminService.ts +++ b/src/api/admin/AdminService.ts @@ -21,13 +21,28 @@ interface DimensionConfigResponse { }; } +/** + * Administrative API for general information about Dimension + */ @Path("/api/v1/dimension/admin") export class AdminService { + /** + * Determines if a given user is an administrator + * @param {string} userId The user ID to validate + * @returns {boolean} True if the user is an administrator + */ public static isAdmin(userId: string) { return config.admins.indexOf(userId) >= 0; } + /** + * Validates the given scalar token to ensure the owner is an administrator. If the + * given scalar token does not belong to an administrator, an ApiError is raised. + * @param {string} scalarToken The scalar token to validate + * @returns {Promise} Resolves to the owner's user ID if they are an administrator + * @throws {ApiError} Thrown with a status code of 401 if the owner is not an administrator + */ public static async validateAndGetAdminTokenOwner(scalarToken: string): Promise { const userId = await ScalarService.getTokenOwner(scalarToken, true); if (!AdminService.isAdmin(userId)) diff --git a/src/api/admin/AdminUpstreamService.ts b/src/api/admin/AdminUpstreamService.ts index ea9ca6e..36ab43d 100644 --- a/src/api/admin/AdminUpstreamService.ts +++ b/src/api/admin/AdminUpstreamService.ts @@ -18,6 +18,10 @@ interface NewUpstreamRequest { apiUrl: string; } +/** + * Administrative API for managing the instances upstream of this instance. Particularly + * useful for configuring the Modular upstream. + */ @Path("/api/v1/dimension/admin/upstreams") export class AdminUpstreamService { diff --git a/src/api/dimension/DimensionHealthService.ts b/src/api/dimension/DimensionHealthService.ts index 154600c..00cf8c7 100644 --- a/src/api/dimension/DimensionHealthService.ts +++ b/src/api/dimension/DimensionHealthService.ts @@ -1,5 +1,8 @@ import { GET, Path } from "typescript-rest"; +/** + * API for the health of Dimension + */ @Path("/api/v1/dimension/health") export class DimensionHealthService { diff --git a/src/api/dimension/DimensionIntegrationsService.ts b/src/api/dimension/DimensionIntegrationsService.ts index 0589360..92bb6d2 100644 --- a/src/api/dimension/DimensionIntegrationsService.ts +++ b/src/api/dimension/DimensionIntegrationsService.ts @@ -15,9 +15,17 @@ export interface IntegrationsResponse { complexBots: ComplexBot[], } +/** + * API for managing integrations, primarily for a given room + */ @Path("/api/v1/dimension/integrations") export class DimensionIntegrationsService { + /** + * Gets a list of widgets + * @param {boolean} enabledOnly True to only return the enabled widgets + * @returns {Promise} Resolves to the widget list + */ public static async getWidgets(enabledOnly: boolean): Promise { const cached = Cache.for(CACHE_INTEGRATIONS).get("widgets"); if (cached) return cached; @@ -27,6 +35,11 @@ export class DimensionIntegrationsService { return widgets; } + /** + * Gets a list of simple bots + * @param {string} userId The requesting user ID + * @returns {Promise} Resolves to the simple bot list + */ public static async getSimpleBots(userId: string): Promise { const cached = Cache.for(CACHE_INTEGRATIONS).get("simple_bots"); if (cached) return cached; @@ -36,6 +49,12 @@ export class DimensionIntegrationsService { return bots; } + /** + * Gets a list of complex bots + * @param {string} userId The requesting user ID + * @param {string} roomId The room ID to get the complex bots for + * @returns {Promise} Resolves to the complex bot list + */ public static async getComplexBots(userId: string, roomId: string): Promise { const cached = Cache.for(CACHE_INTEGRATIONS).get("complex_bots_" + roomId); if (cached) return cached; diff --git a/src/api/dimension/DimensionWebhookService.ts b/src/api/dimension/DimensionWebhookService.ts index 06a2028..cfc8171 100644 --- a/src/api/dimension/DimensionWebhookService.ts +++ b/src/api/dimension/DimensionWebhookService.ts @@ -4,6 +4,9 @@ import { ApiError } from "../ApiError"; import * as request from "request"; import { LogService } from "matrix-js-snippets"; +/** + * API for proxying webhooks to other services. + */ @Path("/api/v1/dimension/webhooks") export class DimensionWebhookService { diff --git a/src/api/matrix/MatrixAppServiceApiService.ts b/src/api/matrix/MatrixAppServiceApiService.ts index 417b121..b232fae 100644 --- a/src/api/matrix/MatrixAppServiceApiService.ts +++ b/src/api/matrix/MatrixAppServiceApiService.ts @@ -8,6 +8,9 @@ interface AppServiceTransaction { events: SimplifiedMatrixEvent[]; } +/** + * API for handling appservice traffic from a homeserver + */ // Note: There's no actual defined prefix for this API. The following was chosen to be // somewhat consistent with the other matrix APIs. In reality, the homeserver will just // hit the URL given in the registration - be sure to define it to match this prefix. diff --git a/src/api/scalar/ScalarService.ts b/src/api/scalar/ScalarService.ts index 1bc429b..ff6be08 100644 --- a/src/api/scalar/ScalarService.ts +++ b/src/api/scalar/ScalarService.ts @@ -19,9 +19,20 @@ interface RegisterRequest { expires_in: number; } +/** + * API for the minimum Scalar API we need to implement to be compatible with clients. Used for registration + * and general account management. + */ @Path("/api/v1/scalar") export class ScalarService { + /** + * Gets the owner of a given scalar token, throwing an ApiError if the token is invalid. + * @param {string} scalarToken The scalar token to validate + * @param {boolean} ignoreUpstreams True to consider the token valid if it is missing links to other upstreams + * @returns {Promise} Resolves to the owner's user ID if the token is valid. + * @throws {ApiError} Thrown with a status code of 401 if the token is invalid. + */ public static async getTokenOwner(scalarToken: string, ignoreUpstreams?: boolean): Promise { const cachedUserId = Cache.for(CACHE_SCALAR_ACCOUNTS).get(scalarToken); if (cachedUserId) return cachedUserId; diff --git a/src/api/scalar/ScalarWidgetService.ts b/src/api/scalar/ScalarWidgetService.ts index ef3c6d3..7de17e9 100644 --- a/src/api/scalar/ScalarWidgetService.ts +++ b/src/api/scalar/ScalarWidgetService.ts @@ -18,6 +18,9 @@ interface UrlPreviewResponse { }; } +/** + * API for the minimum Scalar API for widget functionality in clients. + */ @Path("/api/v1/scalar/widgets") export class ScalarWidgetService {