OpenAPITools / OpenAPITools/openapi-generator
[BUG] [Typescript-fetch] client does not map correctly from timestamp to date
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 26.8k
- Forks
- 7.7k
- PR merge metrics
- PR metrics pending
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator (example)?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
I have an openapi file with a server side in Java and a client side in node. Both using the openapi generator.
The server side returns the fields date-time serialized as timestimap in the json, i see that ok, the problem is that in the node client side, using typescript-fetch the dates are not deserialised correclty.
Given the timestamp 1685211548 it returns the date 1970-01-20T12:06:51.548Z
I think that is because they are mapped like this
return {
'type': ShipmentTypeFromJSON(json['type']),
'price': json['price'],
'departureDate': (new Date(json['departureDate'])),
'arrivalDate': (new Date(json['arrivalDate'])),
};
In the Suggest a Fix section i clarify why i think that this is the problem.
For more info the server side is in Java 17 + springboot 3 and the date field is generated like this
import org.springframework.format.annotation.DateTimeFormat;
import java.time.OffsetDateTime;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
private OffsetDateTime departureDate;
and is serialized to the json as unix timestamp
openapi-generator version
6.6.0 Both client and server
OpenAPI declaration file content or url
AvaliableShipmentAirlines:
additionalProperties: false
type: object
required:
- "airlineShipmentOptions"
properties:
airlineShipmentOptions:
type: array
maxItems: 1000
items:
$ref: "#/components/schemas/AirlineShipmentOption"
AirlineShipmentOption:
additionalProperties: false
type: object
required:
- "airlineLogoUrl"
- "airlineName"
- "airlineCode"
- "shipmentOptions"
properties:
airlineLogoUrl:
maxLength: 255
type: string
example: https://www.somedomian.com/airlineLogo.png
airlineName:
maxLength: 40
pattern: '^[A-Za-z0-9]+$'
type: string
example: Emirates
airlineCode:
maxLength: 40
pattern: '^[A-Za-z0-9]+$'
type: string
example: EMX
shipmentOptions:
$ref: "#/components/schemas/ShipmentOptions"
ShipmentOptions:
type: array
maxItems: 1000
items:
$ref: "#/components/schemas/ShipmentOption"
ShipmentOption:
additionalProperties: false
type: object
required:
- "type"
- "price"
- "departureDate"
- "arrivalDate"
properties:
type:
$ref: "#/components/schemas/ShipmentType"
price:
type: number
format: double
description: Price of the shipment
example: 1
maximum: 999
minimum: 0
departureDate:
type: string
format: date-time
description: Departure date of the shipment
arrivalDate:
type: string
format: date-time
description: Arrival date of the shipment
Generation Details
Client side, where the timestaps are not mapped corrreclty
package.json scripts looks like this (other names)
"scripts": {
...
"clean": "rimraf ./next && rimraf .generated/*",
"post-process": "node src/scripts/post-process.js",
"generate-pre": "npm run clean && npx openapi-generator-cli generate --generator-key name1 name2 && npm run post-process",
"build-name1-rest-client": "cd .generated/name1-rest-client && npm install && npm run build",
"generate": "npm run generate-pre && npm run build-name1-rest-client && npm i .generated/name1-rest-client "
},
openapitools.json looks like this (other names)
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "6.6.0",
"storageDir": ".tmp/",
"generators": {
"name1": {
"generatorName": "typescript-fetch",
"output": ".generated/name1-rest-client",
"glob": "node_modules/@scope/name1-openapi/open-api.{yaml,yml}",
"additionalProperties": {
"withInterfaces": true,
"supportsES6": "true",
"npmName": "name1-rest-client",
"stringEnums": true
}
},
"name2": {
"generatorName": "typescript-fetch",
"output": ".generated/name2-rest-client",
"glob": "node_modules/@scope/name2-private-openapi/open-api.{yaml,yml}",
"additionalProperties": {
"withInterfaces": true,
"supportsES6": "true",
"npmName": "name2-rest-client",
"stringEnums": true
}
}
}
}
}
Server side:
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.6.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${open-api.path}</inputSpec>
<enablePostProcessFile>false</enablePostProcessFile>
<library>spring-boot</library>
<generateModels>true</generateModels>
<generatorName>spring</generatorName>
<generateApiDocumentation>true</generateApiDocumentation>
<generateModelDocumentation>true</generateModelDocumentation>
<generateApiTests>true</generateApiTests>
<typeMappings>
<typeMapping>Date=OffsetDateTime</typeMapping>
</typeMappings>
<importMappings>Date=java.time.OffsetDateTime</importMappings>
<configOptions>
<removeOperationIdPrefix>true</removeOperationIdPrefix>
<apiNameSuffix>DTO</apiNameSuffix>
<delegatePattern>true</delegatePattern>
<generateApi>true</generateApi>
<skipOperationExample>false</skipOperationExample>
<java17>true</java17>
<dateLibrary>java17</dateLibrary>
<groupId>com.aGreatName</groupId>
<basePackage>com.aGreatName</basePackage>
<modelPackage>com.aGreatName.model</modelPackage>
<apiPackage>com.aGreatName.api</apiPackage>
<configPackage>com.aGreatName</configPackage>
<configHelp>true</configHelp>
<interfaceOnly>true</interfaceOnly>
<skipDefaultInterface>false</skipDefaultInterface>
<useTags>true</useTags>
</configOptions>
<additionalProperties>
<additionalProperty>modelNameSuffix=DTO</additionalProperty>
<additionalProperty>useSpringBoot3=true</additionalProperty>
</additionalProperties>
</configuration>
</execution>
</executions>
</plugin>
Steps to reproduce
Use date-time in the openapi spec and generate client-side code using typescript fetch, then receive timestamp for that field in the json of the response.
Suggest a fix
Generate the code more like this or use a function that does the check and returns the date.
return {
'type': ShipmentTypeFromJSON(json['type']),
'price': json['price'],
'departureDate': isNaN(json['departureDate']) ? (new Date(json['departureDate'])) : (new Date(1000 * json['departureDate'])),
'arrivalDate': isNaN(json['arrivalDate']) ? (new Date(json['arrivalDate'])) : (new Date(1000 * json['arrivalDate'])),
};
My workaround is this script that i apply to the output folder after generating the code and is working fine for me.
const fs = require('fs');
const path = require('path');
const generatedDir = '.generated';
function applyCustomMapping(directory) {
const files = fs.readdirSync(directory);
files.forEach((file) => {
const filePath = path.join(directory, file);
const fileStat = fs.statSync(filePath);
if (fileStat.isDirectory()) {
applyCustomMapping(filePath);
} else {
const fileContent = fs.readFileSync(filePath, 'utf8');
// Replace "(new Date(json['fieldName']))" with "isNaN(json['fieldName']) ? (new Date(json['fieldName'])) : (new Date(1000 * json['fieldName']))"
const modifiedContent = fileContent.replace(/\(new Date\(json\['(.*?)'\]\)\)/g, "isNaN(json['$1']) ? (new Date(json['$1'])) : (new Date(1000 * json['$1']))");
fs.writeFileSync(filePath, modifiedContent, 'utf8');
}
});
}
applyCustomMapping(generatedDir);
console.log('Custom date mapping applied successfully.');
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the typescript-fetch model deserializer shown in the issue and the openapi-generator-cli generate entry point; the generated files are placed under .generated, with post-processing in src/scripts/post-process.js. Reproduce the 1685211548 date-time response and trace how date-time is mapped. Done means generated clients correctly deserialize the reported timestamp without the workaround.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, typescript
- Domain
- api, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100