IIndividualPartyManagementPATCH Apex Interface

The IIndividualPartyManagementPATCH Apex interface provides extensibility for PATCH operations through Apex pre- and post-hooks and GraphQL query customization. Implementations can validate incoming requests, modify query structures, and refine the response to support business-specific retrieval rules while maintaining TMF-compliant behavior.

This interface supports the following hooks.

Update Operation Use Cases 

Use CaseHook(s)DescriptionExample ScenariosBenefit
Block Updates to Protected FieldstransformRequestExamines and transforms the request before validation and mutation processing. Protected or unauthorized fields can be removed from the update payload before the write occurs.- Remove system-managed identifiers
- Prevent clients from changing ownership fields
- Strip restricted financial or security attributes
- Remove fields that are read-only for the caller’s role
Protects controlled fields by stripping disallowed values before they can be persisted.
Enforce Value Policies on UpdateapplyCustomValidationsApplies organization-specific business rules to proposed field values before the update mutation is built. Invalid updates are rejected with an HTTP 400 response and a clear error message.- Reject invalid lifecycle-state transitions
- Enforce permitted ranges or enumerated values
- Require dependent fields when status changes
- Prevent updates that violate regional policies
Stops invalid updates early and preserves business and data integrity.
Add Custom Validation FlagsconfigureDefaultValidationsEnables, disables, or adds validation flags for update requests. This allows each organization to define the checks required before an update can proceed.- Require record-existence validation
- Enable optimistic concurrency checks
- Require version matching
- Apply stricter validation to regulated records
Supports per-organization update policies without changing the shared update implementation.
Stamp Audit Fields on UpdatecustomiseMutationPayloadAdds audit and provenance fields to the GraphQL mutation payload before execution. This allows metadata beyond the TMF632 schema to be persisted with the update.- Add lastModifiedBy and lastModifiedAt
- Record the source channel or integration
- Store a request or correlation ID
- Capture the reason for the update
Persists provenance and audit information beyond the standard TMF632 data model.
Enrich the Update ResponsehandlePostOperationProcesses the mutation result before it is returned to the client. It can add calculated values, derived fields, audit metadata, or information obtained from related systems.- Add a customer health score
- Include update audit metadata
- Return normalized display values
- Add related status or eligibility indicators
Delivers a richer, more contextual response without modifying the underlying TMF632 schema.

transformRequest 

This hook transforms the request context before processing any operation. It is invoked early in the request lifecycle, allowing implementers to adjust the context for subsequent extensibility hooks.

Hook Method 

Map<String, Object> transformRequest(Map<String, Object> context)

Sample Apex Implementation 

Prevent updates to familyName.

1global class IndividualPatchTransformRequestExt implements comms_apex_ext.IIndividualPartyManagementPATCH {
2
3
4    global static Map<String, Object> transformRequest(Map<String, Object> context) {
5        if (context != null && context.get('requestBody') instanceof Map<String, Object>) {
6            Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
7            // Business rule: last name changes must go through a separate governance flow.
8            body.remove('familyName');
9        }
10        return context;
11    }
12
13
14    // ... other hooks return null / empty map ...
15}

configureDefaultValidations 

This hook enables, disables, or modifies the built-in validation rules before they execute.

Hook Method 

Map<String, Boolean> configureDefaultValidations(Map<String, Boolean> defaultValidationConfiguration, Map<String, Object> context)

Sample Apex Implementation 

Add a custom flag consumed by applyCustomValidations.

1global class IndividualPatchConfigValidationsExt implements comms_apex_ext.IIndividualPartyManagementPATCH {
2
3
4    global static Map<String, Boolean> configureDefaultValidations(
5        Map<String, Boolean> defaultValidationConfiguration,
6        Map<String, Object> context
7    ) {
8        Map<String, Boolean> overrides = defaultValidationConfiguration != null
9            ? defaultValidationConfiguration.clone()
10            : new Map<String, Boolean>();
11        overrides.put('emailDomainCheck', true);   // your own flag, read in applyCustomValidations
12        return overrides;
13    }
14
15
16    // ... other hooks return null / empty map ...
17}

applyCustomValidations 

This hook validates custom business logic before retrieving customer record. If validation fails, it rejects the request and returns an error response.

The handler processes return values as follows.

Success:

  • Return a map with validationStatus set to “pass” (case-insensitive).
  • The API request continues normally.
  • Other fields in the map are logged but not used.

Failure:

  • Return a map with validationStatus set to “fail” (case-insensitive).
  • The API request is terminated immediately.
  • Raise a ValidationException containing
    • message: value from validationMessage key (or “Validation failed” by default)
    • details: value from validationDetails key (optional)
  • The client receives an HTTP 400 error response.

Hook Method 

Map<String, Object> applyCustomValidations(Map<String, Object> context)

Sample Apex Implementation 

Validate the updated email domain.

1global class IndividualPatchValidationExt implements comms_apex_ext.IIndividualPartyManagementPATCH {
2
3
4    global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
5        Map<String, Object> result = new Map<String, Object>();
6        if (!(context.get('requestBody') instanceof Map<String, Object>)) {
7            return result;
8        }
9        Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
10
11
12        if (body.get('contactMedium') instanceof List<Object>) {
13            for (Object cmObj : (List<Object>) body.get('contactMedium')) {
14                Map<String, Object> cm = (Map<String, Object>) cmObj;
15                if ('EmailContactMedium'.equals(cm.get('@type'))) {
16                    String email = (String) cm.get('emailAddress');
17                    if (email != null && !email.endsWithIgnoreCase('@acme.com')) {
18                        result.put('validationStatus', 'fail');
19                        result.put('validationMessage',
20                            'Email domain not allowed. Individuals must use an @acme.com address.');
21                    }
22                }
23            }
24        }
25        return result;   // empty => proceed; validationStatus="fail" => HTTP 400
26    }
27
28
29    // ... other hooks return null / empty map ...
30}

customiseMutationPayload 

This hook modifies the GraphQL query before execution to add fields, filters, or transformations.

Hook Method 

Map<String, Object> customiseMutationPayload(Map<String, Object> graphQLAsMap,Map<String, Object> context)

Sample Apex Implementation 

Stamp an audit field on update.

1global class IndividualPatchCustomMutationExt implements comms_apex_ext.IIndividualPartyManagementPATCH {
2    global static Map<String, Object> customiseMutationPayload(
3        Map<String, Object> graphQLAsMap,
4        Map<String, Object> context
5    ) {
6        Map<String, Object> node = new Map<String, Object>{
7            'path' => 'individualData',
8            'addFields' => new Map<String, Object>{
9                'Last_API_Update__c' => 'TMF632-PATCH'
10            }
11        };
12        return new Map<String, Object>{
13            'nodes' => new List<Object>{ node }
14        };
15    }
16    // ... other hooks return null / empty map ...
17}

handlePostOperation 

This hook post-processes and transforms the API response after data retrieval.

Hook Method 

Map<String, Object> handlePostOperation(Map<String, Object> graphQLQueryResultAsMap, Map<String, Object> constructedTMFResponse, Map<String, Object> context)

Sample Apex Implementation 

Enrich the response in place.

1global class IndividualPatchEnrichExt implements comms_apex_ext.IIndividualPartyManagementPATCH {
2
3
4    global static Map<String, Object> handlePostOperation(
5        Map<String, Object> graphQLQueryResultAsMap,
6        Map<String, Object> constructedTMFResponse,
7        Map<String, Object> context
8    ) {
9        if (constructedTMFResponse != null) {
10            constructedTMFResponse.put('updatedBy', UserInfo.getName());
11            constructedTMFResponse.put('lastUpdatedAt',
12                DateTime.now().format('yyyy-MM-dd\'T\'HH:mm:ss\'Z\''));
13        }
14        return null;   // keeps the mutated response as the final payload
15    }
16
17
18    // ... other hooks return null / empty map ...
19}

Full Implementation Example 

Here’s a complete sample Apex implementation using all supported hooks.

1/**
2 * Complete TMF632 Individual (Party Management) PATCH API extension,
3 * demonstrating all hooks with business logic.
4 */
5global class IndividualPartyManagementPATCHExtension implements comms_apex_ext.IIndividualPartyManagementPATCH {
6
7
8    // Hook 1: prevent familyName updates via the API.
9    global static Map<String, Object> transformRequest(Map<String, Object> context) {
10        if (context != null && context.get('requestBody') instanceof Map<String, Object>) {
11            ((Map<String, Object>) context.get('requestBody')).remove('familyName');
12        }
13        return context;
14    }
15
16
17    // Hook 2: PATCH has no default validators; keep it that way.
18    global static Map<String, Boolean> configureDefaultValidations(
19        Map<String, Boolean> defaultValidationConfiguration,
20        Map<String, Object> context
21    ) {
22        return new Map<String, Boolean>();
23    }
24
25
26    // Hook 3: enforce the corporate email domain on update.
27    global static Map<String, Object> applyCustomValidations(Map<String, Object> context) {
28        Map<String, Object> result = new Map<String, Object>();
29        if (context.get('requestBody') instanceof Map<String, Object>) {
30            Map<String, Object> body = (Map<String, Object>) context.get('requestBody');
31            if (body.get('contactMedium') instanceof List<Object>) {
32                for (Object cmObj : (List<Object>) body.get('contactMedium')) {
33                    Map<String, Object> cm = (Map<String, Object>) cmObj;
34                    if ('EmailContactMedium'.equals(cm.get('@type'))) {
35                        String email = (String) cm.get('emailAddress');
36                        if (email != null && !email.endsWithIgnoreCase('@acme.com')) {
37                            result.put('validationStatus', 'fail');
38                            result.put('validationMessage',
39                                'Email domain not allowed. Individuals must use an @acme.com address.');
40                        }
41                    }
42                }
43            }
44        }
45        return result;
46    }
47
48
49    // Hook 4: stamp an audit field on update.
50    global static Map<String, Object> customiseMutationPayload(
51        Map<String, Object> graphQLAsMap,
52        Map<String, Object> context
53    ) {
54        Map<String, Object> node = new Map<String, Object>{
55            'path' => 'individualData',
56            'addFields' => new Map<String, Object>{ 'Last_API_Update__c' => 'TMF632-PATCH' }
57        };
58        return new Map<String, Object>{ 'nodes' => new List<Object>{ node } };
59    }
60
61
62    // Hook 5: enrich the response in place.
63    global static Map<String, Object> handlePostOperation(
64        Map<String, Object> graphQLQueryResultAsMap,
65        Map<String, Object> constructedTMFResponse,
66        Map<String, Object> context
67    ) {
68        if (constructedTMFResponse != null) {
69            constructedTMFResponse.put('updatedBy', UserInfo.getName());
70        }
71        return null;
72    }
73}