diff --git a/generators/src/main/java/com/algolia/codegen/utils/Helpers.java b/generators/src/main/java/com/algolia/codegen/utils/Helpers.java index 9ebe38c88a1..57e65f8ebb0 100644 --- a/generators/src/main/java/com/algolia/codegen/utils/Helpers.java +++ b/generators/src/main/java/com/algolia/codegen/utils/Helpers.java @@ -175,7 +175,7 @@ public static void removeHelpers(OperationsMap operations) { /** * Get the current version of the given client from the * `clients/algoliasearch-client-javascript/packages/${client}/package.json` file, defaults to - * 0.0.1 if not found + * 0.0.1-alpha.0 if not found */ public static String getPackageJsonVersion(String client) throws ConfigException { try { @@ -183,12 +183,12 @@ public static String getPackageJsonVersion(String client) throws ConfigException String value = packageJson.get("version").asText(); if (value.isEmpty()) { - return "0.0.1"; + return "0.0.1-alpha.0"; } return value; } catch (ConfigException e) { - return "0.0.1"; + return "0.0.1-alpha.0"; } } diff --git a/website/docs/docs.md b/website/docs/add-a-new-api/api-documentation-guidelines.md similarity index 99% rename from website/docs/docs.md rename to website/docs/add-a-new-api/api-documentation-guidelines.md index 368a696529f..7c4900bd9d0 100644 --- a/website/docs/docs.md +++ b/website/docs/add-a-new-api/api-documentation-guidelines.md @@ -1,5 +1,5 @@ --- -title: API documentation +title: API documentation guidelines description: Guidelines for writing API documentation for Algolia's APIs. --- @@ -14,7 +14,7 @@ For more general documentation guidelines, see the [Google developer documentation style guide](https://developers.google.com/style). For information on how to structure spec files to support a new API client, -see [Add a new API client](./add-new-api-client.md). +see [Add a new API client](/docs/add-a-new-language). ## Prefer plain text diff --git a/website/docs/add-a-new-api/generate-your-client.md b/website/docs/add-a-new-api/generate-your-client.md new file mode 100644 index 00000000000..8d75dc845a6 --- /dev/null +++ b/website/docs/add-a-new-api/generate-your-client.md @@ -0,0 +1,57 @@ +--- +title: Generate your client +--- + +:::info + +Make sure to first read the [setup the repository tooling section](/docs/setup-repository) first. + +This section is only about **adding to the existing API clients**, to support a new programming language, see [Support a new language](/docs/add-a-new-language). + +::: + +## Configuration file + +> Most of the configuration is determined by the api-clients-automation CLI (`scripts/`). + +The file [`config/clients.config.json`](https://github.com/algolia/api-clients-automation/blob/main/config/clients.config.json) contains information that's common to all clients generated for each language, you can [find its JSON schema here](https://github.com/algolia/api-clients-automation/blob/main/config/clients.schema.json). + +## CLI Commands + +Use the CLI to generate your client: + +- [Commands for working with clients](/docs/CLI/generate-commands) + +## Generate a pre-release client + +:::info + +Only the JavaScript client releases standalone packages along with the main `algoliasearch` package, so it's the only possible "generated" solution for pre-releases (alpha or beta). + +::: + +1. [Update the configuration file](https://github.com/algolia/api-clients-automation/blob/main/config/clients.config.json#L131) + +The `clients` field define which specification to generate and their output location. In order to create a pre-release for your API, it needs to be standalone only (non bundled with `algoliasearch`). + +```json +{ + "name": "awesomeapi", // this must match the name of the specification + "output": "clients/algoliasearch-client-javascript/packages/awesomeapi", // make sure to keep everything in `clients/algoliasearch-client-javascript/packages/` + "isStandaloneClient": true // this tells the generator not to put it in the `algoliasearch` bundle +}, +``` + +2. Generate your client + +With just the above changes, you can now run `yarn cli generate -h` which should output a complete list of the available APIs for Javascript, `awesomeapi` should be in it. + +Running `yarn cli generate javascript awesomeapi` will generate the client and format it, and `yarn cli build clients javascript awesomeapi` will bundle it. + +3. Test the client + +At least one test per operation is required, you can read more about it in the [Common Test Suite section](/docs/testing/common-test-suite.md). + +4. Release + +We take care of it, open your pull request :) diff --git a/website/docs/add-a-new-api/write-a-specification.md b/website/docs/add-a-new-api/write-a-specification.md new file mode 100644 index 00000000000..8172ad0fe98 --- /dev/null +++ b/website/docs/add-a-new-api/write-a-specification.md @@ -0,0 +1,135 @@ +--- +title: Write an OpenAPI specification +--- + +:::info + +Algolia's API specs follow the [OpenAPI specification, version 3.1](https://spec.openapis.org/oas/v3.1.0). + +Starting from an existing specification **really eases the contribution process and is recommended** (e.g. [search](https://github.com/algolia/api-clients-automation/blob/main/specs/search/)) + +**Do not edit the files in [`specs/bundled`](https://github.com/algolia/api-clients-automation/blob/main/specs/bundled)** they are the generated from the manually written specifications, and only used to generate API clients. + +::: + +:::caution + +A specification is used to generate the API client, its tests and code snippets, but is most importantly served by [the Algolia public documentation](https://www.algolia.com/doc/api-reference/rest-api/), please read our [API Documentation guidelines](./api-documentation-guidelines.md) to properly document your specification. + +::: + +# Structure your specification + +Each API specification follows a consistent structure. + +## `specs/common/` + +This [common directory](https://github.com/algolia/api-clients-automation/blob/main/specs/common/) contains schemas and parameters that are common to multiple Algolia APIs, for example: search parameters or indexName definitions. + +## `specs//` + +Each API must be contained in its own directory, for example: [the Search API](https://github.com/algolia/api-clients-automation/blob/main/specs/search/). + +### `specs//spec.yml` + +This file is the main entrypoint of your specification and should describe your API, including the `servers`, `securitySchemes` and `paths` properties. + +### `specs//common/` + +This directory contains schemas and parameters that are common to **your API**. +For schemas that are shared between multiple APIs please use the global [`specs/common`](#specscommon) directory. + +### `specs//paths/` + +This directory contains the descriptions of the **endpoints** of your API. +The paths themselves are defined in the [`spec.yml`](#specsapinamespecyml) file. + +#### `specs//paths/.yml` + +Operations are endpoints combined with an HTTP method (`GET`, `POST`, etc.). +Each operation must have a unique `operationID` property. +Operations for the same endpoint may share the same file, for example, the `GET` and `DELETE` request for the same endpoint. + +##### Filenames + +Follow these conventions: + +- If the file only contains one operation, use `.yml` as filename. +- If the file contains multiple operations, use a more generic name, for example [`rule.yml`](https://github.com/algolia/api-clients-automation/blob/main/specs/search/paths/rules/rule.yml) for the `GET`, `PUT`, and `DELETE` request for a rule. + +##### Summaries and descriptions + +Every operation must have a `summary` and `description` property (they will be used in the generated API clients, and the Algolia documentation). +For information about documenting operations, see [Operation summaries](/docs/add-a-new-api/api-documentation-guidelines#operation-summaries) and [Operation descriptions](./api-documentation-guidelines.md#operation-descriptions). + +##### Access Control Lists (ACL) + +Each operation should include an `x-acl` property +to document the ACL required to make the request. + +The `x-acl` property is an array of strings, the allowed values are: `search`, `browse`, `addObject`, `deleteObject`, `listIndexes`, `deleteIndex`, `settings`, `editSettings`, `analytics`, `recommendation`, `usage`, `logs`, `setUnretrievableAttributes`, `admin`. +For operations that require the admin API key, use `admin` + +##### Complex objects + +The following objects must not be inlined, but referenced with `$ref`: + +- Nested arrays +- Nested objects +- `oneOf` +- `allOf` +- `enum` + +This is required for accurate naming of the generated code objects. +It also improves the readability of the specs. + +##### Properties and parameters + +- Create separate objects and reference them for [complex objects](#complex-objects). +- The `format` parameter for strings isn't supported. +- For **nullable properties**, use the following syntax: + + ```yaml + nullableProp: + default: null + oneOf: + - type: string + description: Some value + - type: 'null' + description: The single quotes are required. + ``` + +For information about documenting properties and parameters, see [Properties and parameters](/docs/add-a-new-api/api-documentation-guidelines#properties-and-parameter-descriptions). + +## CLI Commands + +Use the CLI to generate build your specs: + +- [Commands for working with specs](/docs/CLI/build-commands) + +## Troubleshooting + +### Explicit names for request bodies + +> [Detailed issue](https://github.com/algolia/api-clients-automation/issues/891) + +In some cases, the generated name for the `requestBody` property might be wrong. +This can happen in these cases: + +- The type is too complex or too broad to be correctly generated, + for example, [an object with `additionalProperties`](https://github.com/algolia/api-clients-automation/tree/main/specs/search/paths/objects/partialUpdate.yml#L24-L33). + +- The type is an alias of its model, + for example, [a list of `model`](https://github.com/algolia/api-clients-automation/tree/main/specs/search/paths/rules/saveRules.yml#L12-L20). + +To provide a name for the request body, add the [`x-codegen-request-body-name`](https://openapi-generator.tech/docs/swagger-codegen-migration/#body-parameter-name) property to the root of the operation's spec file. + +For an example, see [pull request #896](https://github.com/algolia/api-clients-automation/pull/896). + +### Send additional options to the templates + +To send additional information to the generators, +you can add properties starting with `x-` to the root level of your spec. +These are available in the templates as part of the `vendorExtensions` object. + +For an example, see [`search.yml`](https://github.com/algolia/api-clients-automation/blob/main/specs/search/paths/search/search.yml#L5-L7) diff --git a/website/docs/add-new-language.md b/website/docs/add-a-new-language.md similarity index 93% rename from website/docs/add-new-language.md rename to website/docs/add-a-new-language.md index aa00c449adb..c16abd2f5ae 100644 --- a/website/docs/add-new-language.md +++ b/website/docs/add-a-new-language.md @@ -1,5 +1,5 @@ --- -title: Support a new language +title: Add a new language --- :::info @@ -28,10 +28,6 @@ Example for the `JavaScript` client with the `typescript-node` template: apic exec java "yarn openapi-generator-cli author template -g typescript-node -o templates/javascript/" ``` -## Update the generator config - -Please read the [`add a new client guide`](/docs/add-new-api-client) for information on how to structure your new client and setup the configuration files. - ### Algolia requirements :::caution @@ -71,8 +67,6 @@ The retry strategy cannot be generated and needs to be implemented outside of th Some Algolia clients (search and recommend) targets the default appId host (`${appId}-dsn.algolia.net`, `${appId}.algolia.net`, etc.), while clients like `personalization` have their own regional `host` (`eu` | `us` | `de`). -As the generator does not support reading `servers` in a spec file **yet**, hosts methods and variables are extracted with a custom script and create variables for you to use in the mustache templates, [read more here](/docs/add-new-api-client#2-configure-the-generator). - ### User Agent The header 'User-Agent' must respect a strict pattern of a base, client, plus additional user defined segments: diff --git a/website/docs/add-new-api-client.md b/website/docs/custom-helpers.md similarity index 51% rename from website/docs/add-new-api-client.md rename to website/docs/custom-helpers.md index fc6a9cb554d..a0e0608a0e5 100644 --- a/website/docs/add-new-api-client.md +++ b/website/docs/custom-helpers.md @@ -1,191 +1,15 @@ --- -title: Add new API clients +title: Custom helpers --- -:::info - -First, [setup the repository tooling](./setup-repository.md) so that you can lint, test, and preview documentation on your computer. - -::: - -To add a new API client in a supported programming language, you need to run these steps: - -1. [Write specs](#1-write-specs) -2. [Configure the generator](#2-configure-the-generator) -3. [Generate the client](#3-generate-the-client) -4. [Add tests](#4-add-tests-with-the-common-test-suite) -5. [Helpers](#5-helpers) - -For more information about adding support for a new programming language, see [Support a new language](./add-new-language.md). - -## 1. Write specs - -Algolia's API specs follow the [OpenAPI specification, version 3.1](https://spec.openapis.org/oas/v3.1.0). - -To add a new spec, it's best to start from an [existing one](https://github.com/algolia/api-clients-automation/blob/main/specs/). - -> Don't edit files in the `specs/bundled/` directory. -> These files are auto-generated and your changes will be overwritten. - -### How to organize the specs - -Each API spec follows a consistent structure. - -#### `specs/common/` - -The [`common`](https://github.com/algolia/api-clients-automation/blob/main/specs/common/) directory contains schemas and parameters that are common to many Algolia APIs. - -#### `specs//` - -Each API is in its own directory. - -For an example, see the [Search API](https://github.com/algolia/api-clients-automation/blob/main/specs/search/) directory. - -#### `specs//spec.yml` - -The `spec.yml` file contains the general description of the API, -including the `servers` and `paths` properties. - -To get started, copy an existing file, for example, from the [Search API](https://github.com/algolia/api-clients-automation/blob/main/specs/search/spec.yml). - -For information about documenting the API, see [API descriptions](./docs.md#api-descriptions). - -#### `specs//common/` - -This directory contains schemas and parameters that are common to endpoints of the current API. -For schemas that are shared between multiple APIs, see the global [`specs/common`](#specscommon) directory. - -#### `specs//paths/` - -This directory contains the descriptions of the **endpoints** of the API. -The paths themselves are defined in the [`spec.yml`](#specsapinamespecyml) file. - -### Guidelines for operations - -Operations are endpoints combined with an HTTP method (`GET`, `POST`, etc.). -Each operation must have a unique `operationID` property. -Operations for the same endpoint may share the same file, for example, the `GET` and `DELETE` request for the same endpoint. - -Every operation must have a `summary` and `description` property. -For information about documenting operations, see [Operation summaries](./docs.md#operation-summaries) and [Operation descriptions](./docs.md#operation-descriptions). - -#### Filenames - -Follow these conventions: - -- If the file only contains one operation, use `.yml` as filename. -- If the file contains multiple operations, use a more generic name, for example [`rule.yml`](https://github.com/algolia/api-clients-automation/blob/main/specs/search/paths/rules/rule.yml) for the `GET`, `PUT`, and `DELETE` request for a rule. - -#### Access control lists (ACL) - -Each operation should include an `x-acl` property -to document the ACL required to make the request. - -The `x-acl` property is an array of strings. -For operations that require the admin API key, use `admin`. - -#### Complex objects - -The following objects must not be inlined, but referenced with `$ref`: - -- Nested arrays -- Nested objects -- `oneOf` -- `allOf` -- `enum` - -This is required for accurate naming of the generated code objects. -It also improves the readability of the specs. - -### Guidelines for properties and parameters - -- Create separate objects and reference them for [complex objects](#complex-objects). -- The `format` parameter for strings isn't supported. -- For **nullable properties**, use the following syntax: - - ```yaml - nullableProp: - default: null - oneOf: - - type: string - description: Some value - - type: 'null' - description: The single quotes are required. - ``` - -For information about documenting properties and parameters, see [Properties and parameters](/docs/docs#properties-and-parameter-descriptions). - -### Troubleshooting - -#### Explicit names for request bodies - -> [Detailed issue](https://github.com/algolia/api-clients-automation/issues/891) - -In some cases, the generated name for the `requestBody` property might be wrong. -This can happen in these cases: - -- The type is too complex or too broad to be correctly generated, - for example, [an object with `additionalProperties`](https://github.com/algolia/api-clients-automation/tree/main/specs/search/paths/objects/partialUpdate.yml#L24-L33). - -- The type is an alias of its model, - for example, [a list of `model`](https://github.com/algolia/api-clients-automation/tree/main/specs/search/paths/rules/saveRules.yml#L12-L20). - -To provide a name for the request body, add the [`x-codegen-request-body-name`](https://openapi-generator.tech/docs/swagger-codegen-migration/#body-parameter-name) property to the root of the operation's spec file. - -For an example, see [pull request #896](https://github.com/algolia/api-clients-automation/pull/896). - -#### Send additional options to the templates - -To send additional information to the generators, -you can add properties starting with `x-` to the root level of your spec. -These are available in the templates as part of the `vendorExtensions` object. - -For an example, see [`search.yml`](https://github.com/algolia/api-clients-automation/blob/main/specs/search/paths/search/search.yml#L5-L7) - -## 2. Configure the generator - -> Most of the configuration is "guessed" by the api-clients-automation CLI (`scripts/`). - -### Configuration file - -The file [`config/clients.config.json`](https://github.com/algolia/api-clients-automation/blob/main/config/clients.config.json) contains information that's common to all clients generated for each language. - -The following fields are required: - -| Option | Description | -| ---------------------- | ------------------------------------------------------------------------------------------------- | -| `clients` | The clients to generate, either a list of string (matching the api name), or see below | -| `clients.name` | The name of the client to generate (matching the API name) | -| `clients.output` | The output folder | -| `folder` | Path to the parent folder of every client for this language. | -| `gitRepoId` | Name of the repository for this API client. | -| `packageVersion` | Initial version number to publish for the generated client. It will be automatically incremented. | -| `modelFolder` | Path to the `model` folder that will host the generated code. | -| `apiFolder` | Path to the `api` folder that will host the generated code. | -| `dockerImage` | The name of the docker image that runs this client `apic_base` | `apic_ruby` | `apic_swift` | -| `tests.extension` | Test file extension, such as `.test.java` or `_test.py` | -| `tests.outputFolder` | Path to the folder that holds the tests for this language, such as `tests/` | -| `snippets.extension` | Snippet file extension, such as `.java` or `.py` | -| `snippets.outputFolder`| Path to the folder that holds the snippets for this language, such as `lib/` | - -## 3. Generate the client - -Use the CLI to generate the clients: - -- [Commands for working with specs](./CLI/build-commands.md) -- [Commands for working with clients](./CLI/generate-commands.md) - -## 4. Add tests with the Common Test Suite - -You must add tests for your clients. -For more information, see [Common Test Suite](./testing/common-test-suite.md). - -## 5. Helpers - -The API clients have hand-written helpers for tasks that would otherwise require custom code. +The API clients provide many hand-written helpers for tasks that would otherwise require custom code or global knowledge of how the Algolia API works. | Helper name | Description | Wrapped API call | Stop condition | Example | | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `customPut` | Makes a fully customizable PUT API call to the current API. | none | none | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | +| `customGet` | Makes a fully customizable GET API call to the current API. | none | none | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | +| `customPost` | Makes a fully customizable POST API call to the current API. | none | none | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | +| `customDelete` | Makes a fully customizable DELETE API call to the current API. | none | none | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | | `waitForTask` | Given a `taskID`, calls the `getTask` method until the status gets `published` | `getTask()` | `response.status == "published"` | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | | `waitForAppTask` | Given a `taskID`, calls the `getAppTask` method until the status gets `published` | `getAppTask()` | `response.status == "published"` | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | | `waitForApiKey` | Given a `Key`, calls the `getApiKey` method until the stop condition for the given `operation` is validated | `getApiKey()` | Diff between the given `Key` and the `response` payload | [JavaScript](https://github.com/algolia/api-clients-automation/blob/main/clients/algoliasearch-client-javascript/packages/client-search/src/searchClient.ts) | @@ -201,14 +25,17 @@ The API clients have hand-written helpers for tasks that would otherwise require | `deleteObjects` | Deletes every records for the given objectIDs. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objectIDs in it. | `batch()` | `none` | [Go](https://github.com/algolia/api-clients-automation/blob/main/templates/go/search_helpers.mustache) | | `partialUpdateObjects` | Replaces object content of all the given objects according to their respective `objectID` field. The `chunkedBatch` helper is used under the hood, which creates a `batch` requests with at most 1000 objects in it. | `batch()` | `none` | [Go](https://github.com/algolia/api-clients-automation/blob/main/templates/go/search_helpers.mustache) | -### `replaceAllObjects` +## Complex usage descrpition :::info -This section explains the decision over the implementation of the helper, as it's quite tricky the get the order right +This section explains the decision over the implementation of complicated helper, self-explanatory ones might not be listed. ::: + +### `replaceAllObjects` + :::caution Always wait on the tmp index, because: diff --git a/website/docs/introduction.md b/website/docs/introduction.md index daeea613fa2..8568915338c 100644 --- a/website/docs/introduction.md +++ b/website/docs/introduction.md @@ -12,8 +12,8 @@ To contribute to the repository, make sure to take a look at our guidelines and - [Setup the repository tooling](/docs/setup-repository): to install our tooling. - CLI commands can be found at [CLI > build commands](/docs/CLI/build-commands), [CLI > generate commands](/docs/CLI/generate-commands) and [CLI > CTS commands](/docs/CLI/cts-commands). -- [Add a new client](/docs/add-new-api-client): to add a new API spec to generate a client. -- [Support a new language](/docs/add-new-language): to add a new supported language to the API clients. +- [Add a new API](/docs/add-a-new-api/write-a-specification): to add your API specification to an existing API client. +- [Add a new language](/docs/add-a-new-language): to add support for a new language to the API clients. - [Commit and Pull-request](/docs/commit-and-pull-request): to see what to commit and send pull-requests. - [Release process](/docs/release-process): to see how to release API clients. diff --git a/website/docs/setup-repository.md b/website/docs/setup-repository.md index c3749fb5b46..ee65e30b2e2 100644 --- a/website/docs/setup-repository.md +++ b/website/docs/setup-repository.md @@ -49,8 +49,8 @@ docker compose down --rmi all Once you've successfully built and mounted the Docker image, you can now play with the repository! Read our guides on: -- [How to add a new client](/docs/add-new-api-client) -- [How to add a new language](/docs/add-new-language) +- [How to add a new API to an existing client](/docs/add-a-new-api/write-a-specification) +- [Add a new language](/docs/add-a-new-language) - [Use CLI specs commands](/docs/CLI/build-commands) - [Use CLI clients commands](/docs/CLI/generate-commands) - [Use CLI release commands](/docs/CLI/release-commands) diff --git a/website/sidebars.js b/website/sidebars.js index cb028f4e654..0f6c7e327ac 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -24,15 +24,20 @@ const sidebars = { label: 'Contributing', collapsed: false, items: [ - 'add-new-api-client', - 'docs', - 'add-new-language', + { + type: 'category', + label: 'Add a new API', + collapsed: false, + items: ['add-a-new-api/write-a-specification', 'add-a-new-api/generate-your-client', 'add-a-new-api/api-documentation-guidelines'], + }, + 'add-a-new-language', { type: 'category', label: 'Testing', collapsed: false, items: ['testing/common-test-suite', 'testing/playground'], }, + 'custom-helpers', 'commit-and-pull-request', 'release-process', { diff --git a/website/src/css/custom.css b/website/src/css/custom.css index 66bb11317f0..0cc0b29dc7e 100644 --- a/website/src/css/custom.css +++ b/website/src/css/custom.css @@ -139,3 +139,10 @@ html[data-theme='dark'] .header-github-link:before { margin: 0 calc(-1 * var(--ifm-pre-padding)); padding: 0 var(--ifm-pre-padding); } + +#button { + padding: 10px; + border-radius: 3px; + margin: 0 3px 0 3px; + background-color: var(--nebula-500); +} diff --git a/website/src/pages/index.js b/website/src/pages/index.js index 282ecf83e28..c1bb7a21bd7 100644 --- a/website/src/pages/index.js +++ b/website/src/pages/index.js @@ -14,7 +14,7 @@ function Hero() { + ,