Refactor SSE response handling and display

Updated response body widgets to handle SSE output as a list of strings instead of a single string. Adjusted view options for SSE-related media types and refactored SSEDisplay to be a stateless widget that accepts a list of SSE events. This improves clarity and consistency in handling and displaying SSE responses.
This commit is contained in:
Ankit Mahato
2025-08-06 00:32:02 +05:30
parent ce2f98af07
commit d491f0540d
4 changed files with 32 additions and 31 deletions

View File

@@ -183,6 +183,10 @@ const kPreviewCodeRawBodyViewOptions = [
ResponseBodyView.code,
ResponseBodyView.raw
];
const kPreviewSSERawBodyViewOptions = [
ResponseBodyView.sse,
ResponseBodyView.raw
];
const Map<String, Map<String, List<ResponseBodyView>>>
kResponseBodyViewOptions = {
@@ -196,6 +200,15 @@ const Map<String, Map<String, List<ResponseBodyView>>>
kSubTypeYaml: kCodeRawBodyViewOptions,
kSubTypeXYaml: kCodeRawBodyViewOptions,
kSubTypeYml: kCodeRawBodyViewOptions,
kSubTypeXNdjson: kPreviewSSERawBodyViewOptions,
kSubTypeNdjson: kPreviewSSERawBodyViewOptions,
kSubTypeJsonSeq: kPreviewSSERawBodyViewOptions,
kSubTypeXLdjson: kPreviewSSERawBodyViewOptions,
kSubTypeLdjson: kPreviewSSERawBodyViewOptions,
kSubTypeXJsonStream: kPreviewSSERawBodyViewOptions,
kSubTypeJsonStream: kPreviewSSERawBodyViewOptions,
kSubTypeJsonstream: kPreviewSSERawBodyViewOptions,
kSubTypeStreamJson: kPreviewSSERawBodyViewOptions,
},
kTypeImage: {
kSubTypeDefaultViewOptions: kPreviewBodyViewOptions,
@@ -217,6 +230,7 @@ const Map<String, Map<String, List<ResponseBodyView>>>
kSubTypeTextXml: kCodeRawBodyViewOptions,
kSubTypeTextYaml: kCodeRawBodyViewOptions,
kSubTypeTextYml: kCodeRawBodyViewOptions,
kSubTypeEventStream: kPreviewSSERawBodyViewOptions,
},
};

View File

@@ -1,5 +1,3 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:apidash_core/apidash_core.dart';
import 'package:apidash/models/models.dart';
@@ -24,6 +22,7 @@ class ResponseBody extends StatelessWidget {
message: '$kNullResponseModelError $kUnexpectedRaiseIssue');
}
final isSSE = responseModel.sseOutput?.isNotEmpty ?? false;
var body = responseModel.body;
var formattedBody = responseModel.formattedBody;
if (body == null) {
@@ -37,6 +36,9 @@ class ResponseBody extends StatelessWidget {
showIssueButton: false,
);
}
if (isSSE) {
body = responseModel.sseOutput!.join();
}
final mediaType =
responseModel.mediaType ?? MediaType(kTypeText, kSubTypePlain);
@@ -56,20 +58,6 @@ class ResponseBody extends StatelessWidget {
options.remove(ResponseBodyView.code);
}
// print('reM -> ${responseModel.sseOutput}');
if (responseModel.sseOutput?.isNotEmpty ?? false) {
// final modifiedBody = responseModel.sseOutput!.join('\n\n');
return ResponseBodySuccess(
key: Key("${selectedRequestModel!.id}-response"),
mediaType: MediaType('text', 'event-stream'),
options: [ResponseBodyView.sse, ResponseBodyView.raw],
bytes: utf8.encode((responseModel.sseOutput!).toString()),
body: jsonEncode(responseModel.sseOutput!),
formattedBody: responseModel.sseOutput!.join('\n'),
);
}
return ResponseBodySuccess(
key: Key("${selectedRequestModel!.id}-response"),
mediaType: mediaType,
@@ -77,6 +65,7 @@ class ResponseBody extends StatelessWidget {
bytes: responseModel.bodyBytes!,
body: body,
formattedBody: formattedBody,
sseOutput: responseModel.sseOutput,
highlightLanguage: highlightLanguage,
);
}

View File

@@ -15,13 +15,16 @@ class ResponseBodySuccess extends StatefulWidget {
required this.options,
required this.bytes,
this.formattedBody,
this.sseOutput,
this.highlightLanguage});
final MediaType mediaType;
final List<ResponseBodyView> options;
final String body;
final Uint8List bytes;
final String? formattedBody;
final List<String>? sseOutput;
final String? highlightLanguage;
@override
State<ResponseBodySuccess> createState() => _ResponseBodySuccessState();
}
@@ -150,7 +153,7 @@ class _ResponseBodySuccessState extends State<ResponseBodySuccess> {
padding: kP8,
decoration: textContainerdecoration,
child: SSEDisplay(
sseOutput: widget.body,
sseOutput: widget.sseOutput,
),
),
),

View File

@@ -2,26 +2,21 @@ import 'dart:convert';
import 'package:apidash_design_system/apidash_design_system.dart';
import 'package:flutter/material.dart';
class SSEDisplay extends StatefulWidget {
final String sseOutput;
const SSEDisplay({super.key, required this.sseOutput});
class SSEDisplay extends StatelessWidget {
final List<String>? sseOutput;
const SSEDisplay({
super.key,
this.sseOutput,
});
@override
State<SSEDisplay> createState() => _SSEDisplayState();
}
class _SSEDisplayState extends State<SSEDisplay> {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final fontSizeMedium = theme.textTheme.bodyMedium?.fontSize;
final isDark = theme.brightness == Brightness.dark;
List<dynamic> sse;
try {
sse = jsonDecode(widget.sseOutput);
} catch (e) {
if (sseOutput == null || sseOutput!.isEmpty) {
return Text(
'Invalid SSE output',
'No content',
style: kCodeStyle.copyWith(
fontSize: fontSizeMedium,
color: isDark ? kColorDarkDanger : kColorLightDanger,
@@ -31,7 +26,7 @@ class _SSEDisplayState extends State<SSEDisplay> {
return ListView(
padding: kP1,
children: sse.reversed.where((e) => e != '').map<Widget>((chunk) {
children: sseOutput!.reversed.where((e) => e != '').map<Widget>((chunk) {
Map<String, dynamic>? parsedJson;
try {
parsedJson = jsonDecode(chunk);