Skip to content

Commit

Permalink
Remote sсhemas (#107)
Browse files Browse the repository at this point in the history
  • Loading branch information
StarProxima authored Oct 14, 2023
1 parent 70890cb commit 8c7d466
Show file tree
Hide file tree
Showing 9 changed files with 256 additions and 80 deletions.
10 changes: 8 additions & 2 deletions swagger_parser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
## 1.10.0
- Support for generating schemas by url (see [example](https://github.com/Carapacik/swagger_parser/blob/main/swagger_parser/example/swagger_parser.yaml))
- Add new config parameter `schema_url`
- Add new config parameter `schema_from_url_to_file`
- Add new config parameter `prefer_schema_source`

## 1.9.2
- Fix error with `required` in clients ([#101](https://github.com/Carapacik/swagger_parser/issues/103))

## 1.9.1
- Handling incorrect names for classes, enums and methods.
- Additional name for unnamed models [#98](https://github.com/Carapacik/swagger_parser/issues/98)
- Additional name for unnamed models ([#98](https://github.com/Carapacik/swagger_parser/issues/98))
- Support for `deprecated` annotations for methods

## 1.9.0
Expand All @@ -13,7 +19,7 @@
- Fix error with missing File import ([#101](https://github.com/Carapacik/swagger_parser/issues/101))

## 1.8.0
- Multiple schemas support(see ([example](https://github.com/Carapacik/swagger_parser/blob/main/swagger_parser/example/swagger_parser.yaml)))
- Multiple schemas support (see [example](https://github.com/Carapacik/swagger_parser/blob/main/swagger_parser/example/swagger_parser.yaml))
- Support for specifying nullable types via anyOf
- Edit root client template
- Add new config parameter `root_client_name`
Expand Down
25 changes: 19 additions & 6 deletions swagger_parser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
[![Tests](https://github.com/Carapacik/swagger_parser/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/Carapacik/swagger_parser/actions/workflows/tests.yml)
<a href="https://omega-r.com/"><img src="https://raw.githubusercontent.com/Carapacik/swagger_parser/main/.github/readme/omega_logo.png" width="200" align="right"/></a>

## Dart package that generates REST clients and data classes from OpenApi definition file
## Dart package that generates REST clients and data classes from OpenApi definition files or links

## Features

- Supports OpenApi v2, v3.0 and v3.1
- Support JSON and YAML format
- Support for generation by link
- Support for multiple schemes
- Generate REST client files based on Retrofit
- Generate data classes (also on [freezed](https://pub.dev/packages/freezed))
- Support for multiple languages (Dart, Kotlin)
Expand Down Expand Up @@ -46,8 +48,12 @@ An example of YAML is shown below. A default value is specified for each of the

```yaml
swagger_parser:
# Required. Sets the OpenApi schema path directory for api definition.
# You must provide the file path and/or url to the OpenApi schema.
# Sets the OpenApi schema path directory for api definition.
schema_path: schemas/openapi.json
# Sets the url of the OpenApi schema
schema_url: https://petstore.swagger.io/v2/swagger.json
# Required. Sets output directory for generated files (Clients and DTOs).
output_directory: lib/api
Expand All @@ -56,6 +62,10 @@ swagger_parser:
# Current available languages are: dart, kotlin
language: dart
# Optional. If 'schema_path' and 'schema_url' are specified, what will be used.
# Current available options are: path, url.
prefer_schema_source: url
# Optional (dart only). Set 'true' to generate data classes using freezed package.
freezed: false
Expand All @@ -79,6 +89,9 @@ swagger_parser:
# Optional. Set to 'true' to squash all clients in one client.
squash_clients: false
# Optional. Set to 'false' to not write the schema from the url to the schema file.
schema_from_url_to_file: true
# Optional. Set postfix for Client class and file.
client_postfix: Client
Expand Down Expand Up @@ -123,14 +136,14 @@ swagger_parser:
put_in_folder: true
replacement_rules: []
- schema_path: schemas/openapi.json
- schema_url: https://petstore.swagger.io/v2/swagger.json
name: pet_service
client_postfix: DataSource
client_postfix: Service
put_clients_in_folder: true
enums_to_json: true
put_in_folder: true
- schema_path: schemas/openapi.json
- schema_path: schemas/pet_store.json
schema_url: https://petstore.swagger.io/v2/swagger.json
output_directory: lib/api/kotlin
language: kotlin
```
Expand Down
23 changes: 17 additions & 6 deletions swagger_parser/example/swagger_parser.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
swagger_parser:
# Required. Sets the OpenApi schema path directory for api definition.
# You must provide the file path and/or url to the OpenApi schema.

# Sets the OpenApi schema path directory for api definition.
# schema_path: schemas/openapi.json
# Sets the url of the OpenApi schema
# schema_url: https://petstore.swagger.io/v2/swagger.json

# Required. Sets output directory for generated files (Clients and DTOs).
output_directory: lib/api

# Optional. Sets the programming language.
# Current available languages are: dart, kotlin
# Current available languages are: dart, kotlin.
language: dart

# Optional. If 'schema_path' and 'schema_url' are specified, what will be used.
# Current available options are: path, url.
prefer_schema_source: url

# Optional (dart only). Set 'true' to generate data classes using freezed package.
freezed: false

Expand All @@ -32,6 +40,9 @@ swagger_parser:
# Optional. Set to 'true' to squash all clients in one client.
squash_clients: false

# Optional. Set to 'false' to not write the schema from the url to the schema file.
schema_from_url_to_file: true

# Optional. Set postfix for Client class and file.
client_postfix: Client

Expand Down Expand Up @@ -67,13 +78,13 @@ swagger_parser:
put_in_folder: true
replacement_rules: []

- schema_path: schemas/openapi.json
- schema_url: https://petstore.swagger.io/v2/swagger.json
name: pet_service
client_postfix: DataSource
client_postfix: Service
put_clients_in_folder: true
enums_to_json: true
put_in_folder: true

- schema_path: schemas/openapi.json
- schema_path: schemas/pet_store.json
schema_url: https://petstore.swagger.io/v2/swagger.json
output_directory: lib/api/kotlin
language: kotlin
110 changes: 79 additions & 31 deletions swagger_parser/lib/src/config/yaml_config.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import 'package:args/args.dart';
import 'package:collection/collection.dart';
import 'package:yaml/yaml.dart';

import '../generator/models/prefer_schema_source.dart';
import '../generator/models/programming_language.dart';
import '../generator/models/replacement_rule.dart';
import '../utils/file_utils.dart';
Expand All @@ -17,9 +19,12 @@ import 'config_exception.dart';
final class YamlConfig {
/// Applies parameters directly from constructor
const YamlConfig({
required this.schemaPath,
required this.outputDirectory,
required this.name,
required this.outputDirectory,
this.schemaPath,
this.schemaUrl,
this.schemaFromUrlToFile,
this.preferSchemaSource,
this.language,
this.freezed,
this.rootClient,
Expand Down Expand Up @@ -48,9 +53,19 @@ final class YamlConfig {
schemaPath = '';
}

if (schemaPath == null) {
final schemaUrl = yamlConfig['schema_url']?.toString();
if (schemaUrl != null) {
final uri = Uri.tryParse(schemaUrl);
if (uri == null) {
throw const ConfigException(
"Config parameter 'schema_url' must be valid URL.",
);
}
}

if (schemaPath == null && schemaUrl == null) {
throw const ConfigException(
"Config parameter 'schema_path' is required.",
"Config parameters 'schema_path' or 'schema_url' are required.",
);
}

Expand All @@ -73,13 +88,48 @@ final class YamlConfig {
outputDirectory = rootConfig.outputDirectory;
}

final rawName = yamlConfig['name'];
if (rawName is! String?) {
throw const ConfigException(
"Config parameter 'name' must be String.",
);
}

final name = rawName == null || rawName.isEmpty
? (schemaPath ?? schemaUrl)!
.split('/')
.lastOrNull
?.split('.')
.firstOrNull ??
'unknown'
: rawName;

final schemaFromUrlToFile = yamlConfig['schema_from_url_to_file'];
if (schemaFromUrlToFile is! bool?) {
throw const ConfigException(
"Config parameter 'schema_from_url_to_file' must be bool.",
);
}

PreferSchemaSource? preferSchemaSource;
final rawPreferSchemeSource =
yamlConfig['prefer_schema_source']?.toString();
if (rawPreferSchemeSource != null) {
preferSchemaSource = PreferSchemaSource.fromString(rawPreferSchemeSource);
if (preferSchemaSource == null) {
throw ConfigException(
"'prefer_schema_source' field must be contained in ${PreferSchemaSource.values.map((e) => e.name)}.",
);
}
}

ProgrammingLanguage? language;
final rawLanguage = yamlConfig['language']?.toString();
if (rawLanguage != null) {
language = ProgrammingLanguage.fromString(rawLanguage);
if (language == null) {
throw ConfigException(
"'language' field must be contained in ${ProgrammingLanguage.values}.",
"'language' field must be contained in ${ProgrammingLanguage.values.map((e) => e.name)}.",
);
}
}
Expand Down Expand Up @@ -117,6 +167,13 @@ final class YamlConfig {
);
}

final putInFolder = yamlConfig['put_in_folder'];
if (putInFolder is! bool?) {
throw const ConfigException(
"Config parameter 'put_in_folder' must be bool.",
);
}

final squashClients = yamlConfig['squash_clients'];
if (squashClients is! bool?) {
throw const ConfigException(
Expand Down Expand Up @@ -180,37 +237,23 @@ final class YamlConfig {
}
}

final putInFolder = yamlConfig['put_in_folder'];
if (putInFolder is! bool?) {
throw const ConfigException(
"Config parameter 'put_in_folder' must be bool.",
);
}

final rawName = yamlConfig['name'];
if (rawName is! String?) {
throw const ConfigException(
"Config parameter 'name' must be String.",
);
}

final name = rawName == null || rawName.isEmpty
? schemaPath.split('/').last.split('.').first
: rawName;

return YamlConfig(
name: name,
schemaPath: schemaPath,
outputDirectory: outputDirectory,
name: name,
schemaUrl: schemaUrl,
schemaFromUrlToFile:
schemaFromUrlToFile ?? rootConfig?.schemaFromUrlToFile,
preferSchemaSource: preferSchemaSource ?? rootConfig?.preferSchemaSource,
language: language ?? rootConfig?.language,
freezed: freezed ?? rootConfig?.freezed,
rootClient: rootClient ?? rootConfig?.rootClient,
rootClientName: rootClientName ?? rootConfig?.rootClientName,
clientPostfix: clientPostfix ?? rootConfig?.clientPostfix,
putInFolder: putInFolder ?? rootConfig?.putInFolder,
putClientsInFolder: putClientsInFolder ?? rootConfig?.putClientsInFolder,
squashClients: squashClients ?? rootConfig?.squashClients,
pathMethodName: pathMethodName ?? rootConfig?.pathMethodName,
putInFolder: putInFolder ?? rootConfig?.putInFolder,
enumsToJson: enumsToJson ?? rootConfig?.enumsToJson,
enumsPrefix: enumsPrefix ?? rootConfig?.enumsPrefix,
markFilesAsGenerated:
Expand Down Expand Up @@ -249,17 +292,19 @@ final class YamlConfig {
final configs = <YamlConfig>[];

final schemaPath = yamlMap['schema_path'] as String?;
final schemaUrl = yamlMap['schema_url'] as String?;
final schemas = yamlMap['schemas'] as YamlList?;

if (schemas == null && schemaPath == null) {
if (schemas == null && schemaUrl == null && schemaPath == null) {
throw const ConfigException(
"Config parameter 'schema_path' or 'schemas' is required.",
"Config parameter 'schema_path', 'schema_url' or 'schemas' is required.",
);
}

if (schemas != null && schemaPath != null) {
if (schemas != null && schemaPath != null ||
schemas != null && schemaUrl != null) {
throw const ConfigException(
"Config parameter 'schema_path' and 'schemas' can't be used together.",
"Config parameter 'schema_path' or 'schema_url' can't be used with 'schemas'.",
);
}

Expand Down Expand Up @@ -290,16 +335,19 @@ final class YamlConfig {
}

final String name;
final String schemaPath;
final String outputDirectory;
final String? schemaPath;
final String? schemaUrl;
final bool? schemaFromUrlToFile;
final PreferSchemaSource? preferSchemaSource;
final ProgrammingLanguage? language;
final bool? freezed;
final String? clientPostfix;
final bool? rootClient;
final String? rootClientName;
final bool? putClientsInFolder;
final bool? squashClients;
final bool? pathMethodName;
final bool? putClientsInFolder;
final bool? putInFolder;
final bool? enumsToJson;
final bool? enumsPrefix;
Expand Down
Loading

0 comments on commit 8c7d466

Please sign in to comment.