nebula_api_studio 0.1.1 copy "nebula_api_studio: ^0.1.1" to clipboard
nebula_api_studio: ^0.1.1 copied to clipboard

A professional Dart/Flutter package combining a Compiler + Runtime SDK. Convert OpenAPI 3.x / Swagger 2.0 specs into fully type-safe Dart SDKs with smart caching, retry policies, a plugin system, offl [...]

🌌 Nebula API Studio #

A complete Dart/Flutter toolkit for consuming REST APIs β€” from OpenAPI/Swagger spec to production-ready client code, with a powerful runtime layer.

Dart SDK Flutter License: MIT pub.dev


Table of Contents #


Overview #

Nebula API Studio is a monolithic Dart package that covers the entire API lifecycle:

Layer What it does
Compiler Parses OpenAPI 3.x / Swagger 2.0 specs β†’ builds an AST β†’ optimizes β†’ emits null-safe Dart code
Runtime NebulaClient with plugin chain, caching, retry, offline queue and a typed Result<T> monad
CLI nebula generate, nebula watch, nebula init, nebula doctor commands

Features #

Compiler #

  • βœ… OpenAPI 3.0 / 3.1 parser
  • βœ… Swagger 2.0 parser
  • βœ… AST-based intermediate representation
  • βœ… Name normalizer (snake_case β†’ PascalCase / camelCase, reserved-keyword escaping)
  • βœ… Null-safety inferrer (required fields β†’ non-nullable, optional β†’ nullable)
  • βœ… Schema deduplicator (removes exact duplicates, renames structural conflicts)
  • βœ… Code emitter (models, enums, services)
  • βœ… Pluggable parser interface for custom spec formats

Runtime #

  • βœ… NebulaClient β€” single entry point for all HTTP calls
  • βœ… Result<T> monad β€” no more uncaught exceptions
  • βœ… Typed ApiError with status code, machine-readable code and details map
  • βœ… HttpAdapter interface β€” swap real HTTP for mocks in tests
  • βœ… Plugin chain β€” AuthPlugin, LoggingPlugin, AnalyticsPlugin + custom
  • βœ… MemoryCache with TTL and LRU eviction
  • βœ… CachePolicy β€” configurable per-method caching
  • βœ… InvalidationGraph β€” tag-based cascading cache invalidation
  • βœ… RetryPolicy + ExponentialBackoff (with optional jitter)
  • βœ… RetryEngine β€” transparent retry orchestration
  • βœ… Offline RequestQueue + SyncEngine for mobile resilience

CLI #

  • βœ… nebula generate β€” one-shot code generation
  • βœ… nebula watch β€” incremental regeneration on file change
  • βœ… nebula init β€” scaffold a new project with nebula.config.json
  • βœ… nebula doctor β€” environment health check
  • βœ… ConfigLoader β€” JSON config with CLI overrides

Architecture #

nebula_api_studio/
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ nebula_api_studio.dart        ← Public API barrel
β”‚   β”œβ”€β”€ cli/
β”‚   β”‚   β”œβ”€β”€ commands/
β”‚   β”‚   β”‚   β”œβ”€β”€ generate_command.dart
β”‚   β”‚   β”‚   β”œβ”€β”€ watch_command.dart
β”‚   β”‚   β”‚   β”œβ”€β”€ init_command.dart
β”‚   β”‚   β”‚   └── doctor_command.dart
β”‚   β”‚   β”œβ”€β”€ config_loader.dart
β”‚   β”‚   └── watcher.dart
β”‚   └── src/
β”‚       β”œβ”€β”€ compiler/
β”‚       β”‚   β”œβ”€β”€ ast/                  ← ApiAst, ApiEndpoint, ApiModel, ApiType
β”‚       β”‚   β”œβ”€β”€ parser/               ← ParserInterface, OpenApiParser, SwaggerParser
β”‚       β”‚   β”œβ”€β”€ optimizer/            ← NameNormalizer, NullSafetyInferrer, SchemaDeduplicator
β”‚       β”‚   β”œβ”€β”€ generator/            ← CodeEmitter, ModelGenerator, EnumGenerator, ServiceGenerator
β”‚       β”‚   └── nebula_compiler.dart  ← Compiler faΓ§ade
β”‚       β”œβ”€β”€ runtime/
β”‚       β”‚   β”œβ”€β”€ core/                 ← Result, ApiError, ApiRequest, ApiResponse
β”‚       β”‚   β”œβ”€β”€ client/               ← NebulaClient, HttpAdapter, DefaultAdapter
β”‚       β”‚   β”œβ”€β”€ cache/                ← CacheProvider, MemoryCache, CachePolicy, InvalidationGraph
β”‚       β”‚   β”œβ”€β”€ retry/                ← RetryPolicy, ExponentialBackoff, RetryEngine
β”‚       β”‚   β”œβ”€β”€ plugins/              ← ApiPlugin, PluginChain, AuthPlugin, LoggingPlugin, AnalyticsPlugin
β”‚       β”‚   └── offline/              ← RequestQueue, SyncEngine
β”‚       └── shared/
β”‚           β”œβ”€β”€ nebula_config.dart
β”‚           └── exceptions.dart
β”œβ”€β”€ bin/
β”‚   └── nebula.dart                   ← CLI entry point
β”œβ”€β”€ example/
β”‚   β”œβ”€β”€ main.dart                     ← Full usage demo
β”‚   β”œβ”€β”€ swagger.yaml                  ← Pet Store OpenAPI spec
β”‚   └── nebula.config.json            ← Example config
└── test/
    β”œβ”€β”€ compiler/                     ← ast_test, parser_test, optimizer_test
    β”œβ”€β”€ runtime/                      ← result_test, client_test, cache_test, retry_plugin_test
    └── cli/                          ← config_loader_test

Installation #

Add to your pubspec.yaml:

dependencies:
  nebula_api_studio: ^1.0.0

Or for CLI usage, activate globally:

dart pub global activate nebula_api_studio

Quick Start #

1 β€” Generate code from a spec #

# Create nebula.config.json in your project root
nebula init

# Edit nebula.config.json to point to your spec
# Then generate
nebula generate

2 β€” Use the runtime client #

import 'package:nebula_api_studio/nebula_api_studio.dart';

final client = NebulaClient(
  adapter: DefaultAdapter(),
  config: NebulaConfig(
    baseUrl: 'https://api.example.com/v1',
    timeout: const Duration(seconds: 30),
    defaultHeaders: {'Accept': 'application/json'},
  ),
  plugins: [
    AuthPlugin(
      tokenProvider: () async => await getAccessToken(),
      headerName: 'Authorization',
      scheme: 'Bearer',
    ),
    LoggingPlugin(logRequests: true, logResponses: true),
  ],
  retryPolicy: RetryPolicy(
    maxAttempts: 3,
    retryOn: {408, 429, 500, 502, 503, 504},
    backoff: ExponentialBackoff(
      initialDelay: const Duration(milliseconds: 200),
      multiplier: 2.0,
      maxDelay: const Duration(seconds: 10),
      jitter: true,
    ),
  ),
  cachePolicy: CachePolicy(
    enabled: true,
    ttl: const Duration(minutes: 5),
    maxEntries: 500,
  ),
);

// Execute a request
final result = await client.execute(
  ApiRequest(method: 'GET', path: '/pets/pet-001'),
);

result.when(
  success: (response) {
    final pet = Pet.fromJson(response.body as Map<String, dynamic>);
    print('Got pet: ${pet.name}');
  },
  failure: (error) {
    print('Error ${error.statusCode}: ${error.message}');
  },
);

// Always close when done
client.close();

3 β€” Result monad chaining #

final names = (await petsService.listPets())
    .map((pets) => pets.map((p) => p.name).toList())
    .getOrElse([]);

print(names); // ['Buddy', 'Rio', 'Nemo']

CLI Usage #

# Initialize a new project
nebula init [--output-dir lib/generated]

# Generate code (uses nebula.config.json in current directory)
nebula generate [--config path/to/nebula.config.json] [--verbose]

# Watch for spec changes and regenerate automatically
nebula watch [--config path/to/nebula.config.json]

# Check environment health
nebula doctor

Runtime Configuration #

final config = NebulaConfig(
  baseUrl: 'https://api.example.com/v1',  // Required
  timeout: const Duration(seconds: 30),    // Default: 30s
  defaultHeaders: {                        // Merged into every request
    'Accept': 'application/json',
    'X-App-Version': '2.0.0',
  },
  connectTimeout: const Duration(seconds: 10),
  receiveTimeout: const Duration(seconds: 30),
);

Plugins #

Plugins intercept the request/response lifecycle. Implement ApiPlugin:

class TimingPlugin implements ApiPlugin {
  final _stopwatches = <String, Stopwatch>{};

  @override
  Future<ApiRequest> beforeRequest(ApiRequest request) async {
    _stopwatches[request.path] = Stopwatch()..start();
    return request;
  }

  @override
  Future<ApiResponse> afterResponse(ApiRequest req, ApiResponse res) async {
    final elapsed = _stopwatches.remove(req.path)?.elapsedMilliseconds;
    print('${req.method} ${req.path} β†’ ${res.statusCode} (${elapsed}ms)');
    return res;
  }

  @override
  Future<ApiError?> onError(ApiRequest req, ApiError error) async => error;
}

Built-in Plugins #

Plugin Purpose
AuthPlugin Adds Bearer / API-key / custom auth headers
LoggingPlugin Structured request/response logging with log-level control
AnalyticsPlugin Fires events on every request for analytics backends

Caching #

// Client-level policy
final client = NebulaClient(
  ...
  cachePolicy: CachePolicy(
    enabled: true,
    ttl: const Duration(minutes: 10),
    maxEntries: 1000,
    cacheableMethods: {'GET', 'HEAD'},
  ),
);

// Tag-based invalidation
final graph = InvalidationGraph();
graph.addDependency(tag: 'pets', invalidates: ['pet-list', 'pet-search']);
// Invalidating 'pets' automatically clears 'pet-list' and 'pet-search'

Retry & Resilience #

final policy = RetryPolicy(
  maxAttempts: 4,
  retryOn: {408, 429, 500, 502, 503, 504},
  backoff: ExponentialBackoff(
    initialDelay: const Duration(milliseconds: 100),
    multiplier: 2.0,
    maxDelay: const Duration(seconds: 30),
    jitter: true,   // Β±25% random jitter to avoid thundering herd
  ),
);

Offline Support #

// The SyncEngine replays queued requests when connectivity is restored
final syncEngine = SyncEngine(
  queue: RequestQueue(),
  client: client,
  onSync: (result) => print('Synced: $result'),
);

// Register connectivity listener
connectivityStream.listen((isOnline) {
  if (isOnline) syncEngine.flush();
});

Code Generation #

nebula.config.json #

{
  "input": "swagger.yaml",
  "output": "lib/generated",
  "packageName": "my_api",
  "options": {
    "nullSafety": true,
    "generateModels": true,
    "generateServices": true,
    "generateEnums": true,
    "useJsonSerializable": true,
    "addCopyWith": true,
    "addEquality": true,
    "addToString": true,
    "dateTimeType": "DateTime",
    "enumSuffix": "Type",
    "serviceSuffix": "Service"
  },
  "runtime": {
    "baseUrl": "https://api.example.com/v1",
    "timeout": 30000,
    "retries": 3,
    "cacheEnabled": true,
    "defaultCacheDuration": 300,
    "offlineEnabled": true
  },
  "plugins": ["auth", "logging", "analytics"]
}

Generated file structure #

lib/generated/
β”œβ”€β”€ models/
β”‚   β”œβ”€β”€ pet.dart
β”‚   β”œβ”€β”€ owner.dart
β”‚   β”œβ”€β”€ order.dart
β”‚   └── address.dart
β”œβ”€β”€ enums/
β”‚   β”œβ”€β”€ pet_status_type.dart
β”‚   β”œβ”€β”€ pet_category_type.dart
β”‚   └── order_status_type.dart
└── services/
    β”œβ”€β”€ pets_service.dart
    β”œβ”€β”€ owners_service.dart
    └── orders_service.dart

Configuration Reference #

Key Type Default Description
input string β€” Path to the OpenAPI/Swagger spec file (required)
output string lib/generated Output directory for generated code
packageName string generated_api Dart package name prefix for generated files
options.nullSafety bool true Enable Dart null-safety annotations
options.generateModels bool true Generate model classes
options.generateServices bool true Generate service classes
options.generateEnums bool true Generate enum types
options.useJsonSerializable bool true Use json_serializable annotations
options.addCopyWith bool true Add copyWith() to models
options.addEquality bool true Add == / hashCode to models
options.enumSuffix string Type Suffix appended to generated enum names
options.serviceSuffix string Service Suffix appended to generated service names
runtime.baseUrl string β€” Base URL injected into generated service constructors
runtime.timeout int 30000 Default request timeout in milliseconds
runtime.retries int 3 Default maximum retry attempts
runtime.cacheEnabled bool true Enable response caching
runtime.defaultCacheDuration int 300 Default cache TTL in seconds
runtime.offlineEnabled bool false Enable offline request queue

Testing #

# Run all tests
dart test

# Run with coverage
dart test --coverage=coverage
dart pub global run coverage:format_coverage \
  --lcov --in=coverage --out=coverage/lcov.info \
  --report-on=lib

# Run specific test file
dart test test/runtime/result_test.dart

# Run tests matching a pattern
dart test --name "RetryEngine"

Contributing #

  1. Fork the repository
  2. Create a feature branch: git checkout -b feat/my-feature
  3. Commit your changes: git commit -m 'feat: add my feature'
  4. Push to the branch: git push origin feat/my-feature
  5. Open a Pull Request

Please run dart analyze and dart test before submitting.


Changelog #

See CHANGELOG.md for the full history.


License #

MIT Β© 2026 Nebula API Studio contributors. See LICENSE.

2
likes
130
points
137
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A professional Dart/Flutter package combining a Compiler + Runtime SDK. Convert OpenAPI 3.x / Swagger 2.0 specs into fully type-safe Dart SDKs with smart caching, retry policies, a plugin system, offline queue, and a powerful CLI with watch mode. Ready for pub.dev.

Topics

#networking #code-generation #openapi #swagger #http

License

MIT (license)

Dependencies

collection, http, meta, path, yaml

More

Packages that depend on nebula_api_studio