diff --git a/apps/mobile/openapi-config.ts b/apps/mobile/openapi-config.ts new file mode 100644 index 0000000..74b0e57 --- /dev/null +++ b/apps/mobile/openapi-config.ts @@ -0,0 +1,30 @@ +import type { ConfigFile } from '@rtk-query/codegen-openapi'; + +const EXCLUDED_OPERATIONS = [ + 'getImagesBkIEhN3PG', + 'getImagesByImageIdBreeds', + 'postImagesByImageIdBreeds', + 'deleteImagesByImageIdBreedsAndBreedId', +]; +const EXCLUDED_TAGS = ['Breeds', 'Facts', 'Webhooks']; + +const config: ConfigFile = { + schemaFile: + 'https://raw.githubusercontent.com/thatapicompany/apis/main/theCatAPI.com/thecatapi-oas.yaml', + apiFile: './src/store/services/EmptyApi.ts', + apiImport: 'EmptyApi', + outputFile: './src/store/services/PetApi.ts', + exportName: 'PetApi', + hooks: true, + tag: true, + filterEndpoints: (operationName, operationDefinition) => { + if (EXCLUDED_OPERATIONS.includes(operationName)) { + return false; + } + + const tagsForOperation = operationDefinition.operation.tags ?? []; + return !EXCLUDED_TAGS.some((tag) => tagsForOperation.includes(tag)); + }, +}; + +export default config; diff --git a/apps/mobile/src/store/services/EmptyApi.ts b/apps/mobile/src/store/services/EmptyApi.ts new file mode 100644 index 0000000..75d6899 --- /dev/null +++ b/apps/mobile/src/store/services/EmptyApi.ts @@ -0,0 +1,19 @@ +import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; + +// Initialize an empty API service that we'll inject endpoints into later +export const EmptyApi = createApi({ + baseQuery: fetchBaseQuery({ + baseUrl: 'https://api.thecatapi.com/v1/', + prepareHeaders: (headers) => { + // @TODO In a real app, this should throw an error to be handled by an ErrorBoundary + if (!process.env.EXPO_PUBLIC_CAT_API_KEY) { + console.error('No API key set for Cat API'); + return headers; + } + + headers.set('x-api-key', process.env.EXPO_PUBLIC_CAT_API_KEY); + return headers; + }, + }), + endpoints: () => ({}), +}); diff --git a/apps/mobile/src/store/services/PetApi.ts b/apps/mobile/src/store/services/PetApi.ts new file mode 100644 index 0000000..5b3cc7a --- /dev/null +++ b/apps/mobile/src/store/services/PetApi.ts @@ -0,0 +1,298 @@ +import { EmptyApi as api } from './EmptyApi'; +export const addTagTypes = ['Images', 'Favourites', 'Votes'] as const; +const injectedRtkApi = api + .enhanceEndpoints({ + addTagTypes, + }) + .injectEndpoints({ + endpoints: (build) => ({ + getImagesSearch: build.query< + GetImagesSearchApiResponse, + GetImagesSearchApiArg + >({ + query: (queryArg) => ({ + url: `/images/search`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + params: { + size: queryArg.size, + mime_types: queryArg.mimeTypes, + format: queryArg.format, + has_breeds: queryArg.hasBreeds, + order: queryArg.order, + page: queryArg.page, + limit: queryArg.limit, + }, + }), + providesTags: ['Images'], + }), + getImages: build.query({ + query: (queryArg) => ({ + url: `/images/`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + params: { + limit: queryArg.limit, + page: queryArg.page, + order: queryArg.order, + }, + }), + providesTags: ['Images'], + }), + postImagesUpload: build.mutation< + PostImagesUploadApiResponse, + PostImagesUploadApiArg + >({ + query: (queryArg) => ({ + url: `/images/upload`, + method: 'POST', + body: queryArg.body, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Images'], + }), + deleteImagesByImageId: build.mutation< + DeleteImagesByImageIdApiResponse, + DeleteImagesByImageIdApiArg + >({ + query: (queryArg) => ({ + url: `/images/${queryArg.imageId}`, + method: 'DELETE', + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Images'], + }), + getFavourites: build.query( + { + query: (queryArg) => ({ + url: `/favourites`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + providesTags: ['Favourites'], + } + ), + postFavourites: build.mutation< + PostFavouritesApiResponse, + PostFavouritesApiArg + >({ + query: (queryArg) => ({ + url: `/favourites`, + method: 'POST', + body: queryArg.body, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Favourites'], + }), + getFavouritesByFavouriteId: build.query< + GetFavouritesByFavouriteIdApiResponse, + GetFavouritesByFavouriteIdApiArg + >({ + query: (queryArg) => ({ + url: `/favourites/${queryArg.favouriteId}`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + providesTags: ['Favourites'], + }), + deleteFavouritesByFavouriteId: build.mutation< + DeleteFavouritesByFavouriteIdApiResponse, + DeleteFavouritesByFavouriteIdApiArg + >({ + query: (queryArg) => ({ + url: `/favourites/${queryArg.favouriteId}`, + method: 'DELETE', + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Favourites'], + }), + getVotes: build.query({ + query: (queryArg) => ({ + url: `/votes`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + providesTags: ['Votes'], + }), + postVotes: build.mutation({ + query: (queryArg) => ({ + url: `/votes`, + method: 'POST', + body: queryArg.body, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Votes'], + }), + getVotesByVoteId: build.query< + GetVotesByVoteIdApiResponse, + GetVotesByVoteIdApiArg + >({ + query: (queryArg) => ({ + url: `/votes/${queryArg.voteId}`, + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + providesTags: ['Votes'], + }), + deleteVoteByVoteId: build.mutation< + DeleteVoteByVoteIdApiResponse, + DeleteVoteByVoteIdApiArg + >({ + query: (queryArg) => ({ + url: `/vote/${queryArg.voteId}`, + method: 'DELETE', + headers: { + 'Content-Type': queryArg['Content-Type'], + 'x-api-key': queryArg['x-api-key'], + }, + }), + invalidatesTags: ['Votes'], + }), + }), + overrideExisting: false, + }); +export { injectedRtkApi as PetApi }; +export type GetImagesSearchApiResponse = /** status 200 OK */ object; +export type GetImagesSearchApiArg = { + 'Content-Type'?: string; + /** [optional] without it only the a basic set of images can be searched */ + 'x-api-key'?: string; + /** [optional] thumb , small, med or full - small is perfect for Discord */ + size?: string; + /** [optional] a comma separated strig of types to return e.g. jpg,png for static, or gif for gifs */ + mimeTypes?: string; + /** [optional] json | src */ + format?: string; + /** [optional] - only return images with breed data */ + hasBreeds?: boolean; + /** [optional] default:RANDOM - RANDOM | ASC | DESC */ + order?: string; + /** [optional] paginate through results */ + page?: number; + /** [optional] number of results to return, up to 25 with a valid API-Key */ + limit?: number; +}; +export type GetImagesApiResponse = /** status 200 OK */ object; +export type GetImagesApiArg = { + 'Content-Type'?: string; + /** - will return all the images from your account + */ + 'x-api-key': string; + /** [Optional] number of images to return valid 1 to 10 - default: 1 */ + limit?: number; + /** [Optional] only works if account_id is present to page through your own uploads */ + page?: number; + /** [Optional] only works if account_id is present, either ASC or DESC - ascending or descending. */ + order?: string; +}; +export type PostImagesUploadApiResponse = /** status 201 Created */ object; +export type PostImagesUploadApiArg = { + 'Content-Type'?: string; + /** - saves the uploaded image to your account. */ + 'x-api-key': string; + body: { + file?: Blob; + /** [optional] - a string you can use to segment your images, e.g. knowing which of your own users uploaded it. */ + sub_id?: string; + /** [optional] comma separated string of breed ids contained in the image */ + breed_ids?: string; + }; +}; +export type DeleteImagesByImageIdApiResponse = + /** status 200 Successful response */ Blob; +export type DeleteImagesByImageIdApiArg = { + 'Content-Type'?: string; + 'x-api-key'?: string; + imageId: string; +}; +export type GetFavouritesApiResponse = /** status 200 OK */ object; +export type GetFavouritesApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; +}; +export type PostFavouritesApiResponse = /** status 200 OK */ object; +export type PostFavouritesApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + body: object; +}; +export type GetFavouritesByFavouriteIdApiResponse = + /** status 200 Successful response */ Blob; +export type GetFavouritesByFavouriteIdApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + favouriteId: string; +}; +export type DeleteFavouritesByFavouriteIdApiResponse = + /** status 200 Successful response */ Blob; +export type DeleteFavouritesByFavouriteIdApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + favouriteId: string; +}; +export type GetVotesApiResponse = /** status 200 OK */ object; +export type GetVotesApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; +}; +export type PostVotesApiResponse = /** status 201 Created */ object; +export type PostVotesApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + body: object; +}; +export type GetVotesByVoteIdApiResponse = + /** status 200 Successful response */ Blob; +export type GetVotesByVoteIdApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + voteId: string; +}; +export type DeleteVoteByVoteIdApiResponse = + /** status 200 Successful response */ Blob; +export type DeleteVoteByVoteIdApiArg = { + 'Content-Type'?: string; + 'x-api-key': string; + voteId: string; +}; +export const { + useGetImagesSearchQuery, + useGetImagesQuery, + usePostImagesUploadMutation, + useDeleteImagesByImageIdMutation, + useGetFavouritesQuery, + usePostFavouritesMutation, + useGetFavouritesByFavouriteIdQuery, + useDeleteFavouritesByFavouriteIdMutation, + useGetVotesQuery, + usePostVotesMutation, + useGetVotesByVoteIdQuery, + useDeleteVoteByVoteIdMutation, +} = injectedRtkApi; diff --git a/bun.lockb b/bun.lockb index 500d43f..f966e99 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 76bd3a5..d85c09b 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@nx/jest": "20.0.0", "@nx/js": "20.0.0", "@nx/workspace": "20.0.0", + "@rtk-query/codegen-openapi": "^1.2.0", "@swc-node/register": "~1.9.1", "@swc/core": "~1.5.7", "@swc/helpers": "~0.5.11",