Skip to content

Implement API data custom formatters using tagged template literals

Mateusz Tyszczak requested to merge tm-implement-formatters into develop

Assumptions

@WaxFormattable() decorator specifies a custom formatter class method as a "formatter method" that matches objects with a given property name and transforms them. The property name can be specified in the decorator arguments as a string, as a property option or it defaults to the method name as the property name to match. You can avoid problems like matching "get" or "constructor" properties.

Additionally, the new formatters are designed using reflect-metadata library, so if you have a method in the formatter class that does not have the mentioned decorator, then it will not be taken into account when formatting properties.

Options for the main formatter instance are passed to your custom formatter functions along the source and target objects, so you can also adapt your code to previously defined options.

Note: You should not modify source and target values passed to the formatter functions. The target object will be formatted properly based on the formatter functions return value

Our library has the default set of formatters, which can be disabled when creating a new instance of the WaxFormatter class with the createDefaultFormatteres option disabled.

Formatters can perform advanced nested replacements. In such case, you can provide the entire transaction for the formatter and it will iterate over all the values replacing the requested properties.

The new interface provides two functions in the formatters:

  • waxify - our "stringify" version that outputs formatted Wax values always in the string data type
  • format - a function that formats the input data of any type and returns the formatted output data in the proper way specified by the user

Examples

Use hive chain interface with default formatters to output data in the formatted string way

import { createHiveChain } from '@hiveio/wax';
const chain = await createHiveChain();

const apiTransaction = {
  /* ... Transaction data from the API ... */
};

console.info(chain.waxify`#${apiTransaction}`); // Prints the transaction id

Use hive chain interface with default formatters to output data in the formatted object way

import { createHiveChain } from '@hiveio/wax';
const chain = await createHiveChain();

const apiOperation = {
  type: "transfer_operation",
  value: {
    from: "gtg",
    to: "initminer",
    amount: {
      amount: "300000",
      precision: 3,
      nai: "@@000000021"
    },
    memo: "ransom"
  }
};

console.info(chain.formatter.format(apiOperation)); // Prints the operation with formatted asset values

Output:

{
  type: "transfer_operation",
  value: {
    from: "gtg",
    to: "initminer",
    amount: "300.000 HIVE", // !! Amount formatted
    memo: "ransom"
  }
}

Use hive chain interface and custom formatters to output data in the specified string format

import { createHiveChain, WaxFormattable } from '@hiveio/wax';
const chain = await createHiveChain();

class MyFormatters {
  helperFunction(value) { // This will not be used a formatter function
    return value.toString();
  }

  @WaxFormattable() // This will be used a formatter function
  myCustomProp({ source }) {
    return this.helperFunction(source.myCustomProp);
  }
}

const formatter = chain.formatter.extend(MyFormatters);

const data = {
  myCustomProp: 12542
};

console.info(formatter.waxify`${data}`); // Prints "12542"

Use hive chain interface and custom formatters with match by value option to output data in the specified format

import { createHiveChain, WaxFormattable } from '@hiveio/wax';
const chain = await createHiveChain();

class OperationsFormatter {
  @WaxFormattable({ matchProperty: "type", matchValue: "transfer_operation" })
  public transferOperationFormatter({ source }): string {
    return `${source.value.from} transferred ${chain.waxify`${source.value.amount!}`} to ${source.value.to}`;
  }

  @WaxFormattable({ matchProperty: "type", matchValue: "vote_operation" })
  public voteOperationFormatter({ source }): string {
    return `${source.value.voter} voted on @${source.value.author}/${source.value.permlink}`;
  }
}

const formatter = chain.formatter.extend(OperationsFormatter);

const ops = [ {
  type: "transfer_operation",
  value: {
    from: "oneplus7",
    to: "kryptogames",
    amount: {
      amount: "300000",
      precision: 3,
      nai: "@@000000021"
    },
    memo: "Roll under 50 4d434bd943616"
  }
}, {
  type: "vote_operation",
  value: {
    voter: "otom",
    author: "c0ff33a",
    permlink: "ewxhnjbj",
    weight: 2200
  }
} ];

console.log(formatter.format(ops));

Output:

[
  "oneplus7 transferred 300.000 HIVE to kryptogames",
  "otom voted on @c0ff33a/ewxhnjbj"
]
Edited by Mateusz Tyszczak

Merge request reports