# Simplify using external types **Author**: FTL Team **Status**: ==draft== / in-review / accepted / rejected ## Description Provide a means for using external types within the FTL type system. ## Motivation (optional) FTL does not support external types for several reasons: 1. Unclear ownership - if multiple modules import an external type, which modules is the owner? 2. FTL supports a limited set of types. External types can and do use the full set of types provided by each language. 3. It is architecturally cleaner to have separate types for each layer of the system. All that said, this comes with downsides if an external type is required as part of an FTL interface, such as a HTTP ingress point, or a secret containing a data structure from an external library. In this situation, types either have to be manually mirrored in FTL, or `Any` used, losing type safety. Both of these options are also tedious. Finally, the FTL type system isn't currently powerful enough to represent some existing type patterns, specifically sum types. These are fairly commonly used in JSON, for example when a field can either be represented by a string, object or a list of strings or objects. ## Goals - Simplify the use of external types within the FTL type system. - Don't compromise type safety. - Improve ergonomics considerably - Support mapping to/from JSON, including language-specific overrides, eg. `json.Unmarshaler` in Go and `@JsonProperty` in the JVM. __What about other encodings???__ ## Design ?? ## Ideas/options ### Type importer from supported languages, ie. Go and Kotlin Add a command to `ftl` for importing external types into FTL: ``` ftl schema import <language> <path> ``` This would utilise the existing schema extraction code, though it would need to be refactored to not error no external types. **Pros**: type safe **Cons**: no custom JSON, no type mapping ### Type importer from JSON schema To solve the "JSON issue" specifically, create an importer for JSON schema that generates FTL types. The FTL type system would need to be extended to support sum types, and potentially other type mechanisms. **Pros**: solves JSON use **Cons**: doesn't solve for arbitrary external types ### Add a `JSON` type Add a `JSON` type similar to `Any`, but for representing arbitrary JSON. It would include helper methods for encoding/decoding native types to this type. **Pros**: solves JSON use, solves type mapping **Cons**: no type safety ### Type mapper Implement some kind of system for creating type mappers, whereby the FTL type system knows what the underlying structure is, but materialises it in each language as a specific external type. (Hand waving) It might be something like this in Go, with an equivalent in Kotlin: Register a mapper between the external `did.DID` type and the FTL `DID` type. ```go // The FTL type mirroring the external type, possibly using `ftl schema import` or JSON schema import, or something. type DID struct { // ... } // FTL type mapper from web5-go/did.DID to the FTL DID type. // //ftl:extern type MapDID struct {} func (MapDID) Encode(d did.DID) (DID, error) { /* ... */ } func (MapDID) Decode(in DID) (did.DID, error) { /* ... */ } ``` > **Note:** The FTL language runtimes could include helpers for common mappers, such as to/from JSON annotated types, and so on. Once the mapper is registered, FTL will automatically use it whenever it encounters `did.DID`. ``` // Now when we //ftl:ingress ht func GetDID(ctx context.Context) (did.DID, error) { // } ``` We'd still need some mechanism for mapping the external type to FTL. **Pros**: solves mapping arbitrary external types, solves ownership **Cons**: doesn't solve JSON, though could in combo with the JSON schema importer