Skip to content

Commit 3426694

Browse files
hunterachiengjosephjclark
authored andcommitted
rapidpro: migrate from deprecated common-http to fetch (#1166)
* feat: update rapidpro Signed-off-by: Hunter Achieng <[email protected]> * feat: add changeset Signed-off-by: Hunter Achieng <[email protected]> * fix: remove config and fix r`return await` Signed-off-by: Hunter Achieng <[email protected]> * fix: update changeset Signed-off-by: Hunter Achieng <[email protected]> * fix: remove export of http Signed-off-by: Hunter Achieng <[email protected]> * fix: update changeset with removal of http export Signed-off-by: Hunter Achieng <[email protected]> * fix: remove nock Signed-off-by: Hunter Achieng <[email protected]> --------- Signed-off-by: Hunter Achieng <[email protected]>
1 parent afca231 commit 3426694

File tree

6 files changed

+109
-120
lines changed

6 files changed

+109
-120
lines changed

.changeset/six-crabs-remember.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@openfn/language-rapidpro': major
3+
---
4+
5+
- Update `rapidPro` to not use deprecated `common-http`.
6+
- Remove support and export of `axios`
7+
- Remove export of `http` namesepace from `common`
8+

packages/rapidpro/ast.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@
490490
"operation"
491491
],
492492
"docs": {
493-
"description": "Scopes an array of data based on a JSONPath.\nUseful when the source data has `n` items you would like to map to\nan operation.\nThe operation will receive a slice of the data based of each item\nof the JSONPath provided.\n\nIt also ensures the results of an operation make their way back into\nthe state's references.",
493+
"description": "Iterates over an array of items and invokes an operation upon each one, where the state\nobject is _scoped_ so that state.data is the item under iteration.\nThe rest of the state object is untouched and can be referenced as usual.\nYou can pass an array directly, or use lazy state or a JSONPath string to\nreference a slice of state.",
494494
"tags": [
495495
{
496496
"title": "public",
@@ -504,7 +504,18 @@
504504
},
505505
{
506506
"title": "example",
507-
"description": "each(\"$.[*]\",\n create(\"SObject\",\n field(\"FirstName\", sourceValue(\"$.firstName\"))\n )\n)"
507+
"description": "each(\n $.data,\n // Inside the callback operation, `$.data` is scoped to the item under iteration\n insert(\"patient\", {\n patient_name: $.data.properties.case_name,\n patient_id: $.data.case_id,\n })\n);",
508+
"caption": "Using lazy state ($) to iterate over items in state.data and pass each into an \"insert\" operation"
509+
},
510+
{
511+
"title": "example",
512+
"description": "each(\n $.data,\n insert(\"patient\", (state) => ({\n patient_id: state.data.case_id,\n ...state.data\n }))\n);",
513+
"caption": "Iterate over items in state.data and pass each one into an \"insert\" operation"
514+
},
515+
{
516+
"title": "example",
517+
"description": "each(\n \"$.data[*]\",\n insert(\"patient\", (state) => ({\n patient_name: state.data.properties.case_name,\n patient_id: state.data.case_id,\n }))\n);",
518+
"caption": "Using JSON path to iterate over items in state.data and pass each one into an \"insert\" operation"
508519
},
509520
{
510521
"title": "param",

packages/rapidpro/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
],
2222
"dependencies": {
2323
"@openfn/language-common": "workspace:*",
24-
"axios": "^1.7.7"
24+
"undici": "^7.8.0"
2525
},
2626
"devDependencies": {
2727
"chai": "^3.4.0",
@@ -44,4 +44,4 @@
4444
"./package.json": "./package.json"
4545
},
4646
"types": "types/index.d.ts"
47-
}
47+
}

packages/rapidpro/src/Adaptor.js

Lines changed: 78 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import {
22
execute as commonExecute,
33
composeNextState,
4-
http, // Important: this is the OLD axios-based http.
54
} from '@openfn/language-common';
65
import { expandReferences } from '@openfn/language-common/util';
7-
8-
const { axios } = http;
9-
export { axios };
6+
import { fetch } from 'undici';
107

118
/**
129
* Execute a sequence of operations.
@@ -48,31 +45,31 @@ export function execute(...operations) {
4845
* @param {function} callback - (Optional) callback function
4946
* @returns {Operation}
5047
*/
51-
export function addContact(params, callback) {
52-
return state => {
48+
export function addContact(params, callback = s => s) {
49+
return async state => {
5350
const [resolvedParams] = expandReferences(state, params);
5451

5552
const { host, apiVersion, token } = state.configuration;
5653

5754
const url = `${host}/api/${apiVersion || 'v2'}/contacts.json`;
5855

59-
const config = {
60-
url,
61-
data: resolvedParams,
62-
headers: { Authorization: `Token ${token}` },
63-
};
56+
const response = await fetch(url, {
57+
method: 'POST',
58+
headers: {
59+
Authorization: `Token ${token}`,
60+
'Content-Type': 'application/json',
61+
},
62+
body: JSON.stringify(resolvedParams),
63+
});
6464

65-
return http
66-
.post(config)(state)
67-
.then(response => {
68-
console.log('Contact added with uuid:', response.data.uuid);
69-
const nextState = {
70-
...composeNextState(state, response.data),
71-
response,
72-
};
73-
if (callback) return callback(nextState);
74-
return nextState;
75-
});
65+
const result = await response.json();
66+
67+
console.log('Contact added with uuid:', result.uuid);
68+
69+
return callback({
70+
...composeNextState(state, result),
71+
response,
72+
});
7673
};
7774
}
7875

@@ -90,59 +87,50 @@ export function addContact(params, callback) {
9087
* @param {function} callback - (Optional) callback function
9188
* @returns {Operation}
9289
*/
93-
export function upsertContact(params, callback) {
94-
return state => {
90+
export function upsertContact(params, callback = s => s) {
91+
return async state => {
9592
const [resolvedParams] = expandReferences(state, params);
9693

9794
const { host, apiVersion, token } = state.configuration;
9895

9996
const url = `${host}/api/${apiVersion || 'v2'}/contacts.json`;
10097

101-
const config = {
102-
url,
103-
data: resolvedParams,
104-
headers: { Authorization: `Token ${token}` },
105-
};
106-
107-
return http
108-
.post(config)(state)
109-
.then(resp => {
110-
console.log('Contact added with uuid:', resp.data.uuid);
111-
return resp;
112-
})
113-
.catch(err => {
114-
const { data } = err.response;
115-
if (
116-
data &&
117-
data.urns &&
118-
Array.isArray(data.urns) &&
119-
data.urns.find(x => x.includes('URN belongs to another'))
120-
) {
121-
const newUrl = `${url}?urn=${config.data.urns[0]}`;
122-
delete config.data['urns'];
123-
return http
124-
.post({ ...config, url: newUrl })(state)
125-
.then(resp => {
126-
console.log('Contact updated with uuid:', resp.data.uuid);
127-
return resp;
128-
});
129-
} else {
130-
console.log(JSON.stringify(data, null, 2));
98+
const response = await fetch(url, {
99+
method: 'POST',
100+
headers: {
101+
Authorization: `Token ${token}`,
102+
'Content-Type': 'application/json',
103+
},
104+
body: JSON.stringify(resolvedParams),
105+
});
131106

132-
delete err.response.request;
133-
delete err.response.config;
107+
let result = await response.json();
108+
if (result && result.urns && Array.isArray(result.urns['0'])) {
109+
const newUrl = `${url}?urn=${resolvedParams.urns[0]}`;
110+
111+
delete resolvedParams['urns'];
112+
result = await fetch(newUrl, {
113+
method: 'POST',
114+
headers: {
115+
'Content-Type': 'application/json',
116+
Authorization: `Token ${token}`,
117+
},
118+
body: JSON.stringify(resolvedParams),
119+
});
120+
const res = await result.json();
134121

135-
throw err.response;
136-
}
137-
})
138-
.then(response => {
139-
const nextState = {
140-
...composeNextState(state, response.data),
141-
response,
142-
};
143-
if (callback) return callback(nextState);
144-
return nextState;
122+
console.log('Contact updated with uuid:', res.uuid);
123+
return callback({
124+
...composeNextState(state, res),
125+
response: {},
145126
});
127+
} else {
128+
console.log('Contact added with uuid:', result.uuid);
129+
return callback({
130+
...composeNextState(state, result),
131+
response: {},
132+
});
133+
}
146134
};
147135
}
148136

@@ -160,38 +148,29 @@ export function upsertContact(params, callback) {
160148
* @param {function} callback - (Optional) callback function
161149
* @returns {Operation}
162150
*/
163-
export function startFlow(params, callback) {
164-
return state => {
151+
export function startFlow(params, callback = s => s) {
152+
return async state => {
165153
const [resolvedParams] = expandReferences(state, params);
166154

167155
const { host, apiVersion, token } = state.configuration;
168156

169157
const url = `${host}/api/${apiVersion || 'v2'}/flow_starts.json`;
170158

171-
const config = {
172-
url,
173-
data: resolvedParams,
159+
const response = await fetch(url, {
160+
method: 'POST',
174161
headers: {
175162
Authorization: `Token ${token}`,
176163
'Content-Type': 'application/json',
177164
},
178-
};
165+
body: JSON.stringify(resolvedParams),
166+
});
179167

180-
return http
181-
.post(config)(state)
182-
.catch(error => {
183-
console.log(error.response);
184-
throw 'That was an error from RapidPro.';
185-
})
186-
.then(response => {
187-
console.log('Flow started:', response.data);
188-
const nextState = {
189-
...composeNextState(state, response.data),
190-
response,
191-
};
192-
if (callback) return callback(nextState);
193-
return nextState;
194-
});
168+
const result = await response.json();
169+
console.log('Flow started:', result);
170+
return callback({
171+
...composeNextState(state, result),
172+
response,
173+
});
195174
};
196175
}
197176

@@ -209,38 +188,28 @@ export function startFlow(params, callback) {
209188
* @param {function} callback - (Optional) callback function
210189
* @returns {Operation}
211190
*/
212-
export function sendBroadcast(params, callback) {
213-
return state => {
191+
export function sendBroadcast(params, callback = s => s) {
192+
return async state => {
214193
const [resolvedParams] = expandReferences(state, params);
215194

216195
const { host, apiVersion, token } = state.configuration;
217196

218197
const url = `${host}/api/${apiVersion || 'v2'}/broadcasts.json`;
219198

220-
const config = {
221-
url,
222-
data: resolvedParams,
199+
const response = await fetch(url, {
200+
method: 'POST',
223201
headers: {
224202
Authorization: `Token ${token}`,
225203
'Content-Type': 'application/json',
226204
},
227-
};
228-
229-
return http
230-
.post(config)(state)
231-
.catch(error => {
232-
console.log(error.response);
233-
throw 'That was an error from RapidPro.';
234-
})
235-
.then(response => {
236-
console.log('Broadcast queued:', response.data);
237-
const nextState = {
238-
...composeNextState(state, response.data),
239-
response,
240-
};
241-
if (callback) return callback(nextState);
242-
return nextState;
243-
});
205+
body: JSON.stringify(resolvedParams),
206+
});
207+
const result = await response.json();
208+
console.log('Broadcast queued:', result);
209+
return callback({
210+
...composeNextState(state, result),
211+
response,
212+
});
244213
};
245214
}
246215

@@ -253,7 +222,6 @@ export {
253222
fields,
254223
fn,
255224
fnIf,
256-
http, // Important: this is the OLD axios-based http. Public docs will be incorrect.
257225
lastReferenceValue,
258226
merge,
259227
sourceValue,

packages/rapidpro/test/index.js

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import chai from 'chai';
22
const { expect } = chai;
3-
import nock from 'nock';
4-
const { back } = nock;
5-
import ClientFixtures, { fixtures } from './ClientFixtures';
63

74
import Adaptor from '../src';
85
const { execute } = Adaptor;

pnpm-lock.yaml

Lines changed: 8 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)