Back to Abp

Custom Endpoints

docs/en/low-code/custom-endpoints.md

10.3.05.2 KB
Original Source
json
//[doc-seo]
{
    "Description": "Define custom REST API endpoints with JavaScript handlers in the ABP Low-Code System. Create dynamic APIs without writing C# controllers."
}

Custom Endpoints

Custom Endpoints allow you to define REST API routes with server-side JavaScript handlers directly in model.json. Each endpoint is registered as an ASP.NET Core endpoint at startup and supports hot-reload when the model changes.

Defining Endpoints

Add endpoints to the endpoints array in model.json:

json
{
  "endpoints": [
    {
      "name": "GetProductStats",
      "route": "/api/custom/products/stats",
      "method": "GET",
      "description": "Get product statistics",
      "requireAuthentication": false,
      "javascript": "var count = await db.count('LowCodeDemo.Products.Product');\nreturn ok({ totalProducts: count });"
    }
  ]
}

Endpoint Descriptor

FieldTypeDefaultDescription
namestringRequiredUnique endpoint name
routestringRequiredURL route pattern (supports {parameters})
methodstring"GET"HTTP method: GET, POST, PUT, DELETE
javascriptstringRequiredJavaScript handler code
descriptionstringnullDescription for documentation
requireAuthenticationbooltrueRequire authenticated user
requiredPermissionsstring[]nullRequired permission names

Route Parameters

Use {paramName} syntax in the route. Access values via the route object:

json
{
  "name": "GetProductById",
  "route": "/api/custom/products/{id}",
  "method": "GET",
  "javascript": "var product = await db.get('LowCodeDemo.Products.Product', route.id);\nif (!product) { return notFound('Product not found'); }\nreturn ok({ id: product.Id, name: product.Name, price: product.Price });"
}

JavaScript Context

Inside custom endpoint scripts, you have access to:

Request Context

VariableDescription
requestFull request object
routeRoute parameter values (e.g., route.id)
paramsAlias for route parameters
queryQuery string parameters (e.g., query.q, query.page)
bodyRequest body (for POST/PUT)
headersRequest headers
userCurrent user (same as context.currentUser in Interceptors)
emailEmail sender (same as context.emailSender in Interceptors)

Response Helpers

FunctionHTTP StatusDescription
ok(data)200Success response with data
created(data)201Created response with data
noContent()204No content response
badRequest(message)400Bad request response
unauthorized(message)401Unauthorized response
forbidden(message)403Forbidden response
notFound(message)404Not found response
error(message)500Internal server error response
response(statusCode, data, error)CustomCustom status code response

Logging

FunctionDescription
log(message)Log an informational message
logWarning(message)Log a warning message
logError(message)Log an error message

Database API

The full Scripting API (db object) is available for querying and mutating data.

Examples

Get Statistics

json
{
  "name": "GetProductStats",
  "route": "/api/custom/products/stats",
  "method": "GET",
  "requireAuthentication": false,
  "javascript": "var totalCount = await db.count('LowCodeDemo.Products.Product');\nvar avgPrice = totalCount > 0 ? await db.query('LowCodeDemo.Products.Product').average(p => p.Price) : 0;\nreturn ok({ totalProducts: totalCount, averagePrice: avgPrice });"
}

Search with Query Parameters

json
{
  "name": "SearchCustomers",
  "route": "/api/custom/customers/search",
  "method": "GET",
  "requireAuthentication": true,
  "javascript": "var searchTerm = query.q || '';\nvar customers = await db.query('LowCodeDemo.Customers.Customer')\n  .where(c => c.Name.toLowerCase().includes(searchTerm.toLowerCase()))\n  .take(10)\n  .toList();\nreturn ok(customers.map(c => ({ id: c.Id, name: c.Name, email: c.EmailAddress })));"
}

Dashboard Summary

json
{
  "name": "GetDashboardSummary",
  "route": "/api/custom/dashboard",
  "method": "GET",
  "requireAuthentication": true,
  "javascript": "var productCount = await db.count('LowCodeDemo.Products.Product');\nvar customerCount = await db.count('LowCodeDemo.Customers.Customer');\nvar orderCount = await db.count('LowCodeDemo.Orders.Order');\nreturn ok({ products: productCount, customers: customerCount, orders: orderCount, user: user.isAuthenticated ? user.userName : 'Anonymous' });"
}

Authentication and Authorization

SettingBehavior
requireAuthentication: falseEndpoint is publicly accessible
requireAuthentication: trueUser must be authenticated
requiredPermissions: ["MyApp.Products"]User must have the specified permissions

See Also