API Client Generation: Add documentation (#102056)
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
## Generating RTK Query API Clients
|
||||
|
||||
To show the steps to follow, we are going to work on adding an API client to create a new dashboard. Just adapt the following guide to your use case.
|
||||
|
||||
### 1. Generate an OpenAPI snapshot
|
||||
|
||||
First, check if the `group` and the `version` are already present in [openapi_test.go](/pkg/tests/apis/openapi_test.go). If so, move on to the next step.
|
||||
<br/> If you need to add a new block, you can check for the right `group` and `version` in the backend API call that you want to replicate in the frontend.
|
||||
|
||||
```jsx
|
||||
{
|
||||
Group: "dashboard.grafana.app",
|
||||
Version: "v0alpha1",
|
||||
}
|
||||
```
|
||||
|
||||
Afterwards, you need to run the `TestIntegrationOpenAPIs` test. Note that it will fail the first time you run it. On the second run, it will generate the corresponding OpenAPI spec, which you can find in [openapi_snapshots](/pkg/tests/apis/openapi_snapshots).
|
||||
<br/>
|
||||
<br/>
|
||||
|
||||
> Note: You don’t need to follow these two steps if the `group` you’re working with is already in the `openapi_test.go` file.
|
||||
|
||||
<br/>
|
||||
|
||||
### 2. Create the API definition
|
||||
|
||||
In the `../public/app/features/{your_group_name}/api/` folder you have to create the `baseAPI.ts` file for your group. This file should have the following content:
|
||||
|
||||
```jsx
|
||||
import { createApi } from '@reduxjs/toolkit/query/react';
|
||||
|
||||
import { createBaseQuery } from 'app/api/createBaseQuery';
|
||||
import { getAPIBaseURL } from 'app/api/utils';
|
||||
|
||||
export const BASE_URL = getAPIBaseURL('dashboard.grafana.app', 'v0alpha1');
|
||||
|
||||
export const baseAPI = createApi({
|
||||
reducerPath: 'dashboardAPI',
|
||||
baseQuery: createBaseQuery({
|
||||
baseURL: BASE_URL,
|
||||
}),
|
||||
endpoints: () => ({}),
|
||||
});
|
||||
```
|
||||
|
||||
This is the API definition for the specific group you're working with, where `getAPIBaseURL` should have the proper `group` and `version` as parameters. The `reducePath` should also be modified to match `group + API`: `dashboard` will be `dashboardAPI`, `iam` will be `iamAPI` and so on.
|
||||
|
||||
### 3. Add the output information
|
||||
|
||||
Open [generate-rtk-apis.ts](scripts/generate-rtk-apis.ts) and add the following information:
|
||||
|
||||
| Data | Descritpion |
|
||||
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| outputFile name | File that will be created after running the API Client Generation script. It is the key of the object. |
|
||||
| apiFile | File with the group's API definition. |
|
||||
| schemaFile | File with the schema that was automatically created in the second step. Although it is in openapi_snapshots, you should link the one saved in `data/openapi`. |
|
||||
| apiImport | Function name exported in the API definition (baseAPI.ts file). |
|
||||
| filterEndpoints | The `operationId` of the particular route you want to work with. You can check the available operationIds in the specific group's spec file. As seen in the `migrate-to-cloud` one, it is an array |
|
||||
| tag | Must be set to `true`, to automatically attach tags to endpoints. This is needed for proper cache invalidation. See more info in the [official documentation](https://redux-toolkit.js.org/rtk-query/usage/automated-refetching#:~:text=RTK%20Query%20uses,an%20active%20subscription.). |
|
||||
|
||||
<br/>
|
||||
|
||||
> More info in [Redux Toolkit](https://redux-toolkit.js.org/rtk-query/usage/code-generation#simple-usage)
|
||||
|
||||
In our example, the information added will be:
|
||||
|
||||
```jsx
|
||||
'../public/app/features/dashboard/api/endpoints.gen.ts': {
|
||||
apiFile: '../public/app/features/dashboard/api/baseAPI.ts',
|
||||
schemaFile: '../data/openapi/dashboard.grafana.app-v0alpha1.json',
|
||||
apiImport: 'baseAPI',
|
||||
filterEndpoints: ['createDashboard', 'updateDashboard'],
|
||||
tag: true,
|
||||
},
|
||||
```
|
||||
|
||||
### 4. Run the API Client script
|
||||
|
||||
Then, we are ready to run the script to create the API client:
|
||||
|
||||
```jsx
|
||||
yarn generate-apis
|
||||
```
|
||||
|
||||
This will create an `endpoints.gen.ts` file in the path specified in the previous step.
|
||||
|
||||
### 5. Create the index file for your hooks
|
||||
|
||||
In the same `api` folder where the `endpoints.gen.ts` file has been saved, you have to create an index file from which you can import the types and hooks needed. By doing this, we selectively export hooks/types from `endpoints.gen.ts`.
|
||||
|
||||
In our case, the dashboard index will be like:
|
||||
|
||||
```jsx
|
||||
import { generatedAPI } from './endpoints.gen';
|
||||
|
||||
export const dashboardAPI = generatedAPI;
|
||||
export const { useCreateDashboardMutation, useUpdateDashboardMutation} = dashboardAPI;
|
||||
// eslint-disable-next-line no-barrel-files/no-barrel-files
|
||||
export { type Dashboard } from './endpoints.gen';
|
||||
|
||||
```
|
||||
|
||||
There are some use cases where the hook will not work, and that is a clue to see if it needs to be modified. The hooks can be tweaked by using `enhanceEndpoints`.
|
||||
|
||||
```jsx
|
||||
export const dashboardsAPI = generatedApi.enhanceEndpoints({
|
||||
endpoints: {
|
||||
// Need to mutate the generated query to set the Content-Type header correctly
|
||||
updateDashboard: (endpointDefinition) => {
|
||||
const originalQuery = endpointDefinition.query;
|
||||
if (originalQuery) {
|
||||
endpointDefinition.query = (requestOptions) => ({
|
||||
...originalQuery(requestOptions),
|
||||
headers: {
|
||||
'Content-Type': 'application/merge-patch+json',
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### 6. Add reducers and middleware to the Redux store
|
||||
|
||||
Last but not least, you need to add the middleware and reducers to the store.
|
||||
|
||||
In Grafana, the reducers are added to [`root.ts`](public/app/core/reducers/root.ts):
|
||||
|
||||
```jsx
|
||||
import { dashboardAPI } from '<pathToYourAPI>';
|
||||
const rootReducers = {
|
||||
...,
|
||||
[dashboardAPI.reducerPath]: dashboardAPI.reducer,
|
||||
};
|
||||
```
|
||||
|
||||
And the middleware is added to [`configureStore.ts`](public/app/store/configureStore.ts):
|
||||
|
||||
```jsx
|
||||
import { dashboardAPI } from '<pathToYourAPI>';
|
||||
export function configureStore(initialState?: Partial<StoreState>) {
|
||||
const store = reduxConfigureStore({
|
||||
reducer: createRootReducer(),
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({ thunk: true, serializableCheck: false, immutableCheck: false }).concat(
|
||||
...,
|
||||
dashboardAPI.middleware
|
||||
),
|
||||
...,
|
||||
});
|
||||
```
|
||||
|
||||
You have available the official documentation in [RTK Query](https://redux-toolkit.js.org/tutorials/rtk-query#add-the-service-to-your-store)
|
||||
|
||||
After this step is done, it is time to use your hooks across Grafana.
|
||||
Enjoy coding!
|
||||
Reference in New Issue
Block a user