Skip to content

feat: Contract types validation #50

Open
@bartelink

Description

@bartelink

In a team environment, where the way event contracts are composed is often a matter of debate, it can be useful to have a way to validate that types that will be mapped to JSON adhere to conventions.

It should be pretty possible to, a la AutoFixture.Idioms use reflection to find all DUs that implement TypeShape.UnionEncoder.IUnionContract, and then walk the type with TypeShape counting anomalies such as

  • using FSharpList without a converter (use array or [] option)
  • using tuples anywhere in a union contract (a converter, e.g. based on a JsonIsomorphism should be permitted, but we definitely don't want random Newtonsoft/STJ representations and/or runtime exceptions)
  • Using DateTime (DateTimeOffset is hands down better)
  • Using Enums (use nullary unions / TypeSafeEnums in preference)
  • using SCDUs without a converter (should probably be using UMX in the data contracts and only using SCDUs where warranted in models)
  • using other unions without tagging the type and/or field with a converter (e.g. UnionConverter) (vs ending up e.g. triggering Newtonsofts built-in encoding)
  • using anything that binds to a name Item* (e.g. unions with single item or tuple bodies)

This would enable a team for write a single unit test saying something like:

let [<Fact>] ``All contract types use simple tagged types`` () =
    let checker = FsCodec.NewtonsoftJson.TypeChecker(allowMaps=true) // or any other exceptions to the search
    let anoms =
        TypesImplementing<TypeShape.UnionEncoder.IUnionContract>(typeof<Domain.SampleType>.Assembly)
        |> Seq.collect checker.EnumViolations
        |> List.ofSeq
    test <@ [] = anoms @>

Reasons to have this in FsCodec vs anywhere else

  1. it's already using TypeShape
  2. we can port it to do the same thing for SystemTextJson

Yes, one could build a Roslyn Analyzer and/or Rider or Ionide checks too!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions