Skip to content

Commit

Permalink
feat: add action input validation and openapi definition
Browse files Browse the repository at this point in the history
  • Loading branch information
loopingz committed Nov 29, 2023
1 parent 862d051 commit fc0e28c
Show file tree
Hide file tree
Showing 14 changed files with 812 additions and 49 deletions.
10 changes: 9 additions & 1 deletion packages/async/src/models.ts
@@ -1,4 +1,4 @@
import { Action, CoreModel, OperationContext, WebContext, WebdaError } from "@webda/core";
import { Action, Core, CoreModel, OperationContext, WebContext, WebdaError } from "@webda/core";
import { WorkerLogLevel } from "@webda/workout";
import * as crypto from "crypto";

Expand Down Expand Up @@ -125,6 +125,14 @@ export default class AsyncAction extends CoreModel {
context.write({ ...this, logs: undefined, statusDetails: undefined });
}

/**
* Return the hook url if empty fallback to the service url
* @returns
*/
public getHookUrl(): string {
return Core.get().getRouter().getModelUrl(this);
}

/**
*
* @param body
Expand Down
4 changes: 3 additions & 1 deletion packages/async/src/services/asyncjobservice.ts
Expand Up @@ -370,7 +370,9 @@ export default class AsyncJobService<T extends AsyncJobServiceParameters = Async
JOB_SECRET_KEY: action.__secretKey,
JOB_ID: action.getUuid(),
JOB_HOOK:
this.parameters.onlyHttpHook || !action.isInternal() ? this.getWebda().getApiUrl(this.parameters.url) : "store", // How to find the absolute url
this.parameters.onlyHttpHook || !action.isInternal()
? action.getHookUrl() || this.getWebda().getApiUrl(this.parameters.url)
: "store", // How to find the absolute url
JOB_ORCHESTRATOR: this.getName()
};
}
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/application.ts
Expand Up @@ -629,6 +629,14 @@ export class Application {
return this.baseConfiguration.cachedModules.schemas[type];
}

/**
* Get schemas
* @returns
*/
getSchemas(): { [key: string]: JSONSchema7 } {
return this.baseConfiguration.cachedModules.schemas;
}

/**
* Check if a schema exists
* @param type
Expand Down
15 changes: 15 additions & 0 deletions packages/core/src/core.ts
Expand Up @@ -1513,6 +1513,21 @@ export class Core<E extends CoreEvents = CoreEvents> extends events.EventEmitter
this.application.getConfiguration().openapi || {}
);
let models = this.application.getModels();
const schemas = this.application.getSchemas();
// Copy all input/output from actions
for (let i in schemas) {
if (!(i.endsWith(".input") || i.endsWith(".output"))) {
continue;
}
// @ts-ignore
openapi.components.schemas[i] ??= schemas[i];
// Not sure how to test following
/* c8 ignore next 3 */
for (let j in schemas[i].definitions) {
// @ts-ignore
openapi.components.schemas[j] ??= schemas[i].definitions[j];
}
}
for (let i in models) {
let model = models[i];
let desc: JSONSchema7 = {
Expand Down
58 changes: 56 additions & 2 deletions packages/core/src/models/aclmodel.ts
@@ -1,4 +1,4 @@
import { ModelAction, OperationContext, Store, User, WebContext, WebdaError } from "../index";
import { OperationContext, User, WebContext, WebdaError } from "../index";
import { Action, CoreModel } from "./coremodel";

export type Acl = { [key: string]: string };
Expand Down Expand Up @@ -66,7 +66,61 @@ export default class AclModel extends CoreModel {
* @param ctx
* @returns
*/
@Action({ methods: ["GET", "PUT"] })
@Action({
methods: ["GET", "PUT"],
openapi: {
get: {
summary: "Get ACLs",
responses: {
"200": {
content: {
"application/json": {
schema: {
type: "object",
properties: {
raw: {
type: "object"
},
resolved: {
type: "array",
items: {
type: "object",
properties: {
permission: {
type: "string"
},
actor: {
type: "object"
}
}
}
}
}
}
}
}
}
}
},
put: {
summary: "Update ACLs",
requestBody: {
content: {
"application/json": {
schema: {
type: "object",
properties: {
raw: {
type: "object"
}
}
}
}
}
}
}
}
})
async acl(ctx: WebContext) {
if (ctx.getHttpContext().getMethod() === "PUT") {
return this._httpPutAcls(ctx);
Expand Down
9 changes: 9 additions & 0 deletions packages/core/src/router.spec.ts
@@ -1,5 +1,6 @@
import { suite, test } from "@testdeck/mocha";
import * as assert from "assert";
import { User } from "./models/user";
import { RouteInfo } from "./router";
import { WebdaTest } from "./test";
import { HttpContext } from "./utils/httpcontext";
Expand Down Expand Up @@ -197,4 +198,12 @@ class RouterTest extends WebdaTest {
this.webda.getRouter().removeRoute("/cov", info);
this.webda.getRouter().getRoutes();
}

@test
getModelUrl() {
let routes = this.webda.getRouter().getRoutes();
console.log(routes["/memory/users{?q}"][0].openapi);
let url = this.webda.getRouter().getModelUrl(new User());
console.log(url);
}
}
24 changes: 24 additions & 0 deletions packages/core/src/router.ts
Expand Up @@ -2,6 +2,7 @@ import { JSONSchema7 } from "json-schema";
import { OpenAPIV3 } from "openapi-types";
import uriTemplates from "uri-templates";
import { Core } from "./core";
import { CoreModel, CoreModelDefinition } from "./models/coremodel";
import { WebContext } from "./utils/context";
import { HttpMethodType } from "./utils/httpcontext";

Expand Down Expand Up @@ -44,6 +45,7 @@ export interface OpenAPIWebdaDefinition extends RecursivePartial<OpenAPIV3.PathI
* Route Information default information
*/
export interface RouteInfo {
model?: CoreModelDefinition;
/**
* HTTP Method to expose
*/
Expand Down Expand Up @@ -91,11 +93,33 @@ export class Router {
protected initiated: boolean = false;
protected pathMap: { url: string; config: RouteInfo }[];
protected webda: Core;
protected models: Map<string, string> = new Map();

constructor(webda: Core) {
this.webda = webda;
}

/**
* Registration of a model
* @param model
* @param url
*/
registerModelUrl(model: string, url: string) {
this.models.set(model, url);
}

/**
* Return the route for model
* @param model
* @returns
*/
getModelUrl(model: string | CoreModel) {
if (typeof model !== "string") {
model = this.webda.getApplication().getModelName(model);
}
return this.models.get(model);
}

/**
* Include prefix to the url if not present
* @param url
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/services/binary.ts
Expand Up @@ -79,6 +79,7 @@ export type BinaryFiles = BinaryFileInfo[];

/**
* Represent a file to store
* @WebdaSchema
*/
export abstract class BinaryFile<T = any> implements BinaryFileInfo {
/**
Expand Down
33 changes: 23 additions & 10 deletions packages/core/src/services/domainservice.spec.ts
Expand Up @@ -160,22 +160,35 @@ class DomainServiceTest extends WebdaTest {
},
context
});
await assert.rejects(
() =>
this.http({
method: "PUT",
url: `/classrooms/${result.results[0].uuid}/test`,
body: {
q: ""
},
context
}),
WebdaError.BadRequest
);
await this.http({
method: "PUT",
url: `/classrooms/${result.results[0].uuid}/test`,
body: {
q: ""
test: "123",
id: "123"
},
context
});
await this.http({
method: "PUT",
url: `/classrooms/${result.results[0].uuid}/hardwares/globalAction`,
body: {
q: ""
},
context
});
}),
await this.http({
method: "PUT",
url: `/classrooms/${result.results[0].uuid}/hardwares/globalAction`,
body: {
q: ""
},
context
});
await this.http({
method: "PUT",
url: `/hardwares/globalAction`,
Expand Down

0 comments on commit fc0e28c

Please sign in to comment.