WebAPI (server scripting)

Server-side scripts run as GSP (Groovy Server Pages) or .groovy endpoints. Scripts receive a number of globals — WebAPI among them — for working with HTTP and content (JCR).

Execution model

Scripts are stored as JCR content and invoked at:

/bin/cms.cgi/<workspace>/content/<path>/<script.groovy|.gsp>

Example: GET /bin/cms.cgi/web/content/commerce/endpoints/health.groovy?days=7

Script globals (main ones)

Name Type Purpose
out Writer write to the response body
request / response HttpServletRequest / HttpServletResponse HTTP in/out
session / application HttpSession / ServletContext session / app-shared state
repositorySession Session (script resource API) the main way to read/write JCR content
resource Resource the JCR resource being processed
WebAPI WebAPI include / fetch / parameters / encoding (only when request exists)
log (LoggerAPI) LoggerAPI logging (debug/info/warn/error)
JSON / YAML JSON / YAML parse & serialize
XPath / MetadataAPI query / metadata
ProcessAPI / IntegrationAPI BPM / EIP integration
EventAdminAPI / cluster / CryptoAPI / MimeTypeAPI / SessionAPI events / cluster / crypto / MIME / session creation

(request / response / out are available only when the script is triggered over HTTP.)

WebAPI methods

Method Purpose
include(path) include another resource (e.g. a GSP); a leading / is workspace-relative
forward(path) forward to another resource
importContent(path[, encoding]) write file / HTTP content (jcr://, relative/absolute path, or HTTP URL)
getParameter(name) a request parameter (single value or an uploaded file)
fetch(uri) HTTP GET (3s connect / 10s request timeout); returns a WebResource
encodeURIComponent / encodeURI / decodeURIComponent URI encode/decode

Session (script resource API)

Operate on content through repositorySession.

  • getResource(absPath) / getResourceByIdentifier(id) / getRootFolder() — get resources
  • commit() / rollback() — save / discard
  • deploy() — apply etc/jcr/deploy and etc/jcr/provisioning
  • adaptTo(javax.jcr.Session) — adapt to the low-level JCR session
  • impersonate(userId) / newSession() — another user / a new session
  • isAdmin() / isAnonymous() / isService() / getUserID() — who is running

Main Resource operations

  • read: getContent() / getContentAsStream() / getProperty(name) / list()
  • write: write(content) / setProperty(name, value) / createFile() / createFolder() / getOrCreateFile(name)
  • move, etc.: moveTo(path) / copyTo(path) / remove()
  • versioning: addVersionControl() / checkout() / checkin() / checkpoint()
  • locking: lock() / unlock() / isLocked()
  • ACL: getAccessControlList() / setAccessControlList(acl) / canRead() / canWrite()

Examples

GSP include:

<% WebAPI.include("/content/public/inc/head_start.gsp") %>

A JSON endpoint (.groovy):

int days = (request.getParameter("days") ?: "7") as int
try {
  def snapshot = Health.snapshot(repositorySession, days)
  response.setStatus(200)
  response.setHeader("Content-Type", "application/json")
  response.getWriter().write(new ObjectMapper().writeValueAsString(snapshot))
} catch (Exception e) {
  log.error("health endpoint error: ${e.message}", e)
  response.setStatus(500)
}

Create and save content:

def res = repositorySession.getRootFolder().getOrCreateFile("content/notes/hello.json")
res.write('{"hello":"world"}')
res.setProperty("jcr:mimeType", "application/json")
repositorySession.commit()

For authorization and service accounts, see "Users, roles & permissions".

Folder descriptor .web.yml (publishing & rendering)

Dropping a .web.yml into a folder declares how the files in that folder (and its descendants) behave when served. It is a configuration file and is never delivered over the web. Settings are resolved by walking up to the nearest ancestor folder's .web.yml.

Site document root (site.root)

site:
  root: true                      # make this folder the public site root (URL `/`)
  baseURL: "https://example.com"  # canonical public origin (optional metadata)

The folder that declares root: true becomes the document root. Placed at /content/public, for example, the public site mounts that folder at / (e.g. NGINX maps /index.gsp/content/public/index.gsp).

This makes site-root-absolute paths inside the content (e.g. href="/docs/css/docs.css", src="/img/logo.svg") resolve correctly for whichever mount point serves them. Authors keep writing absolute paths, and the same content looks identical through either path:

Serving path Where /docs/css/docs.css resolves
Public site At the origin root (https://example.com/docs/css/docs.css)
webtop text-editor preview /bin/cms.cgi/<workspace>/content/public/docs/css/docs.css

The preview performs this rewrite with a Service Worker, so it requires HTTPS (a secure context). Over HTTP — or for files in a folder that does not declare a root — absolute paths are not rewritten (relative paths still resolve as before). baseURL is optional metadata describing the canonical origin; the path-based preview rewrite does not need it.

Binding to a template (render)

Source files (e.g. *.md) can be bound to a template per folder, instead of configuring each file, and rendered through it.

render:
  - match: "*.md"                                  # glob (supports * ?) matched against the file name
    template: "/content/WEB-INF/templates/doc.html"
    output: ["html"]                               # allowed output extensions (any when omitted)

An explicit web.template property set on a file takes precedence. The resolved binding and document root are exposed via GraphQL as node.webRender (templated / fromDescriptor / source / outputs / documentRoot).