feat(medusa): Nested Categories Admin List Endpoint (#2973)

* chore: added get route for admin categories API

* chore: add tree method to mock repository

* chore: added changeset to the PR

* chore: rename id to productCategoryId in service

* chore: switch cli option to string

* chore: lint fixes, tests for parent category

* chore: move Nested Categories behind feature flag

* chore: use transformQuery hook in api

* chore: add feature flag in migrations

* chore: remove migration FF, fix FF name

* chore: add free text search + count repo function

* chore: added list endpoint for admin

* chore: added changeset for feature

* chore: address pr review comments

* chore: change oas comment

* chore: add nullable parent category filter + test
This commit is contained in:
Riqwan Thamir
2023-01-10 12:52:31 +01:00
committed by GitHub
parent 4a50786fbc
commit f3ced106ad
11 changed files with 535 additions and 20 deletions
@@ -70,4 +70,4 @@ export default async (req: Request, res: Response) => {
res.status(200).json({ product_category: productCategory })
}
export class GetProductCategoryParams extends FindParams {}
export class AdminGetProductCategoryParams extends FindParams {}
@@ -1,10 +1,15 @@
import { Router } from "express"
import middlewares, { transformQuery } from "../../../middlewares"
import getProductCategory, {
GetProductCategoryParams,
} from "./get-product-category"
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
import getProductCategory, {
AdminGetProductCategoryParams,
} from "./get-product-category"
import listProductCategories, {
AdminGetProductCategoriesParams,
} from "./list-product-categories"
const route = Router()
export default (app) => {
@@ -14,9 +19,19 @@ export default (app) => {
route
)
route.get(
"/",
transformQuery(AdminGetProductCategoriesParams, {
defaultFields: defaultProductCategoryFields,
defaultRelations: defaultAdminProductCategoryRelations,
isList: true,
}),
middlewares.wrap(listProductCategories)
)
route.get(
"/:id",
transformQuery(GetProductCategoryParams, {
transformQuery(AdminGetProductCategoryParams, {
defaultFields: defaultProductCategoryFields,
isList: false,
}),
@@ -27,6 +42,7 @@ export default (app) => {
}
export * from "./get-product-category"
export * from "./list-product-categories"
export const defaultAdminProductCategoryRelations = [
"parent_category",
@@ -0,0 +1,118 @@
import { IsNumber, IsOptional, IsString } from "class-validator"
import { Request, Response } from "express"
import { Type, Transform } from "class-transformer"
import { ProductCategoryService } from "../../../../services"
import { extendedFindParamsMixin } from "../../../../types/common"
/**
* @oas [get] /product-categories
* operationId: "GetProductCategories"
* summary: "List Product Categories"
* description: "Retrieve a list of product categories."
* x-authenticated: true
* parameters:
* - (query) q {string} Query used for searching product category names orhandles.
* - (query) is_internal {boolean} Search for only internal categories.
* - (query) is_active {boolean} Search for only active categories
* - (query) parent_category_id {string} Returns categories scoped by parent
* - (query) offset=0 {integer} How many product categories to skip in the result.
* - (query) limit=100 {integer} Limit the number of product categories returned.
* x-codeSamples:
* - lang: JavaScript
* label: JS Client
* source: |
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.productCategories.list()
* .then(({ product_category, limit, offset, count }) => {
* console.log(product_category.length);
* });
* - lang: Shell
* label: cURL
* source: |
* curl --location --request GET 'https://medusa-url.com/admin/product-categories' \
* --header 'Authorization: Bearer {api_token}'
* security:
* - api_token: []
* - cookie_auth: []
* tags:
* - Product Categories
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* product_category:
* type: array
* items:
* $ref: "#/components/schemas/ProductCategory"
* count:
* type: integer
* description: The total number of items available
* offset:
* type: integer
* description: The number of items skipped before these items
* limit:
* type: integer
* description: The number of items per page
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*/
export default async (req: Request, res: Response) => {
const productCategoryService: ProductCategoryService = req.scope.resolve(
"productCategoryService"
)
const [data, count] = await productCategoryService.listAndCount(
req.filterableFields,
req.listConfig
)
const { limit, offset } = req.validatedQuery
res.json({
count,
product_categories: data,
offset,
limit,
})
}
export class AdminGetProductCategoriesParams extends extendedFindParamsMixin({
limit: 100,
offset: 0,
}) {
@IsString()
@IsOptional()
q?: string
@IsString()
@IsOptional()
is_internal?: boolean
@IsString()
@IsOptional()
is_active?: boolean
@IsString()
@IsOptional()
@Transform(({ value }) => {
return value === "null" ? null : value
})
parent_category_id?: string | null
}