store/cockpit/baseQuery: add cockpit baseQuery

Add a `cockpitBaseQuery` for api calls that need to be made against
the `cloudapi` on the osbuild-composer unix-socket. This function adds
an extra step of parsing the result and transforming it into JSON.

We need to wrap the `cockpit.http.request` call in a
Promise rather than async/await because cockpit rejects
the http request with two arguments (error & data/body)
and we need to handle this appropriately. It is not possible
to do this with a try/catch block
This commit is contained in:
Gianluca Zuccarelli 2025-01-20 11:32:13 +00:00 committed by Sanne Raymaekers
parent 8e58548385
commit 6b3b3ea3cc
4 changed files with 91 additions and 3 deletions

View file

@ -0,0 +1,67 @@
import { BaseQueryFn } from '@reduxjs/toolkit/query';
import cockpit from 'cockpit';
import type { Method, Params, Headers } from './types.js';
const cockpitApi = cockpit.http('/run/cloudapi/api.socket', {
superuser: 'try',
});
export const baseQuery =
(
{ baseUrl }: { baseUrl: string } = { baseUrl: '' }
): BaseQueryFn<
{
url: string;
method?: Method;
body?: unknown;
params?: Params;
headers?: Headers;
},
// we have to explicitly set the result type as `any`,
// since each of the endpoints might have a slightly
// different output. Unfortunately, typescript still
// complains if we try set the result type as `unknown`
// see the above comment
// eslint-disable-next-line @typescript-eslint/no-explicit-any
any,
unknown
> =>
async (options) => {
// we need to wrap this call in a Promise rather than
// async/await because cockpit rejects the http request
// with two arguments (error & data/body)
return new Promise((resolve, reject) => {
return cockpitApi
.request({
path: baseUrl + options.url,
body: options.body ?? '',
method: options.method ?? 'GET',
params: options.params,
headers: options.headers,
})
.then((result) => {
resolve({ data: JSON.parse(result) });
})
.catch(
// cockpit rejects the promise with two arguments.
// The first argument is the error, the second is the
// data object from the `osbuild-composer` error.
// This makes typescript unhappy.
// @ts-expect-error see above comment
(error: { message: string; problem: string }, data: string) => {
let body = data;
try {
body = JSON.parse(body);
} finally {
reject({
problem: error.problem,
message: error.message,
options,
body,
});
}
}
);
});
};

View file

@ -0,0 +1,4 @@
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Params = Record<string, any>;
export type Method = 'GET' | 'DELETE' | 'POST' | 'PUT' | 'PATCH'; // We can add more if we need
export type Headers = { [name: string]: string };

View file

@ -1,8 +1,11 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
import { createApi } from '@reduxjs/toolkit/query/react';
import { baseQuery } from './cockpit/baseQuery';
export const emptyCockpitApi = createApi({
reducerPath: 'cockpitApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api' }),
tagTypes: ['Composes'],
baseQuery: baseQuery({
baseUrl: '/api/image-builder-composer/v2',
}),
endpoints: () => ({}),
});

View file

@ -1,9 +1,18 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { Method, Headers, Params } from '../../../store/cockpit/types';
type userinfo = {
home: string;
};
type requestOptions = {
path: string;
method: Method;
body: unknown;
headers: Headers | undefined;
params: Params | undefined;
};
export default {
transport: {
host: '',
@ -40,6 +49,11 @@ export default {
post: (path: string, data: object, headers?: object): string => {
return '';
},
request: (request: requestOptions): Promise<string> => {
return new Promise((resolve) => {
resolve('');
});
},
};
},
};