Skip to content

Commit

Permalink
Add API v1 (#2595, #2425, #2331, #2066, #2062, #1762, #759, #394)
Browse files Browse the repository at this point in the history
This is a major rework of the API with a lot of breaking changes. Compared the the old API v0, API v1:

- is generated using a Jekyll Generator (see https://jekyllrb.com/docs/plugins/generators/),
- is versioned using the api/v1 prefix (#2066) and a schema_version field (#2331). This will make it easier to implement non-backward-compatible changes in API,
- feels more "Restful",
- and expose most of the products / tags / categories data (#2062, #2595)

The API v0 is still generated to give time to users to migrate to API v1. It will be removed a year or more. The only change is that the 404 JSON redirect rule had to be reverted because of incompatibilities with API v1 own redirect rules (#2425).

The API v1 documentation is available at /docs/api/v1/, but the tool used for the documentation is now swagger-ui. It fixed the issues we had with stoplight webcomponent on CSP, code example generation and icon on Firefox ESR (#1762). But swagger-ui imposed the downgrade of OpenAPI version from 3.1.0 to 3.0.3.

Changes between the two versions has been documented in the API_CHANGELOG.md files.

Note that we thought of disabling API generation in development (using JEKYLL_ENV like the Jekyll Feed plugin - see https://github.com/jekyll/jekyll-feed/blob/master/lib/jekyll-feed/generator.rb#L145), but it was finally reverted. It does not work well with Netlify preview, and generate production URL (i.e. https://endoflife.date URLs) in development which makes it difficult to use.
  • Loading branch information
marcwrobel committed Apr 1, 2023
1 parent 3d807db commit 48b49e3
Show file tree
Hide file tree
Showing 16 changed files with 828 additions and 89 deletions.
56 changes: 56 additions & 0 deletions CHANGELOG_API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## API v1.0.0

### Summary

API v1 is a major rework of the API v0 with a lot of breaking changes. Compared to the API v0, API v1:

- feels more "Restful",
- is versioned using the `api/v1` prefix, making it easier to implement non-backward-compatible
changes,
- is generated using a Jekyll Generator (see https://jekyllrb.com/docs/plugins/generators/).

API v1 resolves : #394, #759, #905, #2062, #2066, #2078, #2160, #2331, #2431, #2595. It also reverts
#2425 due to incompatibilities in redirect rules.

The API v0 is still generated to give time to users to migrate to API v1.

### Changes in the "All products" endpoint

- Path has been changed from `api/all.json` to `api/v1/products/`
- Response has been changed from a simple array to a JSON document. This made it possible to add endoflife-level data, such as the number of products.
- Array elements have been changed from a simple string to a full JSON document. This made it possible to expose new data, such as product category and tags (#2062).

### Changes in the "Product" endpoint

- Path has been changed from `api/<product>.json` to `api/v1/products/<product>/`.
- Response has been changed from a simple array to a JSON document. This made it possible to expose product-level data, such as product category and tags (#2062).
- Cycles data now always contain all the release cycles properties, even if they are null (example: `discontinued`, `latest`, `latestReleaseDate`, `support`...).

### Changes in the "Cycle" endpoint

- Path has been changed from `api/<product>/<cycle>.json` to `api/v1/products/<product>/cycles/<cycle>/`.
- Cycles data now always contain all the release cycles properties, even if they are null (example: `discontinued`, `latest`, `latestReleaseDate`, `support`...).
- A special `/api/v1/products/<product>/cycles/latest/` cycle, containing the same data as the latest cycle, has been added (#2078).

### Changes in 404 error responses

404 error JSON responses are not returned anymore. #2425 has been reverted because it conflicted
with the rule that rewrites the paths to add `/index.json` to all requests, which is also a global
rule and [takes precedence](https://docs.netlify.com/routing/redirects/#rule-processing-order).

### New endpoints

- `/api/v1/categories/` - list categories used on endoflife.date
- `/api/v1/categories/<category>` - list products having the given category
- `/api/v1/tags/` - list tags used on endoflife.date
- `/api/v1/tags/<tag>` - list products having the given tag



## API v0

On 2023-03-02 the v0 endpoints were:

- "All products" (`/api/all.json`) : Return a list of all products.
- "Product" (`/api/{product}.json`) : Get EoL dates of all cycles for a given product.
- "Cycle" (`/api/{product}/{cycle}.json`) : Details of a single release cycle of a given product.
8 changes: 7 additions & 1 deletion HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,13 @@ The API is just JSON files generated in the `api` directory by `_plugins/create-

### API Documentation

The API Documentation is available at <https://endoflife.date/docs/api> and is generated from an OpenAPI Specification file located at `_data/openapi.yml`. The documentation is rendered [Stoplight Elements](https://meta.stoplight.io/docs/elements/ZG9jOjMyNjU4OTY0-introduction-to-elements).
The current API v1 documentation is available at <https://endoflife.date/docs/api/v1/> and is
generated from an OpenAPI Specification file located at `api_v1/openapi.yml`. The documentation is
rendered by [Swagger UI](https://swagger.io/tools/swagger-ui/).

The old API v0 documentation is available at <https://endoflife.date/docs/api> and is
generated from an OpenAPI Specification file located at `assets/openapi.yml`. The documentation is
rendered by [Stoplight Elements](https://meta.stoplight.io/docs/elements/ZG9jOjMyNjU4OTY0-introduction-to-elements).

## Contributing Workflow

Expand Down
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ While participating in the project, you must abide by its [Code of Conduct](CODE

## API

An API is available for integration with CI platforms.
API documentation is available at https://endoflife.date/docs/api.
The API is currently in Alpha, and breaking changes can happen.
An API is available for integration with CI platforms. API documentation is available at https://endoflife.date/docs/api/v1/.
The API is currently in Beta, and breaking changes can happen.

## License

Expand All @@ -46,6 +45,8 @@ endoflife.date is relying on various amazing software and components :
- [Just the Docs](https://github.com/just-the-docs/just-the-docs), a documentation theme for Jekyll.
- [Stoplight Elements](https://stoplight.io/open-source/elements), a collection of UI components for
displaying beautiful developer documentation from any OpenAPI document.
- [Swagger UI](https://swagger.io/tools/swagger-ui/), a documentation generator for OpenAPI
Specification.
- [Simple Icons](https://simpleicons.org/), free SVG icons for popular brands.
- Our icon is derived from [Hourglass icon (orange)](https://commons.wikimedia.org/wiki/File:Hourglass_icon_%28orange%29.svg)
by David Abián and Serhio Magpie on the English Wikipedia. Remixed under the CC-BY-SA-4.0 license.
Expand Down
2 changes: 1 addition & 1 deletion _config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ aux_links:
source:
- https://github.com/endoflife-date/endoflife.date
api:
- /docs/api
- /docs/api/v1/
jekyll_timeago:
# Use 2 terms in relative timestamps:
# [YES] x years, y months
Expand Down
4 changes: 4 additions & 0 deletions _headers
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ layout: null
Content-Security-Policy: default-src 'none'; manifest-src 'self'; connect-src 'self'; script-src 'self'; style-src 'self'; img-src {{ defaultCspImgSrc }} {{ releaseImageSrc }}
Link: /api{{page.permalink}}.json; rel=alternate;type=application/json
Link: /calendar{{page.permalink}}.ics; rel=alternate;type=text/calendar
{% elsif page.permalink contains '/docs/api/v' %}
{%- comment %}Used contains to match all API version (startswith does not exist){% endcomment %}
# unsafe-inline and data: should not be an issue for a static site
Content-Security-Policy: default-src 'none'; manifest-src 'self'; connect-src 'self'; script-src 'self' 'unsafe-inline' https://unpkg.com/; style-src 'self' https://unpkg.com/; img-src 'self' data:
{% elsif page.permalink == '/docs/api' %}
Content-Security-Policy: default-src 'none'; manifest-src 'self'; connect-src 'self'; script-src 'self' https://unpkg.com/@stoplight/elements/web-components.min.js; style-src 'self' https://unpkg.com/@stoplight/elements/
{% else %}
Expand Down
1 change: 1 addition & 0 deletions _layouts/json.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{{ page.data | jsonify }}
4 changes: 2 additions & 2 deletions _layouts/product.html
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ <h1>{{ page.title }}</h1>
</p>

<p>
A JSON version of this page is available at <a href="/api{{page.permalink}}.json">/api{{page.permalink}}.json</a>.
See the <a href="/docs/api/">API Documentation</a> for more information.
A JSON version of this page is available at <a href="/api/v1/products{{page.permalink}}/">/api/v1/products{{page.permalink}}/</a>.
See the <a href="/docs/api/v1/">API Documentation</a> for more information.
You can subscribe to the iCalendar feed at <a href="webcal://{{site.url | split: '://' | last}}/calendar{{page.permalink}}.ics">/calendar{{page.permalink}}.ics</a>.
</p>
31 changes: 31 additions & 0 deletions _layouts/swagger-ui.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
layout: null
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ page.title }}</title>

<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@3/swagger-ui.css">
</head>

<body>
<div id="swagger-ui"></div>

<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-standalone-preset.js"></script>
<script>
window.onload = function () {
const ui = SwaggerUIBundle({
url: "{{ page.openapi_yml | absolute_url }}",
dom_id: '#swagger-ui',
deepLinking: true,
presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset],
plugins: [SwaggerUIBundle.plugins.DownloadUrl],
layout: "BaseLayout"
})
}
</script>
</body>
</html>
Loading

0 comments on commit 48b49e3

Please sign in to comment.