Skip to main content

spring_boot_starter_feign 0.6.0 copy "spring_boot_starter_feign: ^0.6.0" to clipboard
spring_boot_starter_feign: ^0.6.0 copied to clipboard

Feign clients for spring_boot_dart: annotate an interface with @FeignClient and @GetMapping, inject it as a bean; JSON via ObjectMapper, interceptors, retries, fallbacks.

example/example.dart

// A declarative HTTP client in a Spring Boot application: describe the API,
// the generator writes its implementation and picks the starter up
// (example.spring.dart, from `dart run build_runner build`). JSON goes
// through the ObjectMapper, error statuses become FeignExceptions.
//
//   dart run example/example.dart

import 'dart:async';
import 'dart:convert';
import 'dart:io' as io;

import 'package:spring_boot_starter_feign/spring_boot_starter_feign.dart';

import 'example.spring.dart';

@FeignClient('catalog', url: r'${catalog.url}')
abstract interface class CatalogClient {
  @GetMapping('/books/{isbn}')
  Future<Book> find(@PathVariable() String isbn);

  @GetMapping('/books')
  Future<List<Book>> search(@RequestParam('q') String query);

  /// Server-sent events (`text/event-stream`): a stream that reconnects by
  /// itself with `Last-Event-ID` and ends when the server answers 204.
  @GetMapping('/stock/events')
  EventStream<StockChange> stock();
}

@Introspected()
class Book {
  const Book({required this.isbn, required this.title});
  final String isbn;
  final String title;
}

@Introspected()
class StockChange {
  const StockChange({required this.isbn, required this.copies});
  final String isbn;
  final int copies;
}

@Service()
class Shop {
  Shop(this.catalog);
  final CatalogClient catalog;

  /// The title, or `null` when the catalog answers 404.
  Future<String?> title(String isbn) async {
    try {
      return (await catalog.find(isbn)).title;
    } on FeignNotFound {
      return null;
    }
  }
}

/// Reads from the catalog once the application has started and logs what
/// it got; `@Log` gives it the `log` getter.
@Component()
@Log(topic: 'example')
class ShopTour implements CommandLineRunner {
  ShopTour(this.shop, this.catalog);

  final Shop shop;
  final CatalogClient catalog;

  @override
  Future<void> run(List<String> args) async {
    final dune = await shop.title('978-0');
    final missing = await shop.title('404');
    final isbns = [for (final book in await catalog.search('du')) book.isbn];
    log
      ..info('title: $dune') // title: Dune
      ..info('title: $missing') // title: null
      ..info('search: $isbns'); // search: [978-0]
    await for (final change in catalog.stock()) {
      // 978-0: 4 left, then 978-1: 0 left
      log.info('${change.isbn}: ${change.copies} left');
    }
  }
}

@SpringBootApplication()
Future<void> main(List<String> args) async {
  final server = await _catalogServer();
  final context = await springApplication.runAsync(
    args,
    properties: {'catalog.url': 'http://127.0.0.1:${server.port}'},
  );

  await context.closeAsync();
  await server.close(force: true);
}

/// A local server standing in for the real catalog.
Future<io.HttpServer> _catalogServer() async {
  final server = await io.HttpServer.bind(io.InternetAddress.loopbackIPv4, 0);
  var streamed = false;
  server.listen((request) async {
    final response = request.response;
    void json(Object body) => response
      ..headers.contentType = io.ContentType.json
      ..write(jsonEncode(body));
    switch (request.uri.path) {
      case '/books/978-0':
        json({'isbn': '978-0', 'title': 'Dune'});
      case '/books':
        json([
          {'isbn': '978-0', 'title': 'Dune'},
        ]);
      case '/stock/events' when !streamed:
        streamed = true;
        response
          ..headers.contentType = io.ContentType('text', 'event-stream')
          ..write('id: 1\ndata: {"isbn":"978-0","copies":4}\n\n')
          ..write('id: 2\ndata: {"isbn":"978-1","copies":0}\n\n');
      case '/stock/events':
        response.statusCode = io.HttpStatus.noContent; // no more events
      default:
        response.statusCode = io.HttpStatus.notFound;
    }
    await response.close();
  });
  return server;
}
0
likes
160
points
608
downloads

Documentation

API reference

Publisher

verified publisherfarum-azula.org

Weekly Downloads

Feign clients for spring_boot_dart: annotate an interface with @FeignClient and @GetMapping, inject it as a bean; JSON via ObjectMapper, interceptors, retries, fallbacks.

Repository (GitHub)
View/report issues

Topics

#http #rest #spring

License

Apache-2.0 (license)

Dependencies

spring_boot_dart, spring_boot_starter_logging, spring_web_dart

More

Packages that depend on spring_boot_starter_feign