Exposing the Icon Theme through the REST API

Exposing the Icon Theme through the REST API

Hello Devs,

In order to use the icon theme in the Live Data extension (see https://jira.xwiki.org/browse/XWIKI-18605), we’d like to introduce a REST endpoint to resolve icons (see https://jira.xwiki.org/browse/XWIKI-18604).

The main goal is to allow JavaScript code to use the icons in conformity with the icon theme configurations.
The following endpoints will be introduced:

/xwiki/rest/wikis/{wikiName}/iconThemes/{iconTheme}/icons?icon=icon1&icon=icon2
/xwiki/rest/wikis/{wikiName}/iconThemes/icons?icon=icon1&icon=icon2

The endpoints should be called with the GET method.

Note: the iconThemes segment of the endpoints is open to debate and could also be named iconSets, which is closer to endusers terminology. Let me know which one you prefer (or other propositions of course).

The first one returns the icons metadata for the requested icon theme. The second one returns the icons metadata for the default icon theme.
The response (in json in the example, but jaxb is in charge of rendering in the requested format) is an object with two keys:

  • icons: an array of icons metadata object
  • missingIcons: an array of requested but not found icon names, this key is not included if all the requested icons are found.

The icons metadata objects has the following keys:

  • name: the icon name
  • iconSetName: the name of the icon set for which the metadata are resolved
  • cssClass: the set of css classes of the icon
  • iconSetType: FONT if the icons are made from a find, IMAGE if the icon is an image
  • url: the url of the icon’s image

The client side is in charge of generating the html required to display the icons according to their metadata.

This endpoint will be available in the newly introduced xwiki-platform-icon-rest module.

Some examples:

Query1:

/xwiki/rest/wikis/xwiki/iconThemes/icons?icon=add&icon=arrow_undo&icon=unknown

Response1:

{
  "icons": [
    {
      "name": "add",
      "iconSetName": "Font Awesome",
      "cssClass": "fa fa-plus",
      "iconSetType": "FONT",
      "url": ""
    },
    {
      "name": "arrow_undo",
      "iconSetName": "Font Awesome",
      "cssClass": "fa fa-undo",
      "iconSetType": "FONT",
      "url": ""
    }
  ],
  "missingIcons": [
    "unknown"
  ]
}

Query2:

/xwiki/rest/wikis/xwiki/iconThemes/Silk/icons?icon=add&icon=arrow_undo

Response2:

{
  "icons": [
    {
      "name": "add",
      "iconSetName": "Silk",
      "cssClass": "",
      "iconSetType": "IMAGE",
      "url": "/resources/icons/silk/add.png?cache-version=1617099790000"
    },
    {
      "name": "arrow_undo",
      "iconSetName": "Silk",
      "cssClass": "",
      "iconSetType": "IMAGE",
      "url": "/resources/icons/silk/arrow_undo.png?cache-version=1617099790000"
    }
  ]
}

WDYT?

Hi, you didn’t mention the HTTP verbs. I guess the examples above are using GET. What about POST, DELETE? Can we add icons to a set? Can we remove icons from a set?

So you’d count the number of path elements to differentiate these 2 calls? Or is that handled automatically by jaxrs?

Is that really following REST best practices? (open question, I don’t know if it is or not). I don’t see any REST resource having a path to a given icon. For example: /xwiki/rest/wikis/{wikiName}/iconThemes/{iconTheme}/icon/{iconName}

I had the same question for the localization REST endpoint proposal the other day but I forgot to ask. The general question is: should a REST path be complete and pointing to the resource asked vs having the resource specified as a query string parameter?

Asking just to be sure we’ve thought about it and have a strategy around this and to make sure we have consistent endpoints.

I’m also wondering about REST vs GraphQL.

Indeed, the current proposal it GET only. That does not prevent to introduce other HTTP verbs afterwards.

This is handled automatically by jaxrs.

IMO this is a correct endpoin, but that not for me to decide :slight_smile:

The proposed API present two [...]/icons endpoints, where the resource is a collection of icons (respectively from a specific icon set, and from the default icon set). This does not prevent to introduce [...]/icons/:iconName endpoints later, where the returned resource if a specific icon.

But that raises the question of what is returned when no icon parameters are passed.
We can either:

  • return nothing if we consider that we are performing an icons lookup
  • return the full list of icons, but in this case it is probably safer to return a paginated result and pagination parameters to avoid returning too large responses.

I am not sure where we stand regarding GraphQL. @surli and @Enygma worked on a GraphQL extension in August but it is documented as a WIP.

PS: Just read Best practices for REST API design - Stack Overflow Blog, very interesting.

Wouldn’t null (not sending it at all) make more sense than an empty string when the url make no sense for a specific icon ? Same for cssClass.

Apart from this little details it looks good.

Good catch, I’ll set null instead of the empty string when the value is not defined.

The proposed REST URL follows the collection/item pattern so it allows us to implement later a REST URL that targets a specific icon or translation key if we’re going to need it, but it’s not the case now (we don’t want to do N requests for N icons, we want a single request). The query string is used to filter the collection, i.e. to obtain a sub list of the collection that matches some criteria (e.g. first 10, all that start with something, etc.).

+1 for the proposal.

Thanks,
Marius

I guess that’s what I’m looking for. Would you have a link to this pattern? (I searched but couldn’t find it).

Thanks

See REST API Naming Conventions and Best Practices for instance. It’s actually collection / sub-collection / singleton.

Thanks @mflorea .

BTW I think it could be nicer to use name instead of icon as the query string parameter. The rationale is that an “icon” is more than just an name, it’s made of several fields:

Based on this, it looks like name would be the right query string parameter to filter on.

WDYT?

Also, it should probably be names since this input is a list and not a single element.

It’s proposed to be used like name=name1&name=name2&... so singular seems adequate.

That’s just how a list is formatted in a URL, but it’s still a list.

I personally would find it good to use names=name1&names=name2.... Do we use that elsewhere btw? AFAIR the translation REST endpoint proposal was not proposing that either.

Yes I did not notice that back then, but it’s a mistake IMO. All the APIs which are dealing with URL parameters are handling this as a parameter which contains a list (or an array) value. The REST API itself gets a List<String> as parameter as you can see in xwiki-platform/TranslationsResource.java at master · xwiki/xwiki-platform · GitHub.

The question is not what you get in the implementation code, but what you specify in the API, as a user and using plural would not make sense to me and would be counter-intuitive which is never good for an API.

I don’t get why using the plural for a parameter which have several values is counterintuitive. It seems to me you are fooled by the standard way to format lists in URLs. It’s the same as saying that list properties names should never use plural in xwiki.properties because we tend to format them as:

extension.repositories = maven-xwiki:maven:https://nexus.xwiki.org/nexus/content/groups/public
extension.repositories = store.xwiki.com:xwiki:https://store.xwiki.com/xwiki/rest/
extension.repositories = extensions.xwiki.org:xwiki:https://extensions.xwiki.org/xwiki/rest/

I think you’re too focused on the technical aspects rather than taking the user POV. But let’s see what others think. It seems that Manuel and Marius prefer the singular since they proposed that (unless they didn’t think about using the plural, but in any case the fact that they proposed singular first seems to indicate it’s the most natural). But let’s see what others think.

Actually I’m focused on standards and I would expect a user which format a URL to be a little technical.

You’re right. We’re filtering by icon name. I prefer the singular form but I guess I’d be OK with the plural form also. Singular is nicer when reading the URL, but the code that uses the URL will probably want to submit “names” (as an array) and not “name”.

I agree to use name instead of icon for the name parameters.
Regarding plural vs singular, tough I have a slight personal preference for the singular form.
I guess we can either find a existing best practice to follow (I haven’t found anything interesting so far), or define ours.