write method

void write(
  1. ScenarioRecording recording
)

Writes recording, replacing whatever was there for the same exchange.

No request headers at all. They are not part of the key, so keeping them would be writing an Authorization into a committed file for nothing.

Response headers are kept except the ones keptHeader refuses, which is a deny-list and deliberately not an allow-list. An allow-list is the safer-sounding of the two and the wrong one here: what it drops it drops silently, and the first thing it drops is Link — so a screen that paginates works under live, is recorded, and quietly renders one page forever after, with the recording looking correct in the diff. A deny-list can only be wrong about a header nobody thought of, and it is wrong about it in a file somebody reads before committing.

A response body is on the same footing: an endpoint that answers with a token answers with a token. That is true of any fixture, and there is nothing this can do about it beyond writing it somewhere reviewable.

Implementation

void write(ScenarioRecording recording) {
  Directory(directory).createSync(recursive: true);
  var name = _name(recording.method, recording.url);
  // Unconditionally, and before the new one is written: a body recorded as
  // JSON and re-recorded as an error page changes extension, and the old
  // file would otherwise sit in the store forever with nothing left naming
  // it.
  _deleteBodies(name);
  var body = recording.body.isEmpty
      ? null
      : '$name.body.${_extensionFor(recording.contentType)}';
  if (body != null) {
    File(p.join(directory, body)).writeAsBytesSync(recording.body);
  }
  File(p.join(directory, '$name.json')).writeAsStringSync(
    '${const JsonEncoder.withIndent('  ').convert({
      'version': 1,
      'method': recording.method,
      'url': '${recording.url}',
      'status': recording.status,
      'contentType': ?recording.contentType,
      if (recording.headers.isNotEmpty) 'headers': {for (var key in recording.headers.keys.toList()..sort()) key: recording.headers[key]},
      'bytes': recording.body.length,
      'body': ?body,
      'recorded': (recording.recorded ?? DateTime.now().toUtc()).toIso8601String(),
    })}\n',
  );
}