Foreman REST API version 3 initial thoughts

This is not an RFC because it’s not very concrete yet, but rather to gather thoughts.

Foreman has built API v2 on apipie-rails. This was developed by Foreman developers in a world where OpenAPI didn’t exist yet.

These days OpenAPI is an industry standard and a lot of tooling exists around it. apipie-rails has some support for OpenAPI, but only version 1. These days apipie-rails is not well maintained and we bear much of the maintenance burden. It may be better to look at other API frameworks to see what we can use instead of adding OpenAPI v3 support to apipie-rails.

On a more technical level the design is also not very flexible. Resources are not easily identified. For example, on a host you may find:

{
  "id": 1,
  "name": "host.example.com",
  "organization_id": 1,
  "organization_name": "Example Org"
}

It’s not easy to figure out the where to find the host resource itself. One example is the GitHub API which returns the URL and HTML URL to find the resources.

Then the organization should be an object as well that, again, can be easily found. A better structure would be:

{
  "id": 1,
  "name": "host.example.com",
  "url": "https://satellite.example.com/api/v3/hosts/1",
  "html_url": "https://satellite.com/hosts/1",
  "organization": {
    "id": 1,
    "name": "Example Org",
    "url": "https://satellite.example.com/api/v3/organizations/1",
    "html_url": "https://satellite.com/organizations/1"
  }
}

This allows the front end to easily add links to objects and get more information.

An example of where this would be useful is Fixes #38607 - Make the new implementation the default one by kmalyjur · Pull Request #990 · theforeman/foreman_remote_execution · GitHub.

A consideration that should be taken is to use href or url. Some APIs don’t include the full hostname in their responses but only the path.

Another consideration to be taken is integration. Today both Hammer and our Ansible collections use apipie to build a lot of the support. These should be updated to use OpenAPI if possible.

What are people’s thoughts on this topic?

Concrete question: we could start adding the structure to the existing APIv2, duplicating some information, but is that wise?

5 Likes

I am against adjusting the current API, it already has deprecations never removed and perhaps some other bloat.
So I think we should start fresh, add a more modern v3, after some releases giving Hammer and Ansible collections time to adjust we should deprecate v2 and remove it after the typical number of releases.

Talking about the deprecations in the API, should we in addition to global v3 add an internal API version where semantic versioning would allow for easier removal? Probably then we need an endpoint for this where every plugin registers its API version as there is not only central point where this would be needed?

If we update to a new api structure can we unify all the error types as well? so we dont have to do things like:
error.response?.data?.error?.message || error.response?.data?.error?.full_messages || error.response?.data?.error?.errors?.value[0] || error.response?.data?.errors?.value[0];
in the ui to cover all (some) of the options of where an error can be

1 Like

If we’re on the topic of fixing historical inconsistencies: let’s also make Katello align to Foreman in terms of pagination. In Fixes #37587 - Reuse API parameter handling from base by ekohl · Pull Request #11126 · Katello/katello · GitHub I highlighted the differences.

1 Like