or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

batch-processing.mdconfiguration-utilities.mdcrm-actions-functions.mdcrud-operations.mdentity-associations.mdindex.md

batch-processing.mddocs/

0

# Batch Processing

1

2

Transaction-based batch operations allowing multiple requests to be sent together with rollback capabilities. Batches can contain GET requests directly and change sets for transactional operations, providing efficient bulk processing with automatic error handling.

3

4

## Capabilities

5

6

### Batch Class

7

8

Container for multiple requests that can be processed as a single operation.

9

10

```typescript { .api }

11

/**

12

* Batch request container for sending multiple operations together

13

*/

14

class Batch implements BatchParameters {

15

/** Batch identifier name */

16

name?: string;

17

/** Change sets containing transactional operations */

18

changeSets?: Array<ChangeSet>;

19

/** GET requests (cannot be in change sets) */

20

requests?: Array<BatchRequest>;

21

/** Headers to apply to the entire batch */

22

headers?: Array<Header>;

23

/** Override async setting for batch */

24

async?: boolean;

25

/** Internal flag for URL length handling */

26

isOverLengthGet?: boolean;

27

28

constructor(parameters: BatchParameters);

29

}

30

31

interface BatchParameters extends BaseParameters {

32

name?: string;

33

changeSets?: Array<ChangeSet>;

34

requests?: Array<BatchRequest>;

35

isOverLengthGet?: boolean;

36

}

37

```

38

39

### ChangeSet Class

40

41

Transactional container where all operations succeed or fail together.

42

43

```typescript { .api }

44

/**

45

* Transactional container for batch operations - all requests succeed or fail together

46

*/

47

class ChangeSet implements ChangeSetParameters {

48

/** Change set identifier name */

49

name?: string;

50

/** Array of batch requests in this change set */

51

requests?: Array<BatchRequest>;

52

53

constructor(parameters: ChangeSetParameters);

54

}

55

56

interface ChangeSetParameters {

57

name?: string;

58

requests?: Array<BatchRequest>;

59

}

60

```

61

62

### BatchRequest Class

63

64

Individual request within a batch or change set.

65

66

```typescript { .api }

67

/**

68

* Individual request that can be included in batches or change sets

69

*/

70

class BatchRequest implements BatchRequestParameters {

71

/** HTTP method (GET, POST, PATCH, DELETE) */

72

method: string;

73

/** Request URL (optional, can be auto-generated) */

74

url?: string;

75

/** Request payload as JSON string */

76

payload?: string;

77

/** Headers specific to this request */

78

headers?: Array<Header>;

79

/** Content ID for referencing in other requests */

80

contentId?: string;

81

82

constructor(params: BatchRequestParameters);

83

}

84

85

interface BatchRequestParameters {

86

method: string;

87

url?: string;

88

payload?: string;

89

headers?: Array<Header>;

90

contentId?: string;

91

}

92

```

93

94

### Send Batch Operation

95

96

Executes a batch request and returns comprehensive response information.

97

98

```typescript { .api }

99

/**

100

* Send a batch request to CRM

101

* @param batch - Batch object containing requests and change sets

102

* @returns Promise resolving to batch response with results and error information

103

*/

104

function SendBatch(batch: Batch): Promise<BatchResponse> | BatchResponse;

105

```

106

107

### Batch Response Classes

108

109

```typescript { .api }

110

/**

111

* Response from a batch operation containing all individual responses

112

*/

113

class BatchResponse implements BatchResponseParameters {

114

/** Batch identifier name */

115

name?: string;

116

/** Responses from change sets */

117

changeSetResponses?: Array<ChangeSetResponse>;

118

/** Responses from direct batch requests (GET operations) */

119

batchResponses?: Array<Response>;

120

/** Whether any requests in the batch failed */

121

isFaulted?: boolean;

122

/** Collection of all error responses */

123

errors?: Array<string>;

124

/** Original XMLHttpRequest object */

125

xhr?: XMLHttpRequest;

126

127

constructor(parameters: BatchResponseParameters);

128

}

129

130

interface BatchResponseParameters {

131

name?: string;

132

changeSetResponses?: Array<ChangeSetResponse>;

133

batchResponses?: Array<Response>;

134

isFaulted?: boolean;

135

errors?: Array<string>;

136

xhr?: XMLHttpRequest;

137

}

138

139

/**

140

* Response from a change set containing individual request responses

141

*/

142

class ChangeSetResponse {

143

/** Change set identifier name */

144

name?: string;

145

/** Individual responses for each request in the change set */

146

responses?: Array<Response>;

147

}

148

149

/**

150

* Individual response from a batch request

151

*/

152

class Response implements ResponseParameters {

153

/** Raw response data */

154

rawData?: string;

155

/** Content ID if specified in request */

156

contentId?: string;

157

/** Parsed response payload */

158

payload?: object;

159

/** HTTP status code */

160

status?: string;

161

/** Response headers as key-value object */

162

headers?: any;

163

164

constructor(parameters: ResponseParameters);

165

}

166

167

interface ResponseParameters {

168

rawData?: string;

169

contentId?: string;

170

payload?: object;

171

status?: string;

172

headers?: any;

173

}

174

```

175

176

## Usage Examples

177

178

### Basic Batch with Change Set

179

180

```typescript

181

// Create multiple related records in a transaction

182

const batch = new WebApiClient.Batch({

183

changeSets: [

184

new WebApiClient.ChangeSet({

185

requests: [

186

WebApiClient.Create({

187

entityName: "account",

188

entity: { name: "Parent Account" },

189

headers: [{ key: "Prefer", value: "return=representation" }],

190

asBatch: true

191

}),

192

WebApiClient.Create({

193

entityName: "contact",

194

entity: {

195

firstname: "John",

196

lastname: "Doe",

197

"parentcustomerid_account@odata.bind": "/accounts($1)" // Reference to first request

198

},

199

asBatch: true

200

})

201

]

202

})

203

]

204

});

205

206

const batchResponse = await WebApiClient.SendBatch(batch);

207

208

if (batchResponse.isFaulted) {

209

console.log("Batch failed:", batchResponse.errors);

210

} else {

211

console.log("All operations succeeded");

212

console.log(batchResponse.changeSetResponses[0].responses);

213

}

214

```

215

216

### Mixed Batch with GET and Change Operations

217

218

```typescript

219

// Combine read operations with transactional writes

220

const batch = new WebApiClient.Batch({

221

// GET requests go directly in batch (not in change sets)

222

requests: [

223

WebApiClient.Retrieve({

224

entityName: "systemuser",

225

queryParams: "?$select=fullname,systemuserid&$filter=isdisabled eq false",

226

asBatch: true

227

})

228

],

229

// Change operations go in change sets for transactions

230

changeSets: [

231

new WebApiClient.ChangeSet({

232

requests: [

233

WebApiClient.Update({

234

entityName: "account",

235

entityId: "12345678-1234-1234-1234-123456789abc",

236

entity: { name: "Updated Account" },

237

asBatch: true

238

}),

239

WebApiClient.Delete({

240

entityName: "contact",

241

entityId: "87654321-4321-4321-4321-cba987654321",

242

asBatch: true

243

})

244

]

245

})

246

]

247

});

248

249

const result = await WebApiClient.SendBatch(batch);

250

251

// Access GET request results

252

const userResults = result.batchResponses[0].payload;

253

254

// Access change set results

255

const changeResults = result.changeSetResponses[0].responses;

256

```

257

258

### Batch with Actions and Functions

259

260

```typescript

261

// Execute multiple CRM actions in a transaction

262

const batch = new WebApiClient.Batch({

263

changeSets: [

264

new WebApiClient.ChangeSet({

265

requests: [

266

WebApiClient.Execute(

267

WebApiClient.Requests.QualifyLeadRequest.with({

268

entityId: "lead-guid-here",

269

payload: {

270

CreateAccount: true,

271

CreateContact: true,

272

CreateOpportunity: true,

273

Status: 3

274

}

275

}),

276

{ asBatch: true }

277

),

278

WebApiClient.Execute(

279

WebApiClient.Requests.SendEmailRequest.with({

280

payload: {

281

TemplateId: "template-guid-here",

282

RegardingId: "opportunity-guid-here",

283

RegardingType: "opportunity"

284

}

285

}),

286

{ asBatch: true }

287

)

288

]

289

})

290

]

291

});

292

293

const actionResults = await WebApiClient.SendBatch(batch);

294

```

295

296

### Large FetchXML Automatic Batch

297

298

```typescript

299

// Long FetchXML queries are automatically converted to batch requests

300

const longFetchXml = `

301

<fetch mapping='logical'>

302

<entity name='account'>

303

<attribute name='name'/>

304

<attribute name='accountid'/>

305

<!-- Very long fetch query that exceeds URL limits -->

306

<filter type='and'>

307

<condition attribute='name' operator='like' value='%very long search term%'/>

308

<!-- Many more conditions... -->

309

</filter>

310

<link-entity name='contact' from='parentcustomerid' to='accountid'>

311

<!-- Many attributes and conditions -->

312

</link-entity>

313

</entity>

314

</fetch>`;

315

316

// This will automatically be sent as a batch if URL length exceeds limits

317

const results = await WebApiClient.Retrieve({

318

entityName: "account",

319

fetchXml: longFetchXml

320

});

321

```

322

323

### Error Handling and Response Processing

324

325

```typescript

326

const batch = new WebApiClient.Batch({

327

changeSets: [

328

new WebApiClient.ChangeSet({

329

name: "AccountOperations",

330

requests: [

331

WebApiClient.Create({

332

entityName: "account",

333

entity: { name: "Test Account 1" },

334

asBatch: true

335

}),

336

WebApiClient.Create({

337

entityName: "account",

338

entity: { name: "Test Account 2" },

339

asBatch: true

340

}),

341

WebApiClient.Update({

342

entityName: "account",

343

entityId: "existing-account-guid",

344

entity: { name: "Updated Name" },

345

asBatch: true

346

})

347

]

348

})

349

]

350

});

351

352

try {

353

const response = await WebApiClient.SendBatch(batch);

354

355

if (response.isFaulted) {

356

console.log("Batch contained errors:");

357

response.errors.forEach((error, index) => {

358

console.log(`Error ${index + 1}:`, error);

359

});

360

361

// Check individual change set responses

362

response.changeSetResponses.forEach((changeSetResp, csIndex) => {

363

console.log(`Change set ${csIndex} (${changeSetResp.name}):`);

364

changeSetResp.responses.forEach((resp, reqIndex) => {

365

if (resp.status !== "200" && resp.status !== "201") {

366

console.log(` Request ${reqIndex} failed:`, resp.status, resp.payload);

367

} else {

368

console.log(` Request ${reqIndex} succeeded:`, resp.payload);

369

}

370

});

371

});

372

} else {

373

console.log("All batch operations succeeded");

374

375

// Process successful results

376

const changeSetResults = response.changeSetResponses[0].responses;

377

changeSetResults.forEach((result, index) => {

378

console.log(`Operation ${index} result:`, {

379

status: result.status,

380

entityId: result.headers["OData-EntityId"],

381

data: result.payload

382

});

383

});

384

}

385

} catch (networkError) {

386

console.error("Network or request error:", networkError);

387

}

388

```

389

390

### Content ID References

391

392

```typescript

393

// Use content IDs to reference results from previous requests in the same batch

394

const batch = new WebApiClient.Batch({

395

changeSets: [

396

new WebApiClient.ChangeSet({

397

requests: [

398

// Create account with content ID

399

new WebApiClient.BatchRequest({

400

method: "POST",

401

url: WebApiClient.GetApiUrl() + WebApiClient.GetSetName("account"),

402

payload: JSON.stringify({ name: "Parent Account" }),

403

headers: [

404

{ key: "Content-Type", value: "application/json" },

405

{ key: "Prefer", value: "return=representation" }

406

],

407

contentId: "1"

408

}),

409

// Create contact referencing the account

410

new WebApiClient.BatchRequest({

411

method: "POST",

412

url: WebApiClient.GetApiUrl() + WebApiClient.GetSetName("contact"),

413

payload: JSON.stringify({

414

firstname: "John",

415

lastname: "Doe",

416

"parentcustomerid_account@odata.bind": "$1" // References content ID 1

417

}),

418

headers: [

419

{ key: "Content-Type", value: "application/json" }

420

],

421

contentId: "2"

422

})

423

]

424

})

425

]

426

});

427

428

const result = await WebApiClient.SendBatch(batch);

429

```

430

431

## Best Practices

432

433

1. **Use Change Sets for Transactional Operations**: Put related create, update, delete operations in change sets to ensure data consistency.

434

435

2. **Keep GET Requests Outside Change Sets**: Retrieve operations must be placed directly in the batch requests array.

436

437

3. **Limit Batch Size**: Keep batches under 100 requests for optimal performance.

438

439

4. **Handle Errors Properly**: Always check the `isFaulted` property and process errors appropriately.

440

441

5. **Use Content IDs for Dependencies**: When requests depend on results from previous requests in the same batch, use content IDs for references.

442

443

6. **Set Appropriate Headers**: Include necessary headers like `Prefer: return=representation` when you need response data.

444

445

7. **Monitor Performance**: Large batches may take longer to process and could timeout in some scenarios.