Requested changes

This commit is contained in:
Catalin Pinte 2022-10-03 10:41:40 +03:00
parent e522ec1100
commit 2f0cb89bcb
7 changed files with 52 additions and 44 deletions

View File

@ -1,5 +1,5 @@
import type { ProductsSchema } from '../../../types/product' import type { ProductsSchema } from '../../../types/product'
import { getErrorMessage } from '../../utils/errors' import { CommerceAPIError } from '../../utils/errors'
import isAllowedOperation from '../../utils/is-allowed-operation' import isAllowedOperation from '../../utils/is-allowed-operation'
import type { GetAPISchema } from '../..' import type { GetAPISchema } from '../..'
@ -18,7 +18,12 @@ const productsEndpoint: GetAPISchema<
return await handlers['getProducts']({ ...ctx, body }) return await handlers['getProducts']({ ...ctx, body })
} catch (error) { } catch (error) {
console.error(error) console.error(error)
const message = getErrorMessage(error)
const message =
error instanceof CommerceAPIError
? 'An unexpected error ocurred with the Commerce API'
: 'An unexpected error ocurred'
res.status(500).json({ data: null, errors: [{ message }] }) res.status(500).json({ data: null, errors: [{ message }] })
} }
} }

View File

@ -1,5 +1,5 @@
import type { LoginSchema } from '../../types/login' import type { LoginSchema } from '../../types/login'
import { CommerceAPIError, getErrorMessage } from '../utils/errors' import { CommerceAPIError } from '../utils/errors'
import isAllowedOperation from '../utils/is-allowed-operation' import isAllowedOperation from '../utils/is-allowed-operation'
import type { GetAPISchema } from '..' import type { GetAPISchema } from '..'
@ -24,7 +24,10 @@ const loginEndpoint: GetAPISchema<
} catch (error) { } catch (error) {
console.error(error) console.error(error)
const message = getErrorMessage(error) const message =
error instanceof CommerceAPIError
? 'An unexpected error ocurred with the Commerce API'
: 'An unexpected error ocurred'
res.status(500).json({ data: null, errors: [{ message }] }) res.status(500).json({ data: null, errors: [{ message }] })
} }

View File

@ -12,7 +12,7 @@ import type { CheckoutSchema } from '../types/checkout'
import type { CustomerCardSchema } from '../types/customer/card' import type { CustomerCardSchema } from '../types/customer/card'
import type { CustomerAddressSchema } from '../types/customer/address' import type { CustomerAddressSchema } from '../types/customer/address'
import { withSchemaParser } from './utils/with-schema-parser' import { withOperationCallback } from './utils/with-operation-callback'
import { import {
OPERATIONS, OPERATIONS,
@ -109,7 +109,7 @@ export function getCommerceApi<P extends APIProvider>(
OPERATIONS.forEach((k) => { OPERATIONS.forEach((k) => {
const op = ops[k] const op = ops[k]
if (op) { if (op) {
commerce[k] = withSchemaParser( commerce[k] = withOperationCallback(
k, k,
op({ commerce }) op({ commerce })
) as AllOperations<P>[typeof k] ) as AllOperations<P>[typeof k]

View File

@ -25,6 +25,13 @@ export const OPERATIONS = [
'getProduct', 'getProduct',
] as const ] as const
export type Operation = {
[O in AllowedOperations]: {
name: O
data: Awaited<ReturnType<Operations<APIProvider>[O]>>
}
}[AllowedOperations]
export const defaultOperations = OPERATIONS.reduce((ops, k) => { export const defaultOperations = OPERATIONS.reduce((ops, k) => {
ops[k] = noop ops[k] = noop
return ops return ops
@ -32,15 +39,6 @@ export const defaultOperations = OPERATIONS.reduce((ops, k) => {
export type AllowedOperations = typeof OPERATIONS[number] export type AllowedOperations = typeof OPERATIONS[number]
export type OperationsData = GetProductOperation['data'] &
GetAllProductsOperation['data'] &
GetAllProductPathsOperation['data'] &
GetCustomerWishlistOperation['data'] &
GetSiteInfoOperation['data'] &
GetPageOperation['data'] &
GetAllPagesOperation['data'] &
LoginOperation['data']
export type Operations<P extends APIProvider> = { export type Operations<P extends APIProvider> = {
login: { login: {
<T extends LoginOperation>(opts: { <T extends LoginOperation>(opts: {

View File

@ -24,12 +24,6 @@ export class CommerceNetworkError extends Error {
} }
} }
export const getErrorMessage = (error: unknown) => {
return error instanceof CommerceAPIError
? 'An unexpected error ocurred with the Commerce API'
: 'An unexpected error ocurred'
}
export const getOperationError = (operation: string, error: unknown) => { export const getOperationError = (operation: string, error: unknown) => {
if (error instanceof ZodError) { if (error instanceof ZodError) {
return new CommerceError({ return new CommerceError({

View File

@ -1,54 +1,42 @@
import type { AllowedOperations, OperationsData } from '../operations' import type { AllowedOperations, Operation } from '../operations'
import { z } from 'zod' import { z } from 'zod'
import { getOperationError } from './errors' import { getOperationError } from './errors'
import { pageSchema } from '../../schemas/page' import { pageSchema } from '../../schemas/page'
import { siteInfoSchema } from '../../schemas/site' import { siteInfoSchema } from '../../schemas/site'
import { productSchema, productsPathsSchema } from '../../schemas/product' import { productSchema, productsPathsSchema } from '../../schemas/product'
export const withSchemaParser = export const withOperationCallback =
( (name: AllowedOperations, fn: (...args: any[]) => Promise<any>) =>
operation: AllowedOperations,
fn: (...args: any[]) => Promise<OperationsData>
) =>
async (...args: any[]) => { async (...args: any[]) => {
try { try {
const result = await fn(...args) const data = await fn(...args)
parse(operation, result) parse({ name, data })
return result return data
} catch (error) { } catch (error) {
throw getOperationError(operation, error) throw getOperationError(name, error)
} }
} }
const parse = (operation: AllowedOperations, data: OperationsData) => { const parse = ({ name, data }: Operation) => {
switch (operation) { switch (name) {
case 'getProduct': case 'getProduct':
productSchema.nullable().parse(data.product) productSchema.nullable().parse(data.product)
break break
case 'getAllProducts': case 'getAllProducts':
z.array(productSchema).parse(data.products) z.array(productSchema).parse(data.products)
break break
case 'getAllProductPaths': case 'getAllProductPaths':
productsPathsSchema.parse(data.products) productsPathsSchema.parse(data.products)
break break
case 'getPage': case 'getPage':
pageSchema.nullable().parse(data.page) pageSchema.nullable().parse(data.page)
break break
case 'getAllPages': case 'getAllPages':
z.array(pageSchema).parse(data.pages) z.array(pageSchema).parse(data.pages)
break break
case 'getSiteInfo': case 'getSiteInfo':
siteInfoSchema.parse({ siteInfoSchema.parse(data)
categories: data.categories,
brands: data.brands,
})
break break
} }
} }

View File

@ -1,4 +1,4 @@
import type { Discount, Image } from './common' import type { Discount, Image, Measurement } from './common'
// TODO: This should use the same type as the `ProductVariant` type from `product.ts` // TODO: This should use the same type as the `ProductVariant` type from `product.ts`
export interface ProductVariant { export interface ProductVariant {
@ -35,6 +35,26 @@ export interface ProductVariant {
* The image associated with the variant. * The image associated with the variant.
*/ */
image?: Image image?: Image
/**
* The variant's weight. If a weight was not explicitly specified on the
* variant, this will be the product's weight.
*/
weight?: Measurement
/**
* The variant's height. If a height was not explicitly specified on the
* variant, this will be the product's height.
*/
height?: Measurement
/**
* The variant's width. If a width was not explicitly specified on the
* variant, this will be the product's width.
*/
width?: Measurement
/**
* The variant's depth. If a depth was not explicitly specified on the
* variant, this will be the product's depth.
*/
depth?: Measurement
} }
export interface SelectedOption { export interface SelectedOption {