| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import type {AnyJson, ApiResponse, HydraMetadata} from '~/types/data'
- import UrlUtils from '~/services/utils/urlUtils'
- import {METADATA_TYPE} from '~/types/enum/data'
- import models from "~/models/models";
- import ApiResource from "~/models/ApiResource";
- import {isArray} from "lodash";
- /**
- * Normalisation et dé-normalisation du format de données Hydra
- */
- class HydraNormalizer {
- static models = models
- /**
- * Normalize the given entity into a Hydra formatted content.
- * @param entity
- */
- public static normalizeEntity(entity: ApiResource): AnyJson {
- const iriEncodedFields = HydraNormalizer.getIriEncodedFields(entity)
- for (const field in iriEncodedFields) {
- const value = entity[field]
- const targetEntity = iriEncodedFields[field].entity
- if (isArray(value)) {
- entity[field] = value.map((id: number) => {
- return UrlUtils.makeIRI(targetEntity, id)
- })
- } else {
- entity[field] = UrlUtils.makeIRI(targetEntity, value)
- }
- }
- return entity.$toJson()
- }
- /**
- * Parse une réponse Hydra et retourne un objet ApiResponse
- *
- * @param {AnyJson} data
- * @param model
- * @return {AnyJson} réponse parsée
- */
- public static denormalize(data: AnyJson, model?: typeof ApiResource): ApiResponse {
- return {
- data: HydraNormalizer.getData(data, model),
- metadata: HydraNormalizer.getMetadata(data)
- }
- }
- protected static getData(hydraData: AnyJson, model?: typeof ApiResource): AnyJson {
- if (hydraData['@type'] === 'hydra:Collection') {
- const members = hydraData['hydra:member']
- return members.map((item: AnyJson) => HydraNormalizer.denormalizeItem(item, model))
- } else {
- return HydraNormalizer.denormalizeItem(hydraData, model)
- }
- }
- /**
- * Génère les métadonnées d'un item ou d'une collection
- *
- * @param data
- * @protected
- */
- protected static getMetadata(data: AnyJson): HydraMetadata {
- if (data['@type'] !== 'hydra:Collection') {
- // A single item, no metadata
- return { type: METADATA_TYPE.ITEM }
- }
- const metadata: HydraMetadata = {
- totalItems: data['hydra:totalItems']
- }
- if (data['hydra:view']) {
- /**
- * Extract the page number from the IRIs in the hydra:view section
- */
- const extractPageNumber = (pos: string, default_: number | undefined=undefined): number | undefined => {
- const iri = data['hydra:view']['hydra:' + pos]
- if (!iri) {
- return default_
- }
- return UrlUtils.getParameter(
- data['hydra:view']['hydra:' + pos],
- 'page',
- default_
- ) as number | undefined
- }
- // TODO: utile d'ajouter la page en cours?
- metadata.firstPage = extractPageNumber('first', 1)
- metadata.lastPage = extractPageNumber('last', 1)
- metadata.nextPage = extractPageNumber('next')
- metadata.previousPage = extractPageNumber('previous')
- }
- metadata.type = METADATA_TYPE.COLLECTION
- return metadata
- }
- /**
- * Dénormalise un item d'une réponse hydra
- *
- * @param item
- * @param model
- * @protected
- */
- protected static denormalizeItem(item: AnyJson, model?: typeof ApiResource): AnyJson {
- if (model) {
- return HydraNormalizer.denormalizeEntity(model, item)
- }
- if (!item.hasOwnProperty('@id')) {
- // Not hydra formatted
- console.error('De-normalization error : the item is not hydra formatted', item)
- return item
- }
- if (item['@id'].match(/\/api\/enum\/\w+/)) {
- return HydraNormalizer.denormalizeEnum(item)
- }
- let entity = null
- // On essaie de déterminer la nature de l'objet à partir de son id
- try {
- const iri = HydraNormalizer.parseEntityIRI(item['@id'])
- entity = iri.entity
- } catch (e) {
- console.error('De-normalization error : could not parse the IRI', item)
- return item
- }
- if (entity && HydraNormalizer.models.hasOwnProperty(entity)) {
- model = HydraNormalizer.models[entity]
- return HydraNormalizer.denormalizeEntity(model, item)
- }
- throw Error('De-normalization error : Could not determine the type of the entity '
- + item['@id'] + ' (found: ' + entity + ')')
- }
- protected static denormalizeEntity(model: typeof ApiResource, item: AnyJson) {
- const instance = new model(item)
- const iriEncodedFields = HydraNormalizer.getIriEncodedFields(instance)
- for (const field in iriEncodedFields) {
- const value = instance[field]
- const targetEntity = iriEncodedFields[field].entity
- if (isArray(value)) {
- instance[field] = value.map((iri: string) => {
- return HydraNormalizer.getIdFromEntityIri(iri, targetEntity)
- })
- } else {
- instance[field] = HydraNormalizer.getIdFromEntityIri(value, targetEntity)
- }
- }
- return instance
- }
- protected static denormalizeEnum(item: AnyJson): AnyJson {
- return item
- }
- /**
- * Parse the given IRI
- * @param iri
- * @protected
- */
- protected static parseEntityIRI(iri: string) {
- const rx = /\/api\/(\w+)\/(\d+)/
- const match = rx.exec(iri)
- if (!match) {
- throw Error('could not parse the IRI : ' + JSON.stringify(iri))
- }
- return {
- entity: match[1],
- id: parseInt(match[2])
- }
- }
- /**
- * Get the array of the entity's fields marked as IRIEncoded
- * @see models/decorators.ts
- *
- * @param entity
- * @protected
- */
- protected static getIriEncodedFields(entity: ApiResource): Record<string, ApiResource> {
- const prototype = Object.getPrototypeOf(entity)
- return prototype.constructor.relations
- }
- /**
- * Retrieve the entitie's id from the given IRI
- * Throws an error if the IRI does not match the expected entity
- *
- * @param iri
- * @param expectedEntity
- * @protected
- */
- protected static getIdFromEntityIri(iri: string, expectedEntity: string): number | string {
- const { entity, id } = HydraNormalizer.parseEntityIRI(iri)
- if (entity !== expectedEntity) {
- throw Error("IRI entity does not match the field's target entity (" + entity + ' != ' + expectedEntity + ")")
- }
- return id
- }
- }
- export default HydraNormalizer
|