Skip to content

Latest commit

 

History

History
79 lines (57 loc) · 4.13 KB

http-client-dev-conventions.md

File metadata and controls

79 lines (57 loc) · 4.13 KB

This document establishes a set of best practices related to development of clients for HTTP microservices using Vostok libraries.

An example of a client that implements these practices is HerculesTimelineClient.

General

  • Always target netstandard2.0 to enable both .NET Framework and .NET Core users to make use of the library.
  • Always make client methods asynchronous.
  • Always make client instances thread-safe.
  • Always create a client interface (even if it will only ever have one implemenation) to enable unit-testing against it.
  • Always incapsulate serialization and deserialization of models in the client code.
  • Consider decorating client methods and models with JetBrains annotations (NotNull, CanBeNull, etc).
  • Consider documenting client methods and models with xml-docs in code.
    • These docs should generally help users understand client's guarantees and behaviour.

Method parameters

  • Always add a timeout parameter of TimeSpan type to client methods.
  • Always add a CancellationToken parameter to client methods.
  • Consider passing all the other parameters to client methods as request/query objects with properties instead of passing them directly as method arguments.
    • This will help to avoid breaking backward compatibility later and keep the interfaces clean.
      public class ReadQuery 
      {
        // Extensible without breaking backward compatibility.
        // Required properties are passed to constructor.
        // Optional properties can just have default values.
      }
      

Method results

  • Consider using result objects with status enums to present a user-friendly mechanism for error handling.
    • A common pattern to build such a result object is to include a status (success/timeout/etc.) and an optional payload (service response in case of success).
    • Users are therefore able to distinguish and handle different error conditions without relying on catching exceptions.
    • Unconditionally accessing the payload of a result object that represents failure should throw an exception.

Method extensions

  • Always create synchronous extensions for all asynchronous methods using .GetAwaiter().GetResult().

ClusterClient

  • Always use ClusterClient library to send HTTP requests.
  • Always use universal transport implementation to perform equally well on every runtime.
  • Always set target service name in client configuration.
  • Consider using ForkingRequestStrategy to tolerate slow replicas.
  • Consider enabling replica budgeting and adaptive throttling to protect from overload.

Configuration

  • Always expose an optional ClusterClientSetup property that can be used to customize internal client instances.
  • Always allow to pass an external IClusterProvider or Func<Uri[]> instance to set service topology.
  • Consider including a default topology source if it suits the majority of client library's users.
  • Consider making settings dynamic (through Func<T>) where applicable.

Logging

  • Always provide an option to pass an external ILog instance.
  • Consider using LogProvider when user-provided log is null.
  • Consider adding log source context with log = log.ForContext<MyClient>(); call.

Tracing

  • Always enable tracing for ClusterClient with vostok.clusterclient.tracing module.
  • Always provide an option to pass an external ITracer instance.
  • Consider using TracerProvider when user-provided tracer is null.