Skip to content

The workings of an update to the templates and base implementation of the typescript-axios client code generator

Notifications You must be signed in to change notification settings

rvowles/openapi3-typescript-axios

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

48 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Enhanced Axios Typescript Code generator

Note
Feedback in terms of issues appreciated!

Introduction

This is intended to be submitted back to the OpenAPI Generator crew because there are a number of tickets raised around its:

  • poor serialization and deserialization of data,

  • date formatting

  • support for alternative formats (such as uuids, emails, etc),

  • lack of serialization overrides (if you have a format we don’t support you can add in your own custom serializer for it)

  • honours Javascript style formatting for variable names, properly swapping back and forth between the two (e.g. snake_casesnakeCase, @id_id)

  • incomplete types when multiple return codes exist and support different return objects

  • support oneOf’s and discriminators

  • OpenAPI 5.x brings the Set<> type to the party and it does not work at all as expected. We recommend you use the useEnhancedSerializer mechanism for this otherwise stuff just isn’t going to work.

At the moment it is generating "correct" code, and the serialization works for simple types and is tested with those types. It needs more exhaustive testing around:

  • arrays

  • deep nested objects

  • date and date-times

  • additionalProperty types (i.e. Record types)

Releases

  • 2.1 - swaps to 7.x of the OpenAPI generator. Updates the way that serialization happens for inheritance as well.

it might:

  • being able to understand the full hierarchy of a "type" and determine if any of the types down the tree would cause serialization issues and allow a flag to bypass and just use the returned object as is. This would mean it wouldn’t support classes or serialization overrides.

How to use

Download and build this project. Download the OpenAPI 5.0.0-SNAPSHOT.jar file (see below).

We use an additional property to trigger the extensions so it remains backwards compatible and won’t mess with people’s existing code:

--additional-properties useEnhancedSerializer

This property will give you back a pure AxiosResponse<T> or AxiosError<T> which will in fact not be deserialized. To do that you will need to manually call ObjectSerializer.deserialize(data.data, 'type'). Otherwise it will be the raw json object.

If you wish to have it automatically deserialized, use

--additional-properties useCoalesceReturnTypes

If you wish to use optimized deserialization techniques for primitive data types and their arrays, add no extra options. If however you need to be able to intercept all deserialization, add in

--additional-properties useNonOptimalDeserialization

And then your return types will be all of the possible return types from that method and it will check the status code for you and deserialize into the correct type.

Note
the type of generator is currently typescript-axios-enhanced.
java -cp "openapi-generator-cli-5.0.0-SNAPSHOT.jar:openapi-tsaxios-generator-1.1-SNAPSHOT.jar" org.openapitools.codegen.OpenAPIGenerator generate -i api.yaml -g typescript-axios-enhanced --additional-properties supportsES6 --additional-properties nullSafeAdditionalProps --additional-properties useEnhancedSerializer=true -o api

Getting OpenAPI 5 SNAPSHOT

As we are currently using the 5.0.0-SNAPSHOT because the API changed a bit, getting the snapshot jar is a little more tricky. You need to download the Maven metadata file from here . Once you have done this, you will find references to the current releases in a format similar to below. Find the value reference and that is the jar filename. Then you can grab this from the reference https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator/5.0.0-SNAPSHOT/openapi-generator-maven-plugin-VALUE.jar Where VALUE is the value from the value field.

<snapshotVersion>
<extension>jar</extension>
<value>5.0.0-20200722.171336-430</value>
<updated>20200722171336</updated>
</snapshotVersion>

Example of code

Party for example is created like this:

export class Party {
  /**
  *
  * @type {PartyType}
  * @memberof Party
  */
  public partyType: PartyType;
  /**
  *
  * @type {string}
  * @memberof Party
  */
  public givenName: string;
  /**
  *
  * @type {string}
  * @memberof Party
  */
  public additionalName?: string;
  /**
  *
  * @type {string}
  * @memberof Party
  */
  public familyName: string;
  /**
  *
  * @type {string}
  * @memberof Party
  */
  public telephone?: string;
  /**
  *
  * @type {string}
  * @memberof Party
  */
  public email: string;
  /**
  *
  * @type {Date}
  * @memberof Party
  */
  public birthDate?: Date;

  constructor(init?: Partial<Party>) {
    Object.assign(this, init);
  }
}

The partial is used to allow people to create the class as they have been.

for this is also generates a hidden serializer/deserializer. This is outside because toJson() has semantics in Javascript:

class PartyTypeTransformer {
  static toJson(val: Party): any {
    const data: any = {};
    if (val.partyType) {
      data['partyType'] = ObjectSerializer.serialize(val.partyType, 'PartyType');
    }
    if (val.givenName) {
      data['givenName'] = ObjectSerializer.serialize(val.givenName, 'string');
    }
    if (val.additionalName) {
      data['additionalName'] = ObjectSerializer.serialize(val.additionalName, 'string');
    }
    if (val.familyName) {
      data['familyName'] = ObjectSerializer.serialize(val.familyName, 'string');
    }
    if (val.telephone) {
      data['telephone'] = ObjectSerializer.serialize(val.telephone, 'string');
    }
    if (val.email) {
      data['email'] = ObjectSerializer.serialize(val.email, 'email');
    }
    if (val.birthDate) {
      data['birthDate'] = ObjectSerializer.serialize(val.birthDate, 'date');
    }
    return data;
  }

  // expect this to be a decoded value
  static fromJson(val: any): Party {
    const init = {
      partyType: ObjectSerializer.deserialize(val['partyType'], 'PartyType'),
      givenName: ObjectSerializer.deserialize(val['givenName'], 'string'),
      additionalName: ObjectSerializer.deserialize(val['additionalName'], 'string'),
      familyName: ObjectSerializer.deserialize(val['familyName'], 'string'),
      telephone: ObjectSerializer.deserialize(val['telephone'], 'string'),
      email: ObjectSerializer.deserialize(val['email'], 'email'),
      birthDate: ObjectSerializer.deserialize(val['birthDate'], 'date'),
    };
    return new Party(init);
  }
}

The toJson uses if to determine if there is a value to ensure it does not send the field at all if there is no value. This mechanism is also used for the additionalProperties style capability.

The serializer/deserializer is extendable and generates appropriate code for all types in one serializer.

About

The workings of an update to the templates and base implementation of the typescript-axios client code generator

Resources

Stars

Watchers

Forks

Packages

No packages published