Overview
JumpCloud is transitioning its evaluation engine for Custom REST API Import Connectors from GoLang (GoTemplate) to EXPR. This upgrade introduces a more robust, expressive, and standardized expression language for attribute transformations, pre-processing filters, and user state management when importing identity records from external HRIS providers, like Workday, Personio, UKG Pro, and Dayforce.
Key Reasons for Migration
Enhanced Expressiveness: EXPR provides a purpose-built expression language with native operators, array manipulations, and string transformation capabilities that were cumbersome or limited in GoTemplates
Pre-Processing Data Filters: Enables complex filtering directly on incoming provider payloads—preventing state misalignment or unintended attribute overwrites when providers return multiple records per person (e.g., re-hires or multi-assignment profiles)
Dynamic Attribute & State Mappings: Simplifies translation logic for custom user attributes, dynamic group rules, and status mapping without requiring hardcoded translation lists
Admin Migration Workflow
- Notification: Administrators will receive an in-app notice when editing existing Custom REST API Import configurations that rely on GoTemplate expressions.
- In-App Migration Experience: JumpCloud will provide a guided migration interface within the console to help convert existing GoLang template rules into valid EXPR syntax.
- Verification: Admins should review and test converted expressions against sample API responses prior to saving the updated connector setup.
See the Official EXPR Documentation: EXPR Language Definition.
Writing EXPR Expressions
The following examples demonstrate how to construct an EXPR expression. Please note that providerUser. serves as the standard prefix for accessing any field provided by service providers
{
"id":"123"
"preferred_name":"xyz"
}
Expression: providerUser.preferred_name
Result: xyz
Expression: providerUser.preferred_name + " random string"
Result: xyz random str
{
"id": "123",
"username": "hello.world"
"preferred_name":"null"
}
Expression: (providerUser.preferred_name ?? "") != "" ? providerUser.preferred_name : providerUser.username
Result: hello.world
{
"id": "123",
"first_name": "Hello"
"last_name":"World"
}
Expression: providerUser.first_name + " " + providerUser.last_name
Result: Hello World
{
"id": "123",
"first_name": "Hello"
"last_name":"World"
"department":"Engineering"
"is_manager":true
}
Expression: providerUser.is_manager == true ? "Engineering Manager" : "Engineer"
Result: Engineering Manager
{
"id": "123",
"first_name": "John"
"last_name":"Doe"
"employement_type":{
"name":"IT Consultant
}
}
Expression: (providerUser.employment_type != nil && providerUser.employment_type.name != nil && providerUser.employment_type.name contains "Consultant" ? "[B2B] " : (providerUser.employment_type != nil && providerUser.employment_type.name != nil && providerUser.employment_type.name contains "Employee" ? "[EMP] " : "")) + (providerUser.first_name ?? "") + " " + (providerUser.last_name ?? "")
Result: [B2B] John Doe
{
"id": "123",
"eligible_paid_time_off": [
{ "policy_name": "Sick Policy",
"policy_uuid": "1b34bba6-ed31-4bfa-84a4-e70edae0d97d"
},
{
"policy_name": "Paid Time Off Policy",
"policy_uuid": "08fb23bc-88fb-484f-b805-aa7f22399575"
}
]
}
Expression: len(providerUser.eligible_paid_time_off ?? []) > 1 ? providerUser.eligible_paid_time_off[1].policy_name : ""
Result: Paid Time Off Policy
{ "id": "123",
"jobs": [
{ "compensations": [
{ "job_uuid": "53bee1b5-f7bc-4598-a5e1-66207cc73c4f",
"payment_unit": "Year",
"rate": "78000.00"
},
{
"job_uuid": "53bee1b5-f7bc-4598-a5e1-66207cc73c4f",
"payment_unit": "Year",
"rate": "85000.00"
}
]
}
]
}
Expression: len(providerUser.jobs ?? []) > 0 && len(providerUser.jobs[0].compensations ?? []) > 1 ? providerUser.jobs[0].compensations[1].rate : nil
Result: 85000.00
{
"customFieldGroup": {
"codeFields": [
{
"itemID": "13916651_182",
"nameCode": {
"codeValue": "T-Shirt Size",
"shortName": "T-Shirt Size"
}
},
{
"itemID": "1500091404_30",
"nameCode": {
"codeValue": "Uniform Size",
"shortName": "Uniform Size"
}
}
]
}
}
Expression: len(filter(providerUser.customFieldGroup.codeFields ?? [], #.itemID == "1500091404_30")) > 0 ? (filter(providerUser.customFieldGroup.codeFields ?? [], #.itemID == "1500091404_30")[0].nameCode?.codeValue ?? "") : ""
Result: Uniform Size
Migration Examples
| GoLang Template Expression | EXPR Expression |
{{.preferred_name}} | providerUser.preferred_name |
{{or .preferred_name .username}} | (providerUser.preferred_name ?? “”) != “” ? providerUser.preferred_name : (providerUser.username ?? “”) |
{{.first_name}} {{.last_name}} | providerUser.first_name + ” ” + providerUser.last_name |
{{- range .workAssignments -}}{{- if eq .assignmentStatus.statusCode.codeValue “A” -}}{{- if .assignedWorkLocations -}}{{- if (index .assignedWorkLocations 0).address -}}{{- (index .assignedWorkLocations 0).address.lineOne -}}{{- end -}}{{- end -}}{{- end -}}{{- end -}} | len(filter(providerUser.workAssignments ?? [], (#.assignmentStatus?.statusCode?.codeValue ?? ”) == ‘A’ && len(#.assignedWorkLocations ?? []) > 0)) > 0 ? (filter(providerUser.workAssignments ?? [], (#.assignmentStatus?.statusCode?.codeValue ?? ”) == ‘A’ && len(#.assignedWorkLocations ?? []) > 0)[0].assignedWorkLocations[0]?.address?.lineOne ?? ”) : ” |
{{- range .workAssignments -}}{{- if eq .assignmentStatus.statusCode.codeValue “A” -}}{{- if .assignedWorkLocations -}}{{- if (index .assignedWorkLocations 0).address -}}{{- if (index .assignedWorkLocations 0).address.countrySubdivisionLevel1 -}}{{- (index .assignedWorkLocations 0).address.countrySubdivisionLevel1.shortName -}}{{- end -}}{{- end -}}{{- end -}}{{- end -}}{{- end -}} | len(filter(providerUser.workAssignments ?? [], (#.assignmentStatus?.statusCode?.codeValue ?? “”) == “A”)) > 0 && len(filter(providerUser.workAssignments ?? [], (#.assignmentStatus?.statusCode?.codeValue ?? “”) == “A”)[0].assignedWorkLocations ?? []) > 0 ? (filter(providerUser.workAssignments ?? [], (#.assignmentStatus?.statusCode?.codeValue ?? “”) == “A”)[0].assignedWorkLocations[0].address?.countrySubdivisionLevel1?.shortName ?? “”) : “” |
{{ if or (and (.user.active) (eq .status “ACTIVE” “ACCEPTED”)) (and (not .user.active) (eq .status “TERMINATED” “INIT” “HIRED”)) }}{{ or .user.name.preferred_given_name .user.name.given_name }}{{ end }} | ((providerUser.user?.active == true && providerUser.status in [“ACTIVE”, “ACCEPTED”]) || (providerUser.user?.active != true && providerUser.status in [“TERMINATED”, “INIT”, “HIRED”])) ? ((providerUser.user?.name?.preferred_given_name ?? “”) != “” ? providerUser.user?.name?.preferred_given_name : (providerUser.user?.name?.given_name ?? “”)) : nil |