Technical Bulletin: Migrate HRIS Expressions from GoLang (GoTemplate) to EXPR

Overview

JumpCloud is transitioning its evaluation engine for Custom REST API Import (HRIS) 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

  1. Notification: Administrators will receive an in-app notice when editing existing HRIS Import configurations that rely on GoTemplate expressions.
  2. In-App Migration Experience: After Changing Legacy Expression to Expression, the Migration modal will appear. Use the JumpCloud Admin AI Assistant, or your preferred AI tool, to convert your legacy Go expressions to EXPR.
  3. Verification: Admins should review the converted expressions using the Preview Mapping functionality prior to saving the updated connector setup.

Note:

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

EXPR Examples

{
"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

GoLang to EXPR Migration Table

GoLang Template ExpressionEXPR 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
Back to Top

List IconIn this Article

Still Have Questions?

If you cannot find an answer to your question in our FAQ, you can always contact us.

Submit a Case