Repository: badges/shields (js)

Issue:
Add Nexus Repository Manager 3 support
:clipboard: **Description**

<!-- A clear and concise description of the new feature. -->

Nexus badges don't work (show "artifact not found") with Nexus 3, even if it has the "NXRM2 style URIs" capability enabled.

This is probably because Nexus 3 has had a major overhaul of its REST API. The new API seems to support our use case. For example, a request like this to our self-hosted Nexus 3 instance:
```sh
$ curl -u user:pass -X GET "http://nexus.example.com/service/rest/v1/search?sort=version&repository=public&group=org.slf4j&name=slf4j-api" -H "accept: application/json"
```

yields this:

<details>
<summary>Output</summary>

```json
{
  "items" : [ {
    "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmI2YzZlZjk3OTZkYWM4MzA0ZWJkYmUxN2JmMGFiMTM",
    "repository" : "spring-milestones",
    "format" : "maven2",
    "group" : "org.slf4j",
    "name" : "slf4j-api",
    "version" : "1.8.0-beta4",
    "assets" : [ {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.jar",
      "path" : "org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNmUyNDAyMjcwNmU2NTdhNDA",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "83b0359d847ee053d745be7ec0d8e9e8a44304b4",
        "md5" : "e8147675316a5bc78d1ba5d8cdb9e578"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6ZDZlNGE1MGFiYTNjOGExOTBkNTk0ZGFiOTI4NDExODU",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "a8dbd7d0219300504b1dbb745b06d237ff820a3a",
        "md5" : "fb4bcf72e6dc807a6dcbdebc6bb889fe"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.pom",
      "path" : "org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.pom",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmU3NjU5YzQ4Yjg2OGFkNDQ0OTY0MjY4OGJmZDQ4MDU",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "0bbd45e9c4e1384fb96d3f0d32494d7d02668fb5",
        "md5" : "db31efff7324bfa2d595451f617d7f5a"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.pom.sha1",
      "path" : "org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.pom.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6ODUwYzgwZjYxYzk0MDJlN2JiZDk2YTk3YTljOTk1YjE",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "6ff1c8f882905286f2284b702b05bbbff7234387",
        "md5" : "13ced8d0a7fdc5e6ebd3deac3ac05bf0"
      }
    } ]
  }, {
    "id" : "c3ByaW5nLW1pbGVzdG9uZXM6Zjg5OGIzOTAzY2I5OWM1OTUyZTMyYmNjM2M5MjFjNmQ",
    "repository" : "spring-milestones",
    "format" : "maven2",
    "group" : "org.slf4j",
    "name" : "slf4j-api",
    "version" : "1.7.28",
    "assets" : [ {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-javadoc.jar",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-javadoc.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNmU0ZGU4YmY3MzJiYTEwNjM",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "e70c28747173e53d680f268d021916e684235953",
        "md5" : "89570ffb082eda201ffd50e1f278f413"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-javadoc.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-javadoc.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MjRjMWZlMzM1ZDI2NjUyZmVhOGU2N2IxMDI2N2I3Yzk",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "ec0a6aa49f0c57484ced36e60a07a35f42f566ef",
        "md5" : "ae720339d13e38b2609c613f255cc596"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-sources.jar",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-sources.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MjRjMWZlMzM1ZDI2NjUyZmU0MTgxMzExMWM2MDkyYzY",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "6444f3c8fce32e20f621e264807256c5e65f11c9",
        "md5" : "f265e4f098277b34e33c3c2e429bf05f"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-sources.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28-sources.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmU3NjU5YzQ4Yjg2OGFkNGVkMWZiZTk4ZTRhZTk4ODA",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "317709ca15a130e929d8d77cf14a7c5657f15f16",
        "md5" : "5ee5c4d6974407045d82e9d410fe3bdb"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.jar",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmU3NjU5YzQ4Yjg2OGFkNDRiOWYyM2YwNjVmMmU4ODg",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "2cd9b264f76e3d087ee21bfc99305928e1bdb443",
        "md5" : "1468c816e659d8013027d912863dc865"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MmZmZjUwOWE3YzJhOWViZWVjYTI2NTMyOTExZWVhMTc",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "2b97429f72765cb5dee8c8587f8d58855cd344f3",
        "md5" : "3a237523b0854cb992fdcb69e147bb25"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.pom",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.pom",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MmZmZjUwOWE3YzJhOWViZWZhZmM5OWIxZDYyNDU1Nzc",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "cd719d9023e40888f24b9d2556a2aad034b92203",
        "md5" : "9f3143b70210714beae6be00e436cd19"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.pom.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.28/slf4j-api-1.7.28.pom.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2YjMwOWQ1N2FjZGRmOTljZjE",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "9f14c48474d171f48a5ace29f800654e4259288f",
        "md5" : "8126ea7ff2fd8696df2feb8c9f63e514"
      }
    } ]
  }, {
    "id" : "c3ByaW5nLW1pbGVzdG9uZXM6Zjg5OGIzOTAzY2I5OWM1OWQ3OTA1NDY4M2QyZTM5NDk",
    "repository" : "spring-milestones",
    "format" : "maven2",
    "group" : "org.slf4j",
    "name" : "slf4j-api",
    "version" : "1.7.26",
    "assets" : [ {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-javadoc.jar",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-javadoc.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MjRjMWZlMzM1ZDI2NjUyZmZhN2I3ZTZiNWU5NDBmMTM",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "83863db711c68b9d5542c5fa0cd801b7035281d7",
        "md5" : "d35c4b8eaa7f7dbe3cc7b474902983ae"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-javadoc.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-javadoc.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNjczYjkzZjU5NGExYzUxZDg",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "34a2fe48c02d4dfaa8f8b13086977f6fb8294b92",
        "md5" : "5debf830459684cbaf431d48640f3176"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-sources.jar",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-sources.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmYwYmNmZjMzOWJlZWYwNmRhM2M4N2ZkNDRiYmIxYjQ",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "021c84cdf9da108216b5e402611d4af479b60cb8",
        "md5" : "d208882740e2c4a971dbdec6d48b757b"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-sources.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-sources.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MjRjMWZlMzM1ZDI2NjUyZmM2MjlkMTc0YTRlZGY3Nzg",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "50169964c3f1f07e3f6a4831a89b6faebbf8eb84",
        "md5" : "69f77699ef8696b8833c7fd087e17513"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2Yjg1NzkyMGM5ZjQ1MDZkODM",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "77100a62c2e6f04b53977b9f541044d7d722693d",
        "md5" : "60ec8751be37d54a2aa1b6178f87b968"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2YjJkNGI1OTE1MjAzNGU1MGI",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "445665e3c0491025680c9249090dc17642c35f0c",
        "md5" : "ee5399830ce3dc1610b4b9bf19589114"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.pom",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.pom",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MmZmZjUwOWE3YzJhOWViZWNmZGE1MDVjYzhhYzk1N2Y",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "4d3419a58d77c07f49185aaa556a787d50508d27",
        "md5" : "d1b34b4f8ee2feadc81c38781eb1d5ed"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.pom.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.pom.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2YmQyZGMxYzc3MTMzZjcxMzc",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "d8f45ccfdc07e94a5ec6bce7c58e6a2869bf7d90",
        "md5" : "d5b641d9b61a40a7b4b670a94d867c9d"
      }
    } ]
  }, {
    "id" : "c3ByaW5nLW1pbGVzdG9uZXM6ZDA2NDgwNGE4ZWQ1YWQ2ZTBjZTg3OGExZDVjZGE0M2M",
    "repository" : "spring-milestones",
    "format" : "maven2",
    "group" : "org.slf4j",
    "name" : "slf4j-api",
    "version" : "1.7.25",
    "assets" : [ {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-javadoc.jar",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-javadoc.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MjRjMWZlMzM1ZDI2NjUyZjE4OTM0OGNiODljYTVlNDY",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "f003e89ddebdbaca5cf3fc7cc0c67c88c2ca1a3c",
        "md5" : "91d00b2a20f993a225aa5d58000b5913"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-javadoc.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-javadoc.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNmYwZTJkZjVjMjBjMjRlYmQ",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "1bb012053cab87431f38f070bfc0ef0494b12a2e",
        "md5" : "fdd9d2da0852b154e138a1fd5dc429ba"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6MmZmZjUwOWE3YzJhOWViZWY0NDZmZDQzYjQyNjU2YjQ",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "962153db4a9ea71b79d047dfd1b2a0d80d8f4739",
        "md5" : "6ad0f63b2eaac80e1db9c36235e5db0b"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmYwYmNmZjMzOWJlZWYwNmJjOTA3OTRhMjJlNzhjNjg",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "a32b3e2c22c5122b0fb11b9032966e22e4b4b98d",
        "md5" : "d616e34a02a7d085919994f5dee8a0f6"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNjRjNTVlNzkzMGI5Y2FhZTg",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "da76ca59f6a57ee3102f8f9bd9cee742973efa8a",
        "md5" : "caafe376afb7086dcbee79f780394ca3"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2YjUzNTAxMDQ3NmNkNmE5YTY",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "8bcb4c89b77770f8f1ad0fe09c5c9e01b330eb0d",
        "md5" : "978b90e9c00ed4b44110073b0ee54be1"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.pom",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.pom",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmYwYmNmZjMzOWJlZWYwNjJhZjg5NmY0Y2Y2Y2YzMWE",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "df51c4a85dd6acf8b6cdc9323596766b3d577c28",
        "md5" : "53f7013d37871f9bc0445619999c09bf"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.pom.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.pom.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NDhjN2E2NzlhYTY3OTc2Yjg5NzFkYTVhNjEzNDExOGY",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "bbafa9a1fe00aadabb4e318c8ff98ce9aaa9abdf",
        "md5" : "a767a8bb2b65cc02877c2cefd4c97228"
      }
    } ]
  }, {
    "id" : "c3ByaW5nLW1pbGVzdG9uZXM6NTgxODAwNWRlMmViMmJkMTA0MjUzNjVmMjI2YmI4MDE",
    "repository" : "spring-milestones",
    "format" : "maven2",
    "group" : "org.slf4j",
    "name" : "slf4j-api",
    "version" : "1.7.12",
    "assets" : [ {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.12/slf4j-api-1.7.12.pom",
      "path" : "org/slf4j/slf4j-api/1.7.12/slf4j-api-1.7.12.pom",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YTQ3NTdiY2FhNjJiNjMwNjg2NDcyMWE0YjAwYmQzOGU",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "1163b15d6680795fcc64a14e0c8426a3cc0825a3",
        "md5" : "6eb81f637e9d81b6a71d0757a9f27c20"
      }
    }, {
      "downloadUrl" : "http://nexus.example.com/repository/spring-milestones/org/slf4j/slf4j-api/1.7.12/slf4j-api-1.7.12.pom.sha1",
      "path" : "org/slf4j/slf4j-api/1.7.12/slf4j-api-1.7.12.pom.sha1",
      "id" : "c3ByaW5nLW1pbGVzdG9uZXM6YmU3NjU5YzQ4Yjg2OGFkNDU5NjIxMGNmODQ3MWM4NjU",
      "repository" : "spring-milestones",
      "format" : "maven2",
      "checksum" : {
        "sha1" : "d074e9ad1a69f8b5937da7f7dd9434d5ad57ef4f",
        "md5" : "dc0ed4d57b058941f42ec61d0be415a9"
      }
    } ]
  } ],
  "continuationToken" : null
}
```
</details>
, which seems to have all the data we need. Disregard the weird repository and slf4j-api version - it seems to be some issue with proxy and/or group repositories.

The full API is documented [here](https://help.sonatype.com/repomanager3/rest-and-integration-api/search-api#SearchAPI-SearchComponents). There is also a swagger-ui available to poke around in this API (http://nexus.example.com/swagger-ui/).

<!-- Love Shields? Please consider donating $10 to sustain our activities:
👉  https://opencollective.com/shields -->


Pull request description:
Add version 3 support for [Nexus] badges
Closes #4410 by making the existing badges compatible with both Nexus 2 and Nexus 3 servers.

@nigredo-tori would you like to give this a look?

Patch:
diff --git a/services/nexus/nexus.service.js b/services/nexus/nexus.service.js
index 53d403f080..936a12c4e9 100644
--- a/services/nexus/nexus.service.js
+++ b/services/nexus/nexus.service.js
@@ -10,7 +10,7 @@ const {
 const { isSnapshotVersion } = require('./nexus-version')
 const { BaseJsonService, InvalidResponse, NotFound } = require('..')
 
-const searchApiSchema = Joi.object({
+const nexus2SearchApiSchema = Joi.object({
   data: Joi.array()
     .items(
       Joi.object({
@@ -27,20 +27,30 @@ const searchApiSchema = Joi.object({
     .required(),
 }).required()
 
-const resolveApiSchema = Joi.object({
+const nexus3SearchApiSchema = Joi.object({
+  items: Joi.array()
+    .items(
+      Joi.object({
+        // This schema is relaxed similarly to nexux2SearchApiSchema
+        version: Joi.string().required(),
+      })
+    )
+    .required(),
+}).required()
+
+const nexus2ResolveApiSchema = Joi.object({
   data: Joi.object({
     baseVersion: optionalDottedVersionNClausesWithOptionalSuffix,
     version: optionalDottedVersionNClausesWithOptionalSuffix,
   }).required(),
 }).required()
 
-// https://repository.sonatype.org/nexus-restlet1x-plugin/default/docs/path__artifact_maven_resolve.html
-// https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html
 const queryParamSchema = Joi.object({
   server: optionalUrl.required(),
   queryOpt: Joi.string()
-    .regex(/(:(?:q|g|a|v|p|c|cn|sha1|from|count|repositoryId|e|r)=[\w-. ]+)+/i)
+    .regex(/(:[\w.]+=[\w-. ]+)+/i)
     .optional(),
+  nexusVersion: Joi.equal('2', '3'),
 }).required()
 
 module.exports = class Nexus extends BaseJsonService {
@@ -66,15 +76,22 @@ module.exports = class Nexus extends BaseJsonService {
         title: 'Sonatype Nexus (Releases)',
         pattern: 'r/:groupId/:artifactId',
         namedParams: {
-          groupId: 'com.google.guava',
-          artifactId: 'guava',
+          groupId: 'org.apache.commons',
+          artifactId: 'commons-lang3',
         },
         queryParams: {
-          server: 'https://oss.sonatype.org',
+          server: 'https://nexus.pentaho.org',
+          nexusVersion: '3',
         },
         staticPreview: this.render({
-          version: 'v27.0.1-jre',
+          version: '3.9',
         }),
+        documentation: `
+        <p>
+          Specifying 'nexusVersion=3' when targeting Nexus 3 servers will speed up the badge rendering. 
+          Note that you can use this query parameter with any Nexus badge type (Releases, Snapshots, or Repository).
+        </p>
+        `,
       },
       {
         title: 'Sonatype Nexus (Snapshots)',
@@ -127,6 +144,14 @@ module.exports = class Nexus extends BaseJsonService {
         <p>
           Query options should be provided as key=value pairs separated by a colon.
         </p>
+        <p>
+          Possible values:
+          <ul>
+            <li><a href="https://nexus.pentaho.org/swagger-ui/#/search/search">All Nexus 3 badges</a></li>
+            <li><a href="https://repository.sonatype.org/nexus-restlet1x-plugin/default/docs/path__artifact_maven_resolve.html">Nexus 2 Releases and Snapshots badges</a></li>
+            <li><a href=https://repository.sonatype.org/nexus-indexer-lucene-plugin/default/docs/path__lucene_search.html">Nexus 2 Repository badges</a></li>
+          </ul>
+        </p>
         `,
       },
     ]
@@ -157,7 +182,23 @@ module.exports = class Nexus extends BaseJsonService {
     })
   }
 
-  async fetch({ server, repo, groupId, artifactId, queryOpt }) {
+  async fetch({ server, repo, groupId, artifactId, queryOpt, nexusVersion }) {
+    if (nexusVersion === '3') {
+      return this.fetch3({ server, repo, groupId, artifactId, queryOpt })
+    }
+    // Most servers still use Nexus 2. Fall back to Nexus 3 if the hitting a
+    // Nexus 2 endpoint returns a Bad Request (=> InvalidResponse).
+    try {
+      return await this.fetch2({ server, repo, groupId, artifactId, queryOpt })
+    } catch (e) {
+      if (e instanceof InvalidResponse) {
+        return this.fetch3({ server, repo, groupId, artifactId, queryOpt })
+      }
+      throw e
+    }
+  }
+
+  async fetch2({ server, repo, groupId, artifactId, queryOpt }) {
     const qs = {
       g: groupId,
       a: artifactId,
@@ -168,10 +209,10 @@ module.exports = class Nexus extends BaseJsonService {
     // for /nexus/[rs]/... pattern, use the search api of the nexus server, and
     // for /nexus/<repo-name>/... pattern, use the resolve api of the nexus server.
     if (repo === 'r' || repo === 's') {
-      schema = searchApiSchema
+      schema = nexus2SearchApiSchema
       url += 'service/local/lucene/search'
     } else {
-      schema = resolveApiSchema
+      schema = nexus2ResolveApiSchema
       url += 'service/local/artifact/maven/resolve'
       qs.r = repo
       qs.v = 'LATEST'
@@ -190,10 +231,48 @@ module.exports = class Nexus extends BaseJsonService {
       },
     })
 
-    return { json }
+    return { actualNexusVersion: '2', json }
+  }
+
+  async fetch3({ server, repo, groupId, artifactId, queryOpt }) {
+    const qs = {
+      group: groupId,
+      name: artifactId,
+      sort: 'version',
+    }
+    if (repo === 's') {
+      qs.prerelease = 'true'
+    } else if (repo !== 'r') {
+      qs.repository = repo
+    }
+
+    if (queryOpt) {
+      this.addQueryParamsToQueryString({ qs, queryOpt })
+    }
+
+    const url = `${server}${
+      server.slice(-1) === '/' ? '' : '/'
+    }service/rest/v1/search`
+
+    const json = await this._requestJson({
+      schema: nexus3SearchApiSchema,
+      url,
+      options: { qs, auth: this.authHelper.basicAuth },
+      errorMessages: {
+        404: 'artifact not found',
+      },
+    })
+
+    return { actualNexusVersion: '3', json }
   }
 
-  transform({ repo, json }) {
+  transform({ repo, json, actualNexusVersion }) {
+    return actualNexusVersion === '3'
+      ? this.transform3({ repo, json })
+      : this.transform2({ repo, json })
+  }
+
+  transform2({ repo, json }) {
     if (json.data.length === 0) {
       throw new NotFound({ prettyMessage: 'artifact or version not found' })
     }
@@ -224,16 +303,30 @@ module.exports = class Nexus extends BaseJsonService {
     }
   }
 
-  async handle({ repo, groupId, artifactId }, { server, queryOpt }) {
-    const { json } = await this.fetch({
+  transform3({ repo, json }) {
+    if (json.items.length === 0) {
+      const versionType = repo === 's' ? 'snapshot ' : ''
+      throw new NotFound({
+        prettyMessage: `artifact or ${versionType}version not found`,
+      })
+    }
+    return { version: json.items[0].version }
+  }
+
+  async handle(
+    { repo, groupId, artifactId },
+    { server, queryOpt, nexusVersion }
+  ) {
+    const { actualNexusVersion, json } = await this.fetch({
       repo,
       server,
       groupId,
       artifactId,
       queryOpt,
+      nexusVersion,
     })
 
-    const { version } = this.transform({ repo, json })
+    const { version } = this.transform({ repo, json, actualNexusVersion })
     return this.constructor.render({ version })
   }
 }
diff --git a/services/nexus/nexus.spec.js b/services/nexus/nexus.spec.js
index 59a38c8a88..3b478495d2 100644
--- a/services/nexus/nexus.spec.js
+++ b/services/nexus/nexus.spec.js
@@ -7,10 +7,10 @@ const Nexus = require('./nexus.service')
 const { InvalidResponse, NotFound } = require('..')
 
 describe('Nexus', function() {
-  context('transform()', function() {
+  context('transform2()', function() {
     it('throws NotFound error when no versions exist', function() {
       try {
-        Nexus.prototype.transform({ json: { data: [] } })
+        Nexus.prototype.transform2({ json: { data: [] } })
         expect.fail('Expected to throw')
       } catch (e) {
         expect(e).to.be.an.instanceof(NotFound)
@@ -20,7 +20,7 @@ describe('Nexus', function() {
 
     it('throws InvalidResponse error when no there is no latestRelease version', function() {
       try {
-        Nexus.prototype.transform({ repo: 'r', json: { data: [{}] } })
+        Nexus.prototype.transform2({ repo: 'r', json: { data: [{}] } })
         expect.fail('Expected to throw')
       } catch (e) {
         expect(e).to.be.an.instanceof(InvalidResponse)
@@ -30,7 +30,7 @@ describe('Nexus', function() {
 
     it('returns latestSnapshot value', function() {
       const latestSnapshot = '7.0.1-SNAPSHOT'
-      const { version } = Nexus.prototype.transform({
+      const { version } = Nexus.prototype.transform2({
         repo: 's',
         json: {
           data: [{ latestSnapshot }, { version: '1.2.3' }],
@@ -41,7 +41,7 @@ describe('Nexus', function() {
 
     it('returns version value when it is a snapshot', function() {
       const latestSnapshot = '1.2.7-SNAPSHOT'
-      const { version } = Nexus.prototype.transform({
+      const { version } = Nexus.prototype.transform2({
         repo: 's',
         json: {
           data: [{ latestSnapshot: '1.2.3' }, { version: latestSnapshot }],
@@ -52,7 +52,7 @@ describe('Nexus', function() {
 
     it('throws InvalidResponse error when no snapshot versions exist', function() {
       try {
-        Nexus.prototype.transform({ repo: 's', json: { data: [{}] } })
+        Nexus.prototype.transform2({ repo: 's', json: { data: [{}] } })
         expect.fail('Expected to throw')
       } catch (e) {
         expect(e).to.be.an.instanceof(InvalidResponse)
@@ -62,13 +62,56 @@ describe('Nexus', function() {
 
     it('throws InvalidResponse error when repository has no version data', function() {
       try {
-        Nexus.prototype.transform({ repo: 'developer', json: { data: {} } })
+        Nexus.prototype.transform2({
+          repo: 'developer',
+          json: { data: {} },
+        })
         expect.fail('Expected to throw')
       } catch (e) {
         expect(e).to.be.an.instanceof(InvalidResponse)
         expect(e.prettyMessage).to.equal('invalid artifact version')
       }
     })
+
+    context('transform3()', function() {
+      it('throws NotFound error when no items exist', function() {
+        try {
+          Nexus.prototype.transform3({ json: { items: [] } })
+          expect.fail('Expected to throw')
+        } catch (e) {
+          expect(e).to.be.an.instanceof(NotFound)
+          expect(e.prettyMessage).to.equal('artifact or version not found')
+        }
+      })
+
+      it('throws NotFound error when no snapshot items exist', function() {
+        try {
+          Nexus.prototype.transform3({
+            repo: 's',
+            json: { items: [] },
+          })
+          expect.fail('Expected to throw')
+        } catch (e) {
+          expect(e).to.be.an.instanceof(NotFound)
+          expect(e.prettyMessage).to.equal(
+            'artifact or snapshot version not found'
+          )
+        }
+      })
+
+      it('returns first item version', function() {
+        const { version } = Nexus.prototype.transform3({
+          json: {
+            items: [
+              { version: '1.2.3' },
+              { version: '1.2.2' },
+              { version: '1.0.1' },
+            ],
+          },
+        })
+        expect(version).to.equal('1.2.3')
+      })
+    })
   })
 
   describe('auth', function() {


Test patch:
diff --git a/services/nexus/nexus.tester.js b/services/nexus/nexus.tester.js
index 7edd884232..21c9ed661a 100644
--- a/services/nexus/nexus.tester.js
+++ b/services/nexus/nexus.tester.js
@@ -5,7 +5,7 @@ const {
 } = require('../test-validators')
 const t = (module.exports = require('../tester').createServiceTester())
 
-t.create('search release version valid artifact')
+t.create('Nexus 2 - search release version valid artifact')
   .timeout(15000)
   .get('/r/com.google/bitcoinj.json?server=https://oss.sonatype.org')
   .expectBadge({
@@ -13,7 +13,7 @@ t.create('search release version valid artifact')
     message: isVersion,
   })
 
-t.create('search release version of an nonexistent artifact')
+t.create('Nexus 2 - search release version of an nonexistent artifact')
   .timeout(15000)
   .get(
     '/r/com.google.guava/nonexistent-artifact-id.json?server=https://oss.sonatype.org'
@@ -23,7 +23,7 @@ t.create('search release version of an nonexistent artifact')
     message: 'artifact or version not found',
   })
 
-t.create('search snapshot version valid snapshot artifact')
+t.create('Nexus 2 - search snapshot version valid snapshot artifact')
   .timeout(15000)
   .get(
     '/s/org.fusesource.apollo/apollo-karaf-feature.json?server=https://repository.jboss.org/nexus'
@@ -33,7 +33,7 @@ t.create('search snapshot version valid snapshot artifact')
     message: isVersion,
   })
 
-t.create('search snapshot version of an nonexistent artifact')
+t.create('Nexus 2 - search snapshot version of an nonexistent artifact')
   .timeout(15000)
   .get(
     '/s/com.google.guava/nonexistent-artifact-id.json?server=https://oss.sonatype.org'
@@ -44,17 +44,14 @@ t.create('search snapshot version of an nonexistent artifact')
     color: 'red',
   })
 
-t.create('repository version')
-  .timeout(15000)
-  .get(
-    '/developer/ai.h2o/h2o-automl.json?server=https://repository.jboss.org/nexus'
-  )
+t.create('Nexus 2 - repository version')
+  .get('/public/asm/asm.json?server=http://repo.e-iceblue.com/nexus')
   .expectBadge({
     label: 'nexus',
     message: isVersion,
   })
 
-t.create('repository version with query')
+t.create('Nexus 2 - repository version with query')
   .timeout(15000)
   .get(
     `/fs-public-snapshots/com.progress.fuse/fusehq.json?server=https://repository.jboss.org/nexus&queryOpt=${encodeURIComponent(
@@ -66,7 +63,7 @@ t.create('repository version with query')
     message: isVersion,
   })
 
-t.create('repository version of an nonexistent artifact')
+t.create('Nexus 2 - repository version of an nonexistent artifact')
   .timeout(15000)
   .get(
     '/developer/jboss/nonexistent-artifact-id.json?server=https://repository.jboss.org/nexus'
@@ -76,7 +73,7 @@ t.create('repository version of an nonexistent artifact')
     message: 'artifact not found',
   })
 
-t.create('snapshot version with + in version')
+t.create('Nexus 2 - snapshot version with + in version')
   .get(
     '/s/com.progress.fuse/fusehq.json?server=https://repository.jboss.org/nexus'
   )
@@ -92,7 +89,7 @@ t.create('snapshot version with + in version')
     message: isVersion,
   })
 
-t.create('search snapshot version not in latestSnapshot')
+t.create('Nexus 2 - search snapshot version not in latestSnapshot')
   .get(
     '/s/com.progress.fuse/fusehq.json?server=https://repository.jboss.org/nexus'
   )
@@ -108,7 +105,7 @@ t.create('search snapshot version not in latestSnapshot')
     color: 'orange',
   })
 
-t.create('search snapshot no snapshot versions')
+t.create('Nexus 2 - search snapshot no snapshot versions')
   .get(
     '/s/com.progress.fuse/fusehq.json?server=https://repository.jboss.org/nexus'
   )
@@ -124,7 +121,7 @@ t.create('search snapshot no snapshot versions')
     color: 'lightgrey',
   })
 
-t.create('search release version')
+t.create('Nexus 2 - search release version')
   .get('/r/jboss/jboss-client.json?server=https://repository.jboss.org/nexus')
   .intercept(nock =>
     nock('https://repository.jboss.org/nexus')
@@ -138,7 +135,7 @@ t.create('search release version')
     color: 'blue',
   })
 
-t.create('repository release version')
+t.create('Nexus 2 - repository release version')
   .get(
     '/developer/ai.h2o/h2o-automl.json?server=https://repository.jboss.org/nexus'
   )
@@ -164,7 +161,7 @@ t.create('repository release version')
     color: 'blue',
   })
 
-t.create('repository release version')
+t.create('Nexus 2 - repository release version')
   .get(
     '/developer/ai.h2o/h2o-automl.json?server=https://repository.jboss.org/nexus'
   )
@@ -189,7 +186,7 @@ t.create('repository release version')
     color: 'blue',
   })
 
-t.create('user query params')
+t.create('Nexus 2 - user query params')
   .get(
     '/fs-public-snapshots/com.progress.fuse/fusehq.json?queryOpt=:c=agent-apple-osx:p=tar.gz&server=https://repository.jboss.org/nexus'
   )
@@ -215,3 +212,72 @@ t.create('user query params')
     message: 'v3.2.1',
     color: 'blue',
   })
+
+t.create('Nexus 3 - search release version valid artifact')
+  .get(
+    '/r/org.apache.commons/commons-lang3.json?server=https://nexus.pentaho.org&nexusVersion=3'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: isVersion,
+  })
+
+t.create(
+  'Nexus 3 - search release version valid artifact without explicit nexusVersion parameter'
+)
+  .timeout(15000)
+  .get(
+    '/r/org.apache.commons/commons-lang3.json?server=https://nexus.pentaho.org'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: isVersion,
+  })
+
+t.create('Nexus 3 - search release version of an nonexistent artifact')
+  .get(
+    '/r/org.apache.commons/nonexistent-artifact-id.json?server=https://nexus.pentaho.org&nexusVersion=3'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: 'artifact or version not found',
+  })
+
+t.create('Nexus 3 - search snapshot version valid snapshot artifact')
+  .get(
+    '/s/org.pentaho/pentaho-registry.json?server=https://nexus.pentaho.org&nexusVersion=3'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: isVersion,
+  })
+
+t.create('Nexus 3 - search snapshot version for artifact without snapshots')
+  .get(
+    '/s/javax.inject/javax.inject.json?server=https://nexus.pentaho.org&nexusVersion=3'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: 'artifact or snapshot version not found',
+    color: 'red',
+  })
+
+t.create('Nexus 3 - repository version')
+  .get(
+    '/proxy-public-3rd-party-release/com.fasterxml.jackson.core/jackson-databind.json?server=https://nexus.pentaho.org&nexusVersion=3'
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: isVersion,
+  })
+
+t.create('Nexus 3 - repository version with query')
+  .get(
+    `/proxy-public-3rd-party-release/org.junit.jupiter/junit-jupiter.json?server=https://nexus.pentaho.org&nexusVersion=3&queryOpt=${encodeURIComponent(
+      ':maven.extension=jar:direction=asc'
+    )}`
+  )
+  .expectBadge({
+    label: 'nexus',
+    message: isVersion,
+  })