kurierjs / kurier

TypeScript framework to create JSON:API compliant APIs
https://kurier.readthedocs.io/en/latest/
MIT License
61 stars 9 forks source link

Add `meta` to operation responses, both at resource-level and document-level #326

Closed joelalejandro closed 1 year ago

joelalejandro commented 1 year ago

Currently, Kurier can parse meta in requests, but it cannot inject meta in an operation response. We need a way to inject meta in resources and documents.

The proposal is to add the meta property at the Resource type and add hook-like functions to OperationProcessor so the executeOperation() method can call them if needed:

Initially we won't support meta on remove operations, because we are not returning any response on transport layers (i.e. HTTP 204 No Content).

Execution of these hooks must take place at the Application level, in the executeOperation method, prior to calling buildOperationResponse.

Implementation example

export default class ArticleProcessor<ResourceT extends Article> extends KnexProcessor<ResourceT> {
  /**
   * Returns a `meta` object at the processor (document) level for any operations.
   */
  async meta(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the resource level for any operations.
   */
  async resourceMeta(resource: Resource): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the processor (document) level, providing the operation
   * to help decide in which cases add a `meta`.
   */
  async metaFor(op: Operation, resourceOrResources: Resource | Resource[]): Meta {
    switch (op.op) {
      case 'get':
        // ...
      break;
      // ...
    }
    // ...
  }

  /**
   * Returns a `meta` object at the processor (document) level for `get` operations.
   */
  async metaForGet(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the processor (document) level for `add` operations.
   */
  async metaForAdd(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the processor (document) level for `update` operations.
   */
  async metaForUpdate(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the processor (document) level for a custom operation called `print`.
   */
  async metaForPrint(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the resource level, providing the operation
   * to help decide in which cases add a `meta`.
   */
  async resourceMetaFor(op: Operation, resource: Resource): Meta {
    switch (op.op) {
      case 'get':
        // ...
      break;
      // ...
    }
    // ...
  }

  /**
   * Returns a `meta` object at the resource level for `get` operations.
   */
  async resourceMetaForGet(resource: Resource): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the resource level for `add` operations.
   */
  async resourceMetaForAdd(resource: Resource): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the resource level for `update` operations.
   */
  async resourceMetaForUpdate(resource: Resource): Meta {
    // ...
  }

  /**
   * Returns a `meta` object at the resource level for a custom operation called `print`.
   */
  async resourceMetaForPrint(resourceOrResources: Resource | Resource[]): Meta {
    // ...
  }
}