In this article, we review RTK query usage in Meshery codebase. We will look at:
What is Meshery?
What is RTK Query?
RTK Query usage in Meshery.
I study patterns used in an open source project found on Github Trending. For this week, I reviewed some parts of Meshery codebase and wrote this article.
What is Meshery?
Meshery is the extensible Kubernetes manager. Meshery has 380+ Built-In integrations for your Cloud Native Infrastructure and Apps. Meshery seamlessly integrates with every CNCF project, your existing tools, multiple Clouds and Kubernetes clusters.
Learn more about https://meshery.io/
What is RTK Query?
RTK Query is a powerful data fetching and caching tool. It is designed to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
RTK Query is an optional addon included in the Redux Toolkit package, and its functionality is built on top of the other APIs in Redux Toolkit.
Basic usage
Create an API slice
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type { Pokemon } from './types'
// Define a service using a base URL and expected endpoints
export const pokemonApi = createApi({
reducerPath: 'pokemonApi',
baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
endpoints: (build) => ({
getPokemonByName: build.query<Pokemon, string>({
query: (name) => `pokemon/${name}`,
}),
}),
})
// Export hooks for usage in functional components, which are
// auto-generated based on the defined endpoints
export const { useGetPokemonByNameQuery } = pokemonApi
Configure the store
The “API slice” also contains an auto-generated Redux slice reducer and a custom middleware that manages subscription lifetimes. Both of those need to be added to the Redux store:
import { configureStore } from '@reduxjs/toolkit'
// Or from '@reduxjs/toolkit/query/react'
import { setupListeners } from '@reduxjs/toolkit/query'
import { pokemonApi } from './services/pokemon'
export const store = configureStore({
reducer: {
// Add the generated reducer as a specific top-level slice
[pokemonApi.reducerPath]: pokemonApi.reducer,
},
// Adding the api middleware enables caching, invalidation, polling,
// and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(pokemonApi.middleware),
})
// optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch)
Use hooks in components
import * as React from 'react'
import { useGetPokemonByNameQuery } from './services/pokemon'
export default function App() {
// Using a query hook automatically fetches data and returns query values
const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
// Individual hooks are also accessible under the generated endpoints:
// const { data, error, isLoading } = pokemonApi.endpoints.getPokemonByName.useQuery('bulbasaur')
// render UI based on data and loading state
}
Learn more about RTK Query.
RTK Query usage in Meshery.
In the above section, we learnt a simple RTK query usage example. Let’s see how Meshery has applied some of these concepts.
Create API Base:
You will find the below code at meshery/ui/rtk-query/index.js.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
export const api = createApi({
reducerPath: 'mesheryApi',
baseQuery: fetchBaseQuery({ baseUrl: '/api/' }),
endpoints: () => ({}),
});
Please note that all the APIs related to RTK query are located in rtk-query folder.
Create API slices:
Below code snippet is picked from meshery/ui/rtk-query/user.js
import { ctxUrl } from '@/utils/multi-ctx';
import { api } from './index';
import { initiateQuery } from './utils';
import { useGetOrgsQuery } from './organization';
import { useGetWorkspacesQuery } from './workspace';
const Tags = {
USER_PREF: 'userPref',
LOAD_TEST_PREF: 'loadTestPref',
PROVIDER_CAP: 'provider_capabilities',
};
export const userApi = api
.enhanceEndpoints({
addTagTypes: [Tags.USER_PREF, Tags.LOAD_TEST_PREF, Tags.PROVIDER_CAP],
})
.injectEndpoints({
endpoints: (builder) => ({
getLoadTestPrefs: builder.query({
query: (selectedK8sContexts) => ({
}),
providesTags: [Tags.LOAD_TEST_PREF],
// Transform response to directly get the loadTestPrefs
transformResponse: (response) => response?.loadTestPrefs || {},
}),
updateLoadTestPrefs: builder.mutation({
query: (queryArg) => ({
}),
invalidatesTags: [Tags.LOAD_TEST_PREF],
}),
...
Register the APIs in the store:
Below code is picked from meshery/ui/store/index.js
import eventsReducer from './slices/events';
import globalEnvironmentContextReducer from './slices/globalEnvironmentContext';
import { configureStore } from '@reduxjs/toolkit';
import { api } from '../rtk-query/index';
import mesheryUiReducer from './slices/mesheryUi';
import prefTestReducer from './slices/prefTest';
import telemetryReducer from './slices/telemetry';
import adapterReducer from './slices/adapter';
import { mesheryEventBus } from '@/utils/eventBus';
export const store = configureStore({
reducer: {
events: eventsReducer,
globalEnvironmentContext: globalEnvironmentContextReducer,
ui: mesheryUiReducer,
prefTest: prefTestReducer,
telemetry: telemetryReducer,
adapter: adapterReducer,
[api.reducerPath]: api.reducer,
},
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(api.middleware),
});
mesheryEventBus.on('DISPATCH_TO_MESHERY_STORE').subscribe((event) => {
console.log('Dispatching to Meshery Store:', event.data);
store.dispatch(event.data);
});
About me:
Hey, my name is Ramu Narasinga. I study codebase architecture in large open-source projects.
Email: ramu.narasinga@gmail.com
Want to learn from open-source? Solve challenges inspired by open-source projects.
Top comments (0)