import Serializer from './serializer'; import Model from '../data/model'; import Action, { RenderOptions } from '../runtime/action'; import { RelationshipDescriptor } from '../data/descriptors'; import { RelationshipConfig } from './serializer'; import * as JSONAPI from '../utils/json-api'; export interface Options extends RenderOptions { /** * An array of Models you want to ensure are included in the "included" sideload. Note that the * spec requires "full-linkage" - i.e. any Models you include here must be referenced by a * resource identifier elsewhere in the payload - to maintain full compliance. */ included?: Model[]; /** * Any top level metadata to send with the response. */ meta?: JSONAPI.Meta; /** * Any top level links to send with the response. */ links?: JSONAPI.Links; [key: string]: any; } /** * Used internally to simplify passing arguments required by all functions. */ export interface Context { action: Action; body: any; options: Options; document: JSONAPI.Document; } /** * Renders the payload according to the JSONAPI 1.0 spec, including related * resources, included records, and support for meta and links. * * @package data * @since 0.1.0 */ export default abstract class JSONAPISerializer extends Serializer { /** * The default content type to use for any responses rendered by this serializer. * * @since 0.1.0 */ contentType: string; /** * Take a response body (a model, an array of models, or an Error) and render * it as a JSONAPI compliant document * * @since 0.1.0 */ serialize(body: any, action: Action, options: RenderOptions): Promise; /** * Render the primary payload for a JSONAPI document (either a model or array * of models). * * @since 0.1.0 */ protected renderPrimary(context: Context): Promise; /** * Render the primary data for the document, either a single Model or a * single Error. * * @since 0.1.0 */ protected renderPrimaryObject(context: Context, payload: any): Promise; /** * Render the primary data for the document, either an array of Models or * Errors * * @since 0.1.0 */ protected renderPrimaryArray(context: Context, payload: any): Promise; /** * Render any included records supplied by the options into the top level of * the document * * @since 0.1.0 */ protected renderIncluded(context: Context): Promise; /** * Render top level meta object for a document. Default uses meta supplied in * options call to res.render(). * * @since 0.1.0 */ protected renderMeta(context: Context): void; /** * Render top level links object for a document. Defaults to the links * supplied in options. * * @since 0.1.0 */ protected renderLinks(context: Context): void; /** * Render the version of JSONAPI supported. * * @since 0.1.0 */ protected renderVersion(context: Context): void; /** * Render the supplied record as a resource object. * * @since 0.1.0 */ protected renderRecord(context: Context, record: Model): Promise; /** * Returns the JSONAPI attributes object representing this record's * relationships * * @since 0.1.0 */ protected attributesForRecord(context: Context, record: Model): JSONAPI.Attributes; /** * The JSONAPI spec recommends (but does not require) that property names be * dasherized. The default implementation of this serializer therefore does * that, but you can override this method to use a different approach. * * @since 0.1.0 */ protected serializeAttributeName(context: Context, name: string): string; /** * Take an attribute value and return the serialized value. Useful for * changing how certain types of values are serialized, i.e. Date objects. * * The default implementation returns the attribute's value unchanged. * * @since 0.1.0 */ protected serializeAttributeValue(context: Context, value: any, key: string, record: Model): any; /** * Returns the JSONAPI relationships object representing this record's * relationships * * @since 0.1.0 */ protected relationshipsForRecord(context: Context, record: Model): Promise; /** * Convert the relationship name to it's "over-the-wire" format. Defaults to * dasherizing it. * * @since 0.1.0 */ protected serializeRelationshipName(context: Context, name: string): string; /** * Takes the serializer config and the model's descriptor for a relationship, * and returns the serialized relationship object. Also sideloads any full * records if the relationship is so configured. * * @since 0.1.0 */ protected serializeRelationship(context: Context, name: string, config: RelationshipConfig, descriptor: RelationshipDescriptor, record: Model): Promise; /** * Returns the serialized form of the related Models for the given record and * relationship. * * @since 0.1.0 */ protected dataForRelationship(context: Context, name: string, config: RelationshipConfig, descriptor: RelationshipDescriptor, record: Model): Promise; /** * Given a related record, return the resource object for that record, and * sideload the record as well. * * @since 0.1.0 */ protected dataForRelatedRecord(context: Context, name: string, relatedRecord: Model, config: RelationshipConfig, descriptor: RelationshipDescriptor, record: Model): Promise; /** * Takes a relationship descriptor and the record it's for, and returns any * links for that relationship for that record. I.e. '/books/1/author' * * @since 0.1.0 */ protected linksForRelationship(context: Context, name: string, config: RelationshipConfig, descriptor: RelationshipDescriptor, record: Model): JSONAPI.Links; /** * Returns any meta for a given relationship and record. No meta included by * default. * * @since 0.1.0 */ protected metaForRelationship(context: Context, name: string, config: RelationshipConfig, descriptor: RelationshipDescriptor, record: Model): JSONAPI.Meta | void; /** * Returns links for a particular record, i.e. self: "/books/1". Default * implementation assumes the URL for a particular record maps to that type's * `show` action, i.e. `books/show`. * * @since 0.1.0 */ protected linksForRecord(context: Context, record: Model): JSONAPI.Links; /** * Returns meta for a particular record. * * @since 0.1.0 */ protected metaForRecord(context: Context, record: Model): void | JSONAPI.Meta; /** * Sideloads a record into the top level "included" array * * @since 0.1.0 */ protected includeRecord(context: Context, name: string, relatedRecord: Model, config: RelationshipConfig, descriptor: RelationshipDescriptor): Promise; /** * Render the supplied error * * @since 0.1.0 */ protected renderError(context: Context, error: any): JSONAPI.ErrorObject; /** * Given an error, return a unique id for this particular occurence of the * problem. * * @since 0.1.0 */ protected idForError(context: Context, error: any): string; /** * A short, human-readable summary of the problem that SHOULD NOT change from * occurrence to occurrence of the problem, except for purposes of * localization. * * @since 0.1.0 */ protected titleForError(context: Context, error: any): string; /** * Given an error, return a JSON Pointer, a URL query param name, or other * info indicating the source of the error. * * @since 0.1.0 */ protected sourceForError(context: Context, error: any): string; /** * Return the meta for a given error object. You could use this for example, * to return debug information in development environments. * * @since 0.1.0 */ protected metaForError(context: Context, error: any): JSONAPI.Meta | void; /** * Return a links object for an error. You could use this to link to a bug * tracker report of the error, for example. * * @since 0.1.0 */ protected linksForError(context: Context, error: any): JSONAPI.Links | void; /** * Remove duplicate entries from the sideloaded data. * * @since 0.1.0 */ protected dedupeIncluded(context: Context): void; }