Skip to content

Commit eb79f1f

Browse files
committed
feat: VariableSubstitutionService
1 parent 1c44825 commit eb79f1f

3 files changed

Lines changed: 441 additions & 0 deletions

File tree

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.syncapi.dto.request;
2+
3+
import java.util.Map;
4+
5+
/**
6+
* DTO containing a request with substituted variables.
7+
*/
8+
public class SubstitutedRequest {
9+
private final String url;
10+
private final Map<String, String> headers;
11+
private final Map<String, Object> body;
12+
13+
/**
14+
* Parameterized constructor.
15+
*
16+
* @param url the substituted URL
17+
* @param headers the substituted headers
18+
* @param body the substituted body
19+
*/
20+
public SubstitutedRequest(String url, Map<String, String> headers, Map<String, Object> body) {
21+
this.url = url;
22+
this.headers = headers;
23+
this.body = body;
24+
}
25+
26+
public String getUrl() {
27+
return url;
28+
}
29+
30+
public Map<String, String> getHeaders() {
31+
return headers;
32+
}
33+
34+
public Map<String, Object> getBody() {
35+
return body;
36+
}
37+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.syncapi.service.substitution;
2+
3+
import com.syncapi.dto.request.SubstitutedRequest;
4+
import org.springframework.stereotype.Service;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
9+
/**
10+
* Service for variable substitution in strings and requests.
11+
*/
12+
@Service
13+
public class VariableSubstitutionService {
14+
/**
15+
* Substitutes variables in the input string based on the provided variables.
16+
* <p>
17+
* For example, substitute("Hello, {{name}}!", Map.of("name", "World")) returns "Hello, World!"
18+
* <p>
19+
* Variables not found in the map are left unchanged.
20+
*
21+
* @param input the input string containing {{key}} patterns
22+
* @param variables the map of variable keys and their corresponding values
23+
* @return the input string with variables substituted
24+
*/
25+
public String substitute(String input, Map<String, String> variables) {
26+
if (input == null || input.isEmpty()) {
27+
return input;
28+
}
29+
30+
if (variables == null || variables.isEmpty()) {
31+
return input;
32+
}
33+
34+
String result = input;
35+
for (Map.Entry<String, String> entry : variables.entrySet()) {
36+
String token = "{{" + entry.getKey() + "}}";
37+
38+
String value = entry.getValue();
39+
if (value != null) {
40+
result = result.replace(token, value);
41+
}
42+
}
43+
44+
return result;
45+
}
46+
47+
/**
48+
* Substitutes variables in the Request's URL, headers, and body.
49+
* <p>
50+
* Returns a new SubstitutedRequest DTO to avoid mutating the JPA entity.
51+
*
52+
* @param url the request URL
53+
* @param headers the request headers
54+
* @param body the request body
55+
* @param variables the map of variable keys and their corresponding values
56+
* @return a new SubstitutedRequest with variables substituted
57+
*/
58+
public SubstitutedRequest substituteRequest(String url, Map<String, String> headers, Map<String, Object> body,
59+
Map<String, String> variables) {
60+
String substitutedUrl = substitute(url, variables);
61+
Map<String, String> substitutedHeaders = substituteHeaders(headers, variables);
62+
Map<String, Object> substitutedBody = substituteBody(body, variables);
63+
64+
return new SubstitutedRequest(substitutedUrl, substitutedHeaders, substitutedBody);
65+
}
66+
67+
/**
68+
* Substitutes variables in header values.
69+
*
70+
* @param headers the request headers
71+
* @param variables the map of variable keys and their corresponding values
72+
* @return a new map with substituted header values
73+
*/
74+
private Map<String, String> substituteHeaders(Map<String, String> headers, Map<String, String> variables) {
75+
if (headers == null || headers.isEmpty()) {
76+
return headers;
77+
}
78+
79+
Map<String, String> substitutedHeaders = new HashMap<>();
80+
for (Map.Entry<String, String> entry : headers.entrySet()) {
81+
String substitutedValue = substitute(entry.getValue(), variables);
82+
substitutedHeaders.put(entry.getKey(), substitutedValue);
83+
}
84+
85+
return substitutedHeaders;
86+
}
87+
88+
/**
89+
* Substitutes variables in body values (only for String values).
90+
*
91+
* @param body the request body
92+
* @param variables the map of variable keys and their corresponding values
93+
* @return a new map with substituted body values
94+
*/
95+
private Map<String, Object> substituteBody(Map<String, Object> body, Map<String, String> variables) {
96+
if (body == null || body.isEmpty()) {
97+
return body;
98+
}
99+
100+
Map<String, Object> substitutedBody = new HashMap<>();
101+
for (Map.Entry<String, Object> entry : body.entrySet()) {
102+
Object value = entry.getValue();
103+
if (value instanceof String) {
104+
substitutedBody.put(entry.getKey(), substitute((String) value, variables));
105+
} else {
106+
substitutedBody.put(entry.getKey(), value);
107+
}
108+
}
109+
110+
return substitutedBody;
111+
}
112+
}

0 commit comments

Comments
 (0)