Milesoft Liquid SDK (liquid-sdk)
1. Overview
The Liquid SDK (liquid-sdk) provides a strongly-typed programmatic interface to the Liquid compilation and resolution microservice of the Milesoft platform. It supports high-performance rendering of dynamic text, email layouts, and JSON payloads based on the Liquid template language. It also manages account-level template layouts, global app-level libraries, and custom text filters with automated context lazy-loading.
2. Initialization
2.1 Dependency Installation
The liquid-sdk package is hosted in our secure Google Cloud Artifact Registry repository.
To consume liquid-sdk in your Spring Boot application, apply the Google Cloud Artifact Registry plugin and declare our secure repository in your build.gradle:
plugins {
id "com.google.cloud.artifactregistry.gradle-plugin" version "2.2.5"
}
repositories {
mavenCentral()
maven { url "artifactregistry://us-west2-maven.pkg.dev/milesoft-repo/repo-maven" }
}
dependencies {
// Declaring the standard liquid-sdk library dependency
implementation "io.milesoft:liquid-sdk:2.1.0"
}
2.2 Central Spring Boot Configuration
Configure the underlying clients and LiquidService helper class inside your Spring configuration layer.
import io.milesoft.clients.PlatformClient;
import io.milesoft.clients.strategy.PlatformTokenProvider;
import io.milesoft.liquid.client.v2.LibraryClient;
import io.milesoft.liquid.client.v2.LiquidClient;
import io.milesoft.liquid.client.v2.TemplateClient;
import io.milesoft.liquid.services.LiquidService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class LiquidSdkConfig {
private final LiquidClient liquidClient;
private final LibraryClient libraryClient;
private final TemplateClient templateClient;
private final LiquidService liquidService;
@Autowired
public LiquidSdkConfig(PlatformClient platformClient,
@Value("${milesoft.liquid.baseUrl}") String baseUrl) {
PlatformTokenProvider tokenProvider = new PlatformTokenProvider(platformClient);
this.liquidClient = new LiquidClient(baseUrl, tokenProvider);
this.libraryClient = new LibraryClient(baseUrl, tokenProvider);
this.templateClient = new TemplateClient(baseUrl, tokenProvider);
this.liquidService = new LiquidService(liquidClient);
}
@Bean
public LiquidClient liquidClient() { return liquidClient; }
@Bean
public LibraryClient libraryClient() { return libraryClient; }
@Bean
public TemplateClient templateClient() { return templateClient; }
@Bean
public LiquidService liquidService() { return liquidService; }
}
3. Core SDK Clients & Method Specifications
Programmatic execution is managed across logical clients designed to completely abstract the underlying REST boundaries.
3.1 TemplateClient
Manages account-specific template configurations.
Templates list(String cursor, Integer limit, Actor actor): Lists active account templates.Templates loadBulk(Ids payload, Actor actor): Batch resolves templates by ID lists.Template create(SaveTemplate payload, Actor actor): Registers a template.Template update(String templateId, SaveTemplate payload, Actor actor): Updates template content or metadata.Template copy(String templateId, Actor actor): Clones an existing template within the account.Template installLibrary(String libraryId, Actor actor): Clones an app-level library template into the account portfolio.void delete(String templateId, Actor actor): Purges templates.
3.2 LibraryClient
Handles global app-level templates.
Templates listLibrary(String cursor, Integer limit, Actor actor): Lists app-level library templates.Templates loadBulkLibrary(Ids payload, Actor actor): Batch resolves library templates.Template createLibrary(SaveTemplate payload, Actor actor): Registers global templates.Template updateLibrary(String id, SaveTemplate payload, Actor actor): Updates global templates.Template cloneLibrary(String id, Actor actor): Clones library templates.void deleteLibrary(String id, Actor actor): Purges library templates.
3.3 LiquidClient
Performs compilation and resolution of Liquid layouts.
Resolved resolve(Resolve payload, Actor actor): Compiles raw Liquid strings using merge variables.ResolvedTemplate resolveSaved(String templateId, MergeData payload, Actor actor): Resolves database templates using merge data.ResolvedBulk resolveBulk(ResolveBulk payload, Actor actor): Compiles multiple raw Liquid strings in a single batch request.
3.4 LiquidService
A high-level convenience service designed for backend applications. It internally extracts the active Actor and handles direct compilation with the minimum boilerplate.
String resolve(String template, MergeData data): Directly compiles raw template text.
4. Custom Liquid Filters & Preloaded Contexts
4.1 Custom Template Filters
The Liquid service implements custom formatting filters directly inside the Shopify Liquid compilation engine:
| Filter Name | Class | Example Usage | Output / Behavior |
|---|---|---|---|
json |
EscapeJsonFilter |
{{ value | json }} |
Escapes literal characters safely for raw JSON embedding. |
money |
MoneyFilter |
{{ 1234.5 | money }} |
Formats numbers to currency string ($1,234.50). |
iso |
IsoDateTimeFilter |
{{ created | iso }} |
Formats date/time, local date, or local time objects to ISO-8601 strings. |
full |
FullDateTimeFilter |
{{ created | full }} |
Formats localized datetime using FormatStyle.FULL. |
long |
LongDateTimeFilter |
{{ created | long }} |
Formats localized datetime using FormatStyle.LONG. |
medium |
MediumDateTimeFilter |
{{ created | medium }} |
Formats localized datetime using FormatStyle.MEDIUM. |
short |
ShortDateTimeFilter |
{{ created | short }} |
Formats localized datetime using FormatStyle.SHORT. |
pretty |
PrettyDateTimeFilter |
{{ created | pretty }} |
Formats localized datetime using human-friendly pattern eee, d MMM h:mm a. |
custom |
CustomDateTimeFilter |
{{ created | custom: "yyyy-MM-dd" }} |
Formats localized datetime using custom format patterns. |
range |
DateTimeRangeFilter |
{{ start_time | range: stop_time }} |
Merges two localized datetimes into an optimized localized range span string. |
4.2 Lazy-Loaded Context Variables
Render requests leverage lazy-loading mechanisms, fetching metadata from database repositories only if referenced inside the template text:
today(TodayModel): LocalizedZonedDateTime,LocalDate, orLocalTime.app(AppModel): Active application configurations (id,title,url,logo_url,version).account(AccountModel): Active subscriber metadata, branding colors, and company URLs.profile(ProfileModel): Profile details of the active operator (id,name,first_name,last_name,email,phone).user(UserModel): Evaluated ifuserIdis passed in context. Exposes target user profile fields.contact(ContactModel): Evaluated ifcontactIdis passed in context. Exposes contact directory fields (names, phones, emails, addresses, dates, tags).users(UsersModel): Plural map of users resolved viauserQualifiers.contacts(ContactsModel): Plural map of contacts resolved viacontactQualifiers.
5. Code Examples
5.1 Rendering a Welcome Document
import io.milesoft.liquid.services.LiquidService;
import io.milesoft.primitives.merge.MergeData;
import io.milesoft.primitives.merge.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
@Service
public class DocumentRenderer {
private final LiquidService liquidService;
@Autowired
public DocumentRenderer(LiquidService liquidService) {
this.liquidService = liquidService;
}
public String generateWelcomeEmail(String userId, String contactId, String organizationName) {
// Construct custom dataset models
Model companyModel = Model.builder()
.key("organization")
.data(Map.of("name", organizationName))
.build();
// Populate context merge data
MergeData mergeData = MergeData.builder()
.userId(userId)
.contactId(contactId)
.models(List.of(companyModel))
.build();
String rawTemplate = "Dear {{ contact.first_name }},\n\n"
+ "Our customer success agent, {{ user.name }}, welcomes you on behalf of {{ organization.name }}! "
+ "Your account was successfully provisioned on {{ today.date | pretty }}.\n\n"
+ "Warm regards,\n{{ app.title }} Support";
// Resolve compiled output using the high-level service helper
return liquidService.resolve(rawTemplate, mergeData);
}
}
6. SDK Data Transfer Objects (DTOs)
SaveTemplate
Represents request payload to write or modify a template.
| Field | Type | Description / Constraints |
|---|---|---|
name |
String | Name of the template. Required / Not Blank. |
content |
String | Raw Liquid template body. Required / Not Blank. |
extra |
Map<String, String> | Optional auxiliary template content map. |
order |
Integer | Ordinal sorting value. Required / Min(0). |
metadata |
Map<String, Object> | Optional custom metadata. |
Template
Represents a persisted template model.
| Field | Type | Description / Constraints |
|---|---|---|
id |
String | Unique identifier. Required. |
name |
String | Template name. Required. |
content |
String | Raw Liquid template body. Required. |
extra |
Map<String, String> | Auxiliary content map. |
order |
Integer | Sort order. Required / Min(0). |
metadata |
Map<String, Object> | Custom metadata. |
created |
ZonedDateTime | Creation timestamp. Required. |
updated |
ZonedDateTime | Last update timestamp. Required. |
Templates
A paged container of templates.
| Field | Type | Description / Constraints |
|---|---|---|
templates |
List | List of template results. |
cursor |
String | Pagination continuation token. |
Ids
Bulk lookup ID parameter payload.
| Field | Type | Description / Constraints |
|---|---|---|
ids |
List |
List of unique identifiers. Required. |
Qualifier
A lookup tuple to map a dynamic key to a specific record ID.
| Field | Type | Description / Constraints |
|---|---|---|
key |
String | Context variable key. Required / Not Blank. |
id |
String | Target record database ID. Required / Not Blank. |
Model
A custom variable payload map to merge dynamically into the Liquid template environment.
| Field | Type | Description / Constraints |
|---|---|---|
key |
String | Root variable namespace (e.g. organization). Required / Not Blank. |
data |
Map<String, Object> | Map of keys and values. Required. |
MergeData
Main context container containing all inputs needed to resolve dynamic tokens inside Liquid strings.
| Field | Type | Description / Constraints |
|---|---|---|
userId |
String | Target user ID to bind under user. |
contactId |
String | Target contact ID to bind under contact. |
userQualifiers |
List |
List of custom user qualifiers. |
contactQualifiers |
List |
List of custom contact qualifiers. |
models |
List |
Custom model payload lists. |
Resolve
Execution parameters to parse a single content string.
| Field | Type | Description / Constraints |
|---|---|---|
content |
String | Target template text. Required / Not Blank. |
data |
MergeData | Contextual merge parameters. |
ResolveBulk
Execution parameters to parse a collection of content strings.
| Field | Type | Description / Constraints |
|---|---|---|
content |
Map<String, String> | Dictionary of keys to template text. Required (Size >= 1). |
data |
MergeData | Contextual merge parameters. |
Resolved
Result from a single content string resolution.
| Field | Type | Description / Constraints |
|---|---|---|
content |
String | Rendered plain text. Required / Not Blank. |
ResolvedBulk
Result from a bulk content string resolution.
| Field | Type | Description / Constraints |
|---|---|---|
content |
Map<String, String> | Dictionary of keys to rendered plain text. Required (Size >= 1). |
ResolvedTemplate
Rendered outputs from a database-persisted template.
| Field | Type | Description / Constraints |
|---|---|---|
name |
String | Template name. Required / Not Blank. |
content |
String | Rendered main content. Required / Not Blank. |
extra |
Map<String, String> | Rendered dictionary of auxiliary templates. |