API and Components
API and Components 📚
Section titled “API and Components 📚”This section details the primary extensions for chaining and manipulating Convertors, along with the concrete Datasource Convertor implementations.
Convertor Extensions
Section titled “Convertor Extensions”The architecture provides various extensions to enable pipeline functionalities for different Convertor types.
Basic Convertor Extensions (Convertor<To, From>)
Section titled “Basic Convertor Extensions (Convertor<To, From>)”| Extension Method | Purpose |
|---|---|
mightExecute | Allows execution with nullable input, returning a nullable output. |
decorate | Wraps the Convertor with a custom decorator function for input/output modification. |
then | Chains another Convertor where the current output (To) becomes the new Convertor’s input. |
thenConvert | Chains a simple function that converts the output (To) to a new type (NewTo). |
interceptWith | Intercepts the input or output using explicit Interceptor objects for side effects. |
intercept | Intercepts the input or output using simple functions for side effects. |
Iterable Convertor Extensions (Convertor<Iterable<To>, From>)
Section titled “Iterable Convertor Extensions (Convertor<Iterable<To>, From>)”| Extension Method | Purpose |
|---|---|
thenEach | Applies a subsequent Convertor to each item in the output iterable. |
thenConvertEach | Applies a subsequent conversion function to each item in the output iterable. |
StreamConvertor Extensions (StreamConvertor<To, From>)
Section titled “StreamConvertor Extensions (StreamConvertor<To, From>)”These extensions operate on the data within the output stream.
| Extension Method | Purpose |
|---|---|
transform | Applies a StreamTransformer to the output stream. |
map | Maps the data within the output stream to a new type. |
thenMap | Applies a basic Convertor to the data within the output stream. |
asyncMap | Asynchronously maps the data within the output stream to a new type. |
AsyncConvertor Extensions (AsyncConvertor<To, From>)
Section titled “AsyncConvertor Extensions (AsyncConvertor<To, From>)”These extensions operate on the result of the Future.
| Extension Method | Purpose |
|---|---|
thenMap | Applies a basic Convertor to the Future’s result (To). |
map | Maps the result of the Future synchronously. |
asyncMap | Maps the result of the Future asynchronously (returns a flattened Future). |
Datasource Convertors
Section titled “Datasource Convertors”Datasource Convertors define the specific logic for fetching and processing data from external sources.
Rest Convertor
Section titled “Rest Convertor”This convertor uses the Dio client for HTTP requests.
- Input:
RestParams(path, method, queryParameters, data, etc.).
class RestParams { final String path; final String method; final Map<String, dynamic>? queryParameters; final Object? data; final FormData? formData; final Options? options; final CancelToken? cancelToken; final ProgressCallback? onSendProgress; final ProgressCallback? onReceiveProgress;}- Executor:
RestJsonExecutor<Result>handles the raw HTTP execution.
class RestJsonExecutor<Result> implements AsyncConvertor<Response<Result>, RestParams> { final Dio dio;
const RestJsonExecutor({required this.dio});
@override Future<Response<Result>> execute(RestParams argument) async { var options = argument.options ?? Options(); options = options.copyWith(method: argument.method); final response = await dio.request<Result>( argument.path, data: argument.data ?? argument.formData, queryParameters: argument.queryParameters, options: options, cancelToken: argument.cancelToken, onReceiveProgress: argument.onReceiveProgress, onSendProgress: argument.onSendProgress, ); return response; }}- Data Conversion:
RestDataExecutor<Data>wraps the executor and applies an internalConvertor<Data, dynamic>to transform the raw JSON response data (response.data!) into a domainDatamodel.
class RestDataExecutor<Data> implements AsyncConvertor<Response<Data>, RestParams> { final RestJsonExecutor _executor; final Convertor<Data, dynamic> _convertor;
const RestDataExecutor({ required RestJsonExecutor executor, required Convertor<Data, Json> convertor, }) : _executor = executor, _convertor = convertor;
@override Future<Response<Data>> execute(RestParams from) async { final response = await _executor.execute(from); if (response.data == null) { throw DioException( requestOptions: response.requestOptions, type: DioExceptionType.badResponse, stackTrace: StackTrace.current, response: response, message: response.statusMessage, ); } return Response( data: _convertor.execute(response.data!), statusCode: response.statusCode, requestOptions: response.requestOptions, ); }}Or we could also chain the convertors together using the extension:
AsyncConvertor<NewTo, From> AsyncConvertor<To, From>.thenMap<NewTo>( Convertor<NewTo, To> convertor)GraphQL Convertor
Section titled “GraphQL Convertor”This convertor uses the Ferry client for GraphQL operations.
- Input:
class ListRequestParams<F, O> { final int? skip; final int? take; final F? filter; final O? sort;}
class SingleRequestParams<F> { final F? filter;}
class UpsertRequestParams<V> { final V vars;}
class DeleteRequestParams<F> { final F? filter;}
class SubscriptionRequestParams<C> { final C? context;}- Request Executor (
GraphQLRequestExecutor): ImplementsStreamConvertor<OperationResponse<Data, Vars>, Params>.- It uses a request-specific Convertor to transform custom
Paramsinto a Ferry-compatibleOperationRequest. - It executes the request via a
GqlClient, which returns aStream<OperationResponse>.
- It uses a request-specific Convertor to transform custom
class GraphQLRequestExecutor<Data, Params, Vars> implements StreamConvertor<OperationResponse<Data, Vars>, Params> { final GqlClient _gqlClient; final Convertor<OperationRequest<Data, Vars>, Params> _convertor;
const GraphQLRequestExecutor({ required GqlClient gqlClient, required Convertor<OperationRequest<Data, Vars>, Params> convertor, }) : _gqlClient = gqlClient, _convertor = convertor;
@override Stream<OperationResponse<Data, Vars>> execute(Params from) { final request = _convertor.execute(from); return _gqlClient.request(request); }}- Stream Convertor (
GraphQLStreamConvertor): ImplementsStreamConvertor<Data, Stream<OperationResponse<Data, Vars>>>.- This component chains onto the Executor to transform the stream of
OperationResponseinto a stream of the actual GQL data (Data). - It handles unwrapping the data and propagating GraphQL or Link errors.
- This component chains onto the Executor to transform the stream of
class GraphQLStreamConvertor<Data, Vars> implements StreamConvertor<Data, Stream<OperationResponse<Data, Vars>>> { const GraphQLStreamConvertor();
@override Stream<Data> execute(Stream<OperationResponse<Data, Vars>> from) { return from.transform( StreamTransformer.fromHandlers( handleData: (data, sink) { if (data.hasErrors || data.data == null) { sink.addError( data.graphqlErrors?.firstOrNull ?? data.linkException ?? Exception(), ); } else { sink.add(data.data!); } }, ), ); }}