Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TimeRange context TypeScript type vs docs inconsistencies #1479

Open
hellosmithy opened this issue Dec 19, 2024 · 3 comments
Open

TimeRange context TypeScript type vs docs inconsistencies #1479

hellosmithy opened this issue Dec 19, 2024 · 3 comments

Comments

@hellosmithy
Copy link

hellosmithy commented Dec 19, 2024

There appear to be a couple of inconsistencies between the published TypeScript types and the docs/json schemas for the fdc3.timeRange context.

Use of Date vs string types

export interface TimeRange {
/**
* The end time of the range, encoded according to [ISO
* 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator.
*/
endTime?: Date;
/**
* The start time of the range, encoded according to [ISO
* 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator.
*/
startTime?: Date;

The current TypeScript type for fdc3.timeRange specifies Date types for both startTime and endTime. Which appears to conflict with the TimeRange docs and the json schema file which both suggest they should be string types encoded as ISO 8601-1:2019:

Ranges corresponding to dates (e.g. 2022-05-12 to 2022-05-19) should be specified using times as this prevents issues with timezone conversions and inclusive/exclusive date ranges.

String fields representing times are encoded according to ISO 8601-1:2019.

A timezone indicator should be specified, e.g. "2022-05-12T15:18:03Z" or "2022-05-12T16:18:03+01:00"
Times MAY be specified with millisecond precision, e.g. "2022-05-12T15:18:03.349Z"

This is also mentioned in the Context Overview

Times
Fields representing a point in time SHOULD be string encoded according to ISO 8601-1:2019 with a timezone indicator included, e.g.:

Dates
Fields representing a point in time SHOULD be string encoded using the YYYY-MM-DD date format from ISO 8601-1:2019.

Optional startTime and endTime

An additional difference is that the type specifies both startTime and endTime as optional values whereas the docs and json schema specify that:

** One of startTime or endTime MUST be specified.

The generated type might be better represented as a discriminated union type to capture this:

export type TimeRange = {
    type:       "fdc3.timeRange";
    id?:        { [key: string]: any };
    name?:      string;
    [property: string]: any;
} & ({
    startTime: string;
    endTime: string;
} | {
    startTime: string;
} | {
    endTime: string;
})
@hellosmithy hellosmithy changed the title TimeRange context type vs docs inconsistencies TimeRange context TypeScript type vs docs inconsistencies Dec 19, 2024
@kriswest
Copy link
Contributor

Hi @hellosmithy, encoding of contexts in JSON and representation in other languages differs - but all other language representations need to be able to convert to and from JSON as the exchange format. We don't say that clearly in the Context overview and should probably clarify.

I.e. where we say:

Times
Fields representing a point in time SHOULD be string encoded according to ISO 8601-1:2019 with a timezone indicator included, e.g.:

We should probably be saying "... SHOULD be string encoded in JSON according to ..."

The JavaScript Date object will stringify to an ISO 8601 encoding, so the Typescript encoding will produce a valid JSON encoding when stringified. However, the example in the TimeRange 2.0 and 2.1 docs pages confuse things by giving an example with the dates initialized as strings - thank you for pointing that out! In the 2.2 version these are JSON drawn from the schema: https://fdc3.finos.org/docs/next/context/ref/TimeRange. We do mention date fields and parsing in Javascript via the Date type in the context overview (https://fdc3.finos.org/docs/context/spec#times) but again are not clear on using Date objects in JavaScript/Typescript.

The TypeScript types in ContextTypes.ts are generated via Quicktype from the JSON Schemas and as we list the date fields as "type": "string" with "format": "date-time" QuickType will generate a fields with the Date type and a Convert function that parses JSON into that format. You'll see the same in the Valuation type. They've been encoded this way since the first Contexts were introduced with Date fields in FDC3 2.0.

Quicktype is also whats behind the particular format of the timerange object. Unfortunately, Quicktypes combines similar objects within a schema, generating a type that could represent any of them, but may be less expressive than the schema itself. Where we've got the following in the schema:

 "anyOf": [
    {
      "required": [
        "startTime",
        "endTime"
      ]
    },
    {
      "required": [
        "startTime"
      ]
    },
    {
      "required": [
        "endTime"
      ]
    }
  ],

That does provide enough information to produce the discriminated union you propose - although we might have been better to use oneOf than anyOf (I may pop a PR in for that change - it won't affect the generated typescript unfortunately). However, QuickType's Typescript geneartor doesn't know how to do that. There are numerous places (particularly in the FDC3 for Web Schemas) where we would produce better types if QuickType was able to produce Object unions types in TypeScript (it can do unions of values, but not objects it seems).

Hence, to adopt that, we'd need to move to manually maintained typescript types for context, which sit well with our long-term goal of opening up the context part of the Standard to additions outside of the (API) version cycle, as we'd planned to focus only on JSON schema submissions and make auto-generated types available.

I hope this provides an explanation and background for what you've highlighted, if not a solution. I think based on your comment that we should:

  • Add some additional notes to the field type conventions of the context Part of the FDC3 Standard on TypeScript/JavaScript and other language encoding of context (tagging @bingenito & @kemerava to think about .NET and other languages),
  • Label examples on context docs pages as examples of the JSON encoding
  • Tweak the timeRange schema to use oneOf
  • Perhaps raise an issue within the QuickType project regarding generating unions or fiutre out a PR to add support - I've managed to get at least one PR merged into QuickType in the past.

Would that help - or do you think we should go further? Let me know and I can add this to the SWG meeting agenda in January.

@hellosmithy
Copy link
Author

hellosmithy commented Dec 20, 2024

@kriswest thanks for the detailed reply.

We should probably be saying "... SHOULD be string encoded in JSON according to ..."

The JavaScript Date object will stringify to an ISO 8601 encoding, so the Typescript encoding will produce a valid JSON encoding when stringified.

I'm still a little unclear on the role of the json schemas in that case. Currently they specify strings for the startTime and endTime.

"startTime": {
"type": "string",
"format": "date-time",
"title": "Start Time",
"description": "The start time of the range, encoded according to [ISO 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator."
},
"endTime": {
"type": "string",
"format": "date-time",
"title": "End Time",
"description": "The end time of the range, encoded according to [ISO 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator."
}

Are you saying the json schema types don't represent the input / output type but rather the serialized "transport" type? If so I guess they would be more targeted to those writing FDC3 platforms rather than consumers.

Do other languages also send equivalent Date types and are these converted to JavaScript Dates if for example a .NET application sent a context that was then received by a web app? If so is this expected to be handled by the platforms?

@kriswest
Copy link
Contributor

I'm still a little unclear on the role of the json schemas in that case. Currently, they specify strings for the startTime and endTime.

They do, there's no Date type in JSON to use, so dates are always string encoded. This passage from the introduction to the Context Overview may help:

FDC3 Context Data defines a standard for passing common identifiers and data, encoded in JSON, between apps to create a seamless workflow. FDC3 Context Data is not a symbology solution and is not specifically focused on modeling financial objects. The focus is on providing a standard JSON payload structure that can be used to establish a lowest common denominator for interoperability.

https://fdc3.finos.org/docs/next/context/spec

Hence, contexts are defined in JSON, which we govern with JSON Schema. A specific FDC3 API binding for a language can represent Context in its own form (e.g. TypeScript Context, .NET Context), as long as they are able to serialize/stringify that form to the required JSON format.

This can then be transmitted via various means and parsed at the receiving end into another language-specific representation. In the case of TypeScript types that we publish from the ContextTypes.ts file, JSON.stringify(context) will produce valid JSON (converting date to its ISO string form), while const timeRange = Convert.toTimeRange(json); will parse the JSON into the generated TimeRange type:

export interface TimeRange {
/**
* The end time of the range, encoded according to [ISO
* 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator.
*/
endTime?: Date;
/**
* The start time of the range, encoded according to [ISO
* 8601-1:2019](https://www.iso.org/standard/70907.html) with a timezone indicator.
*/
startTime?: Date;
type: "fdc3.timeRange";
id?: { [key: string]: any };
name?: string;
[property: string]: any;
}

Are you saying the json schema types don't represent the input / output type but rather the serialized "transport" type? If so I guess they would be more targeted to those writing FDC3 platforms rather than consumers.

Yes, although I would say that the Context Part of the FDC3 Standard is focused on that "transport" type, while specific API bindings (i.e. TypeScript, .NET) provide the object types to represent context in that language. There would be nothing stopping them using a string containing the JSON as their representation - although it would not be very easy to work with.

Also, please note that the description fields from the Schema are automatically imported as comments on the types, which is why the TypeScript file's comments on startTime and endTime talk about the string encoding. We could refine that description to cause less confusion!

Do other languages also send equivalent Date types and are these converted to JavaScript Dates if for example a .NET application sent a context that was then received by a web app? If so is this expected to be handled by the platforms?

Each language binding works with its own type representing context, which it needs to be able to convert to JSON (rather than javascript) to exchange with other languages. However, that is an implementation detail of the platform - as long as each language interface sends/receives context as defined in its standardized binding it is upto the platform how they handle conversions.

Does that answer your questions? If so, what could we be improving in the Standards docs to make this clearer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants