forked from crowetic/commerce
Allow API operations to be more customizable
This commit is contained in:
parent
4c43278e67
commit
1c3714bf51
29
lib/bigcommerce/api/cart/handlers/get-cart.ts
Normal file
29
lib/bigcommerce/api/cart/handlers/get-cart.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { BigcommerceApiError } from '../../utils/errors'
|
||||||
|
import getCartCookie from '../../utils/get-cart-cookie'
|
||||||
|
import type { Cart, CartHandlers } from '..'
|
||||||
|
|
||||||
|
// Return current cart info
|
||||||
|
const getCart: CartHandlers['getCart'] = async ({
|
||||||
|
res,
|
||||||
|
body: { cartId },
|
||||||
|
config,
|
||||||
|
}) => {
|
||||||
|
let result: { data?: Cart } = {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = await config.storeApiFetch(
|
||||||
|
`/v3/carts/${cartId}?include=redirect_urls`
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof BigcommerceApiError && error.status === 404) {
|
||||||
|
// Remove the cookie if it exists but the cart wasn't found
|
||||||
|
res.setHeader('Set-Cookie', getCartCookie(config.cartCookie))
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).json({ data: result.data ?? null })
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getCart
|
@ -1,9 +1,11 @@
|
|||||||
import { serialize, CookieSerializeOptions } from 'cookie'
|
import { serialize, CookieSerializeOptions } from 'cookie'
|
||||||
import isAllowedMethod from './utils/is-allowed-method'
|
import isAllowedMethod from '../utils/is-allowed-method'
|
||||||
import createApiHandler, {
|
import createApiHandler, {
|
||||||
BigcommerceApiHandler,
|
BigcommerceApiHandler,
|
||||||
} from './utils/create-api-handler'
|
BigcommerceHandler,
|
||||||
import { BigcommerceApiError } from './utils/errors'
|
} from '../utils/create-api-handler'
|
||||||
|
import { BigcommerceApiError } from '../utils/errors'
|
||||||
|
import getCart from './handlers/get-cart'
|
||||||
|
|
||||||
type Body<T> = Partial<T> | undefined
|
type Body<T> = Partial<T> | undefined
|
||||||
|
|
||||||
@ -40,10 +42,19 @@ export type Cart = {
|
|||||||
// TODO: add missing fields
|
// TODO: add missing fields
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CartHandlers = {
|
||||||
|
getCart: BigcommerceHandler<Cart, { cartId?: string }>
|
||||||
|
}
|
||||||
|
|
||||||
const METHODS = ['GET', 'POST', 'PUT', 'DELETE']
|
const METHODS = ['GET', 'POST', 'PUT', 'DELETE']
|
||||||
|
|
||||||
// TODO: a complete implementation should have schema validation for `req.body`
|
// TODO: a complete implementation should have schema validation for `req.body`
|
||||||
const cartApi: BigcommerceApiHandler<Cart> = async (req, res, config) => {
|
const cartApi: BigcommerceApiHandler<Cart, CartHandlers> = async (
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
config,
|
||||||
|
handlers
|
||||||
|
) => {
|
||||||
if (!isAllowedMethod(req, res, METHODS)) return
|
if (!isAllowedMethod(req, res, METHODS)) return
|
||||||
|
|
||||||
const { cookies } = req
|
const { cookies } = req
|
||||||
@ -52,22 +63,7 @@ const cartApi: BigcommerceApiHandler<Cart> = async (req, res, config) => {
|
|||||||
try {
|
try {
|
||||||
// Return current cart info
|
// Return current cart info
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
let result: { data?: Cart } = {}
|
return await handlers['getCart']({ req, res, config, body: { cartId } })
|
||||||
|
|
||||||
try {
|
|
||||||
result = await config.storeApiFetch(
|
|
||||||
`/v3/carts/${cartId}?include=redirect_urls`
|
|
||||||
)
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof BigcommerceApiError && error.status === 404) {
|
|
||||||
// Remove the cookie if it exists but the cart wasn't found
|
|
||||||
res.setHeader('Set-Cookie', getCartCookie(config.cartCookie))
|
|
||||||
} else {
|
|
||||||
throw error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.status(200).json({ data: result.data ?? null })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create or add an item to the cart
|
// Create or add an item to the cart
|
||||||
@ -192,4 +188,10 @@ const parseItem = (item: ItemBody) => ({
|
|||||||
variant_id: item.variantId,
|
variant_id: item.variantId,
|
||||||
})
|
})
|
||||||
|
|
||||||
export default createApiHandler(cartApi)
|
const handlers = {
|
||||||
|
getCart,
|
||||||
|
}
|
||||||
|
|
||||||
|
const h = createApiHandler(cartApi, handlers)
|
||||||
|
|
||||||
|
export default h
|
48
lib/bigcommerce/api/customers.ts
Normal file
48
lib/bigcommerce/api/customers.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import createApiHandler, {
|
||||||
|
BigcommerceApiHandler,
|
||||||
|
BigcommerceHandler,
|
||||||
|
} from './utils/create-api-handler'
|
||||||
|
import isAllowedMethod from './utils/is-allowed-method'
|
||||||
|
import { BigcommerceApiError } from './utils/errors'
|
||||||
|
|
||||||
|
export type Customer = any
|
||||||
|
|
||||||
|
const METHODS = ['POST']
|
||||||
|
|
||||||
|
const customersApi: BigcommerceApiHandler<Customer> = async (
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
config
|
||||||
|
) => {
|
||||||
|
if (!isAllowedMethod(req, res, METHODS)) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (req.method === 'POST') {
|
||||||
|
// let result = {} as any
|
||||||
|
// const
|
||||||
|
// result = await config.storeApiFetch('/v3/customers')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
|
||||||
|
const message =
|
||||||
|
error instanceof BigcommerceApiError
|
||||||
|
? 'An unexpected error ocurred with the Bigcommerce API'
|
||||||
|
: 'An unexpected error ocurred'
|
||||||
|
|
||||||
|
res.status(500).json({ data: null, errors: [{ message }] })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createCustomer: BigcommerceHandler<Customer> = ({
|
||||||
|
req,
|
||||||
|
res,
|
||||||
|
body,
|
||||||
|
config,
|
||||||
|
}) => {}
|
||||||
|
|
||||||
|
const handlers = {
|
||||||
|
createCustomer,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createApiHandler(customersApi, handlers)
|
@ -1,23 +1,47 @@
|
|||||||
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next'
|
||||||
import { BigcommerceConfig, getConfig } from '..'
|
import { BigcommerceConfig, getConfig } from '..'
|
||||||
|
|
||||||
export type BigcommerceApiHandler<T = any> = (
|
export type BigcommerceApiHandler<
|
||||||
|
T = any,
|
||||||
|
H extends BigcommerceHandlers = {}
|
||||||
|
> = (
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<BigcommerceApiResponse<T>>,
|
res: NextApiResponse<BigcommerceApiResponse<T>>,
|
||||||
config: BigcommerceConfig
|
config: BigcommerceConfig,
|
||||||
|
handlers: H
|
||||||
) => void | Promise<void>
|
) => void | Promise<void>
|
||||||
|
|
||||||
|
export type BigcommerceHandler<T = any, Body = any> = (options: {
|
||||||
|
req: NextApiRequest
|
||||||
|
res: NextApiResponse<BigcommerceApiResponse<T>>
|
||||||
|
config: BigcommerceConfig
|
||||||
|
body: Body
|
||||||
|
}) => void | Promise<void>
|
||||||
|
|
||||||
|
export type BigcommerceHandlers<T = any> = {
|
||||||
|
[k: string]: BigcommerceHandler<T, any>
|
||||||
|
}
|
||||||
|
|
||||||
export type BigcommerceApiResponse<T> = {
|
export type BigcommerceApiResponse<T> = {
|
||||||
data: T | null
|
data: T | null
|
||||||
errors?: { message: string }[]
|
errors?: { message: string }[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function createApiHandler(handler: BigcommerceApiHandler) {
|
export default function createApiHandler<H extends BigcommerceHandlers>(
|
||||||
|
handler: BigcommerceApiHandler<any, H>,
|
||||||
|
handlers: H
|
||||||
|
) {
|
||||||
return function getApiHandler({
|
return function getApiHandler({
|
||||||
config,
|
config,
|
||||||
}: { config?: BigcommerceConfig } = {}): NextApiHandler {
|
operations,
|
||||||
|
}: {
|
||||||
|
config?: BigcommerceConfig
|
||||||
|
operations?: Partial<H>
|
||||||
|
} = {}): NextApiHandler {
|
||||||
|
const ops = { ...operations, ...handlers }
|
||||||
|
|
||||||
return function apiHandler(req, res) {
|
return function apiHandler(req, res) {
|
||||||
return handler(req, res, getConfig(config))
|
return handler(req, res, getConfig(config), ops)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
lib/bigcommerce/api/utils/get-cart-cookie.ts
Normal file
20
lib/bigcommerce/api/utils/get-cart-cookie.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { serialize, CookieSerializeOptions } from 'cookie'
|
||||||
|
|
||||||
|
export default function getCartCookie(
|
||||||
|
name: string,
|
||||||
|
cartId?: string,
|
||||||
|
maxAge?: number
|
||||||
|
) {
|
||||||
|
const options: CookieSerializeOptions =
|
||||||
|
cartId && maxAge
|
||||||
|
? {
|
||||||
|
maxAge,
|
||||||
|
expires: new Date(Date.now() + maxAge * 1000),
|
||||||
|
secure: process.env.NODE_ENV === 'production',
|
||||||
|
path: '/',
|
||||||
|
sameSite: 'lax',
|
||||||
|
}
|
||||||
|
: { maxAge: -1, path: '/' } // Removes the cookie
|
||||||
|
|
||||||
|
return serialize(name, cartId || '', options)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user