Api.fromOpenApi constructor

Api.fromOpenApi(
  1. APIDocument api,
  2. {required String backendName}
)

Implementation

factory Api.fromOpenApi(
  APIDocument api, {
  required String backendName,
}) {
  final endpoints = <Endpoint>[];
  final objects = <SchemaObject>[];
  final parameterObjects = <ParameterObject>[];
  final definedSecuritySchemes = <String>[];

  final securitySchemes = api.components?.securitySchemes;
  if (securitySchemes != null) {
    for (final securitySchemeEntries in securitySchemes.entries) {
      if (securitySchemeEntries.value!.type != APISecuritySchemeType.http) {
        throw Exception(
          // ignore: lines_longer_than_80_chars
          'WARNING: Backbone currently only supports HTTP security schemes. Skipping ${securitySchemeEntries.key}',
        );
      }
      if (securitySchemeEntries.value!.scheme != 'bearer') {
        throw Exception(
          // ignore: lines_longer_than_80_chars
          'WARNING: Backbone currently only supports Bearer tokens. Skipping ${securitySchemeEntries.key}',
        );
      }
      definedSecuritySchemes.add(securitySchemeEntries.key);
    }
  }

  for (final pathEntry in api.paths!.entries) {
    final pathParamers = pathEntry.value!.parameters;
    for (final operationEntry in pathEntry.value!.operations.entries) {
      final operation = operationEntry.value;
      if (operation != null) {
        final operationId = operation.id;
        if (operationId == null) {
          throw Exception(
            'Operation id missing: ${operationEntry.key}: ${pathEntry.key}',
          );
        }

        final operationParameters = operation.parameters;
        final combinedParameters = [...?pathParamers, ...?operationParameters]
            .where((p) => p != null && p.name != null)
            .map(
              (parameter) => Parameter.fromOpenApi(parameter: parameter!),
            )
            .toList();
        String? paramsType;
        if (combinedParameters.isNotEmpty) {
          paramsType = '${operationId}Parameters';
          final prunedParameters = combinedParameters.fold<List<Parameter>>(
            <Parameter>[],
            (acc, element) {
              if (acc.any((curr) => curr.name == element.name)) {
                return acc;
              } else {
                return [...acc, element];
              }
            },
          );

          parameterObjects.add(
            ParameterObject(
              name: paramsType,
              parameters: prunedParameters,
            ),
          );
        }

        final successfulResponse = operation.responses!['200'];

        if (successfulResponse == null) {
          throw Exception('No 200 response found for ${operationEntry.key}');
        }
        var responseName = successfulResponse.referenceURI?.pathSegments[2];

        final responseSchema =
            successfulResponse.content?['application/json']?.schema;
        if (responseSchema == null) {
          responseName = 'Response';
        }
        if (responseSchema != null) {
          objects.add(
            SchemaObject.fromOpenApi(
              object: responseSchema,
              name: responseName ?? '${operationId}Response',
            ),
          );
        }

        String? requestName;
        final requestSchema =
            operation.requestBody?.content?['application/json']?.schema;

        if (requestSchema != null) {
          requestName = requestSchema.referenceURI?.pathSegments[2] ??
              '${operationId}Request';

          objects.add(
            SchemaObject.fromOpenApi(
              object: requestSchema,
              name: requestName,
            ),
          );
        }

        final securitySchemes = operation.security;

        if (securitySchemes != null) {
          for (final securityScheme in securitySchemes) {
            for (final requirement in securityScheme!.requirements.entries) {
              if (!definedSecuritySchemes.contains(requirement.key)) {
                throw Exception(
                  'Unknown security scheme: ${requirement.key}',
                );
              }
            }
          }
        }

        endpoints.add(
          Endpoint(
            name: operationId,
            path: pathEntry.key.replaceAll('{', '<').replaceAll('}', '>'),
            method: operationEntry.key,
            requestType: requestName,
            paramsType: paramsType,
            responseType: responseName ?? '${operationId}Response',
            parameters: combinedParameters,
            requiresAuthentication:
                securitySchemes != null && securitySchemes.isNotEmpty,
          ),
        );
      }
    }
  }

  for (final schemaEntry in api.components!.schemas!.entries) {
    objects.add(
      SchemaObject.fromOpenApi(
        object: schemaEntry.value!,
        name: schemaEntry.key,
      ),
    );
  }

  final prunedObjects = objects.fold<List<SchemaObject>>(
    <SchemaObject>[],
    (acc, element) {
      if (acc.any((curr) => curr.name == element.name)) {
        return acc;
      } else {
        return [...acc, element];
      }
    },
  );

  return Api(
    apiName: api.info!.title!,
    endpoints: endpoints,
    objects: prunedObjects,
    parameters: parameterObjects,
    backendFolder: backendName,
  );
}