urlUtils.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import _ from 'lodash'
  2. /**
  3. * Utilitaire permettant de construire une URL pour l'interrogation d'une API externe
  4. */
  5. const UrlUtils = {
  6. /**
  7. * Concatenate a base url and a tail
  8. * @param base
  9. * @param tails
  10. * @private
  11. */
  12. join(base: string | number, ...tails: Array<string | number>): string {
  13. let url = String(base)
  14. tails.forEach((tail: string | number) => {
  15. url =
  16. url.replace(/^|\/$/g, '') + '/' + String(tail).replace(/^\/?|$/g, '')
  17. })
  18. return url
  19. },
  20. /**
  21. * Prepend the 'https://' part if neither 'http://' nor 'https://' prefixes are present, else does nothing
  22. *
  23. * @param url
  24. */
  25. prependHttps(url: string): string {
  26. if (!url.match(/^https?:\/\/.*/)) {
  27. url = 'https://' + url
  28. }
  29. return url
  30. },
  31. /**
  32. * Parse an URI to retrieve a parameter
  33. *
  34. * @param uri
  35. * @param parameter
  36. * @param default_
  37. * @private
  38. */
  39. getParameter(
  40. uri: string,
  41. parameter: string,
  42. default_: string | number | null = null,
  43. ): string | number | null {
  44. uri = this.prependHttps(uri)
  45. const urlParams = new URL(uri).searchParams
  46. let value: string | number | null = urlParams.get(parameter)
  47. if (
  48. value &&
  49. (default_ === null || Number.isInteger(default_)) &&
  50. /^\d+$/.test(value)
  51. ) {
  52. // On convertit automatiquement si et seulement la valeur par défaut est elle-même un entier ou n'est pas définie
  53. value = parseInt(value)
  54. }
  55. return value ?? default_
  56. },
  57. /**
  58. * Extrait l'ID de l'URI passée en paramètre
  59. * L'URI est supposée être de la forme `.../foo/bar/{id}`,
  60. * où l'id est un identifiant numérique, à moins que `isLiteral` soit défini comme vrai.
  61. * Dans ce cas, si `isLiteral` est vrai, l'id sera retourné sous forme de texte.
  62. *
  63. * @param uri
  64. * @param isLiteral
  65. */
  66. extractIdFromUri(
  67. uri: string,
  68. isLiteral: boolean = false,
  69. ): number | string | null {
  70. const partUri: Array<string> = uri.split('/')
  71. const id: string = partUri.pop() ?? ''
  72. if (!id || (!isLiteral && !/\d+/.test(id))) {
  73. throw new Error('no id found')
  74. }
  75. return isLiteral ? id : parseInt(id)
  76. },
  77. /**
  78. * Découpe une URI au niveau des '/'
  79. * Utilisé entre autres pour le breadcrumb
  80. *
  81. * Ex:
  82. *
  83. * foo/bar/1 => ['foo', 'bar', '1']
  84. * /foo/bar/1 => ['foo', 'bar', '1']
  85. * https://domain.com/foo/bar/1 => ['https:', 'domain.com', 'foo', 'bar', '1']
  86. *
  87. *
  88. * @param uri
  89. */
  90. split(uri: string) {
  91. return uri.split('/').filter((s) => s.length > 0)
  92. },
  93. /**
  94. * Format and add a query to an url
  95. * If the url already has a query, append the new parameters to it.
  96. * If the query is an empty object, does nothing.
  97. *
  98. * Ex:
  99. * addQuery('foo/bar', {}) => 'foo/bar'
  100. * addQuery('foo/bar', {'a': 1}) => 'foo/bar?a=1'
  101. * addQuery('foo/bar?a=1', {'b': 2}) => 'foo/bar?a=1&b=2'
  102. *
  103. * @param url
  104. * @param query
  105. */
  106. addQuery(url: string | URL, query: object): string {
  107. let urlObj = new URL(url, 'https://temporary-dommain.inexistent') as URL
  108. if (!_.isEmpty(query)) {
  109. urlObj = new URL(
  110. `${urlObj.origin}${urlObj.pathname}${urlObj.hash}?${new URLSearchParams(
  111. [
  112. ...Array.from(urlObj.searchParams.entries()),
  113. ...Object.entries(query),
  114. ],
  115. )}`,
  116. )
  117. }
  118. let result = urlObj.toString()
  119. if (urlObj.host === 'temporary-dommain.inexistent') {
  120. result = result.replace('https://temporary-dommain.inexistent', '')
  121. }
  122. return result
  123. },
  124. /**
  125. * Make an ApiPlatform IRI for the given entity and id
  126. *
  127. * @see https://api-platform.com/docs/admin/handling-relations/
  128. */
  129. makeIRI(entity: string, id: number | string) {
  130. const initialId = id
  131. if (_.isString(id)) {
  132. id = parseInt(id)
  133. }
  134. if (!_.isFinite(id)) {
  135. throw new TypeError('Invalid id : ' + initialId)
  136. }
  137. return `/api/${entity}/${id}`
  138. },
  139. }
  140. export default UrlUtils