Back to Abp

Script Actions

docs/en/low-code/script-actions.md

10.5.09.1 KB
Original Source
json
//[doc-seo]
{
    "Description": "Define event handlers, background jobs, background workers, script code editing, autocomplete, and dry-run testing in the ABP Low-Code Designer."
}

Script Actions

Preview: Script actions are part of the preview Low-Code System. Descriptor fields, designer screens, and script context members may change before general availability.

Use Actions in the Low-Code Designer when descriptor metadata and generated CRUD behavior are not enough. Actions can add JavaScript-backed HTTP endpoints, distributed event handlers, background jobs, and scheduled background workers.

Custom HTTP endpoints are documented separately in Custom Endpoints. This page focuses on the shared action designer experience and the event handler, background job, and background worker action types.

Action Types

TypeUse it forRuntime trigger
Custom endpointExpose a small model-owned REST APIHTTP request to the configured route
Event handlerReact to a named distributed eventevents.publishAsync(...) or any compatible distributed event publisher
Background jobRun named JavaScript work asynchronouslyjobs.enqueueAsync(...)
Background workerRun recurring JavaScript workperiod or cronExpression

All action scripts run server-side and use the shared Scripting API. Available services can be enabled or disabled per action type with scripting capability profiles.

Script Code Editor

The Designer uses a code editor for JavaScript fields in custom endpoints, event handlers, background jobs, background workers, and interceptors.

The editor provides:

  • Syntax highlighting for JavaScript
  • Type-aware completions for low-code services
  • Entity name completions for db, file, image, and attachment helpers
  • Entity property completions for query lambda parameters and query results
  • Enum completions through enums and enumValues
  • File and image field selector completions through fileFields and imageFields
  • An Available context list for the services enabled for the selected script type

The fileFields and imageFields globals are not lists of every entity property. They are selector trees for File and Image properties used by files.save(...), files.get(...), images.save(...), and images.get(...).

javascript
await files.save(fileFields.Acme.Campaigns.Campaign.Document, {
    fileName: 'brief.pdf',
    contentType: 'application/pdf',
    base64: base64Content
});

await images.save(imageFields.Acme.Campaigns.Campaign.BannerImage, {
    fileName: 'banner.png',
    contentType: 'image/png',
    base64: base64Image
});

Regular entity fields autocomplete from entity records and query lambda parameters:

javascript
var campaignQuery = await db.query('Acme.Campaigns.Campaign');
var rows = await campaignQuery
    .where(campaign => campaign.Name.includes('Spring'))
    .select(campaign => ({
        id: campaign.Id,
        name: campaign.Name
    }))
    .toList();

If the selected model layer is read-only, the Designer shows the JavaScript in a read-only editor. Switch to a writable layer before editing.

Event Handlers

Event handlers run when a distributed event with the configured name is published.

Descriptor

FieldTypeDescription
namestringUnique event handler name
eventNamestringDistributed event name to handle
javascriptstringJavaScript handler body
descriptionstringOptional documentation text

Context

GlobalDescription
handlerHandler runtime metadata
eventRuntime event metadata with name and data
eventNameEvent name string
eventDataEvent payload

Example

json
{
  "eventHandlers": [
    {
      "name": "NotifyCampaignCompleted",
      "eventName": "Acme.Campaigns.CampaignCompleted",
      "description": "Logs and notifies when a campaign is completed",
      "javascript": "log('Campaign completed: ' + eventData.id);\nawait email.queueAsync('[email protected]', 'Campaign completed', eventData.id);"
    }
  ]
}

Publish the event from another script:

javascript
await events.publishAsync('Acme.Campaigns.CampaignCompleted', {
    id: campaignId,
    completedAt: new Date().toISOString()
});

Background Jobs

Background jobs define named JavaScript handlers that can be enqueued from scripts.

Descriptor

FieldTypeDescription
namestringUnique job name used by jobs.enqueueAsync(...)
javascriptstringJavaScript job body
descriptionstringOptional documentation text

Context

GlobalDescription
jobJob runtime metadata
jobNameJob name string
jobDataParsed job payload
jobJsonDataRaw JSON payload

Example

json
{
  "backgroundJobs": [
    {
      "name": "SendCampaignSummary",
      "description": "Sends a summary for one campaign",
      "javascript": "var campaign = await db.get('Acme.Campaigns.Campaign', jobData.campaignId);\nif (!campaign) { userFriendlyError('Campaign not found.'); }\nawait email.queueAsync(jobData.to, 'Campaign summary', campaign.Name);"
    }
  ]
}

Enqueue the job from another script:

javascript
var jobId = await jobs.enqueueAsync('SendCampaignSummary', {
    campaignId: campaignId,
    to: '[email protected]'
}, {
    priority: 'Normal',
    delayMs: 60000
});

Background Workers

Background workers run recurring JavaScript work on a schedule.

Descriptor

FieldTypeDescription
namestringUnique worker name
periodnumberPeriod in milliseconds
cronExpressionstringCron expression for scheduled execution
javascriptstringJavaScript worker body
descriptionstringOptional documentation text

Configure either period or cronExpression.

Context

GlobalDescription
workerWorker runtime metadata
workerNameWorker name string

Example

json
{
  "backgroundWorkers": [
    {
      "name": "CampaignCleanup",
      "period": 3600000,
      "description": "Runs every hour",
      "javascript": "var query = await db.query('Acme.Campaigns.Campaign');\nvar stale = await query.where(c => c.Status === 0).take(100).toList();\nlog('Stale draft count: ' + stale.length);"
    }
  ]
}

Test JavaScript

Where the Designer shows Test JavaScript, you can run the current editor content without saving it. The built-in dry-run panel is available for custom endpoints, interceptors, event handlers, background jobs, and background workers.

For custom endpoints, provide request data:

  • Method
  • Path
  • Route values
  • Query values
  • Headers
  • Body JSON

For interceptors, provide the command name, entity name, command data, and an optional record id. For event handlers, provide event data JSON. For background jobs and background workers, provide the job or worker input JSON that the script expects.

When the script uses the HTTP API, you can also define outbound HTTP mocks. If a script calls http.getAsync(...), http.postAsync(...), or another HTTP helper, the dry-run engine returns the matching mock response instead of calling the real URL. If no mock matches, the result includes an HTTP mock miss.

Dry-run behavior:

OperationDry-run behavior
Database writesExecuted in a transaction and rolled back
Low-code file/image/attachment operationsCaptured as side effects without persisting files
Email send or queueCaptured as an email side effect; no email is sent
Event publishCaptured as an event side effect; no event is published
Background job enqueueCaptured as a job side effect; no job is enqueued
Outbound HTTPMatched against HTTP mocks; no real HTTP call is made
LogsReturned in the test result
ErrorsReturned with type, message, and diagnostics when available

Dry-run results can include:

  • Endpoint response data
  • Execution status and duration
  • Logs
  • Captured side effects
  • Error details

The endpoint dry-run still evaluates the endpoint authentication and permission metadata against the current user. If the test user is not authenticated or does not have the required permission, the dry-run returns the corresponding 401 or 403 endpoint response.

Operational Guidance

  • Prefer metadata and generated CRUD behavior before adding scripts.
  • Keep scripts small and focused.
  • Use explicit permissions for custom endpoints.
  • Use take() and specific filters for database queries.
  • Treat public unauthenticated endpoints as public API surface.
  • Keep outbound HTTP, email, event, job, file, and blob limits enabled for tenant-authored scripts.
  • Use capability profiles to disable services that a script type does not need.

See Also