urlUtils.ts 3.8 KB

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