Skip to content

Commit

Permalink
Dynamic API routes (vercel#836)
Browse files Browse the repository at this point in the history
* Add dynamic API endpoints

* Add missing dependency

* Update api handlers

* Updates

* Fix build errors

* Update package.json

* Add checkout endpoint parser & update errors

* Update tsconfig.json

* Update cart.ts

* Update parser

* Update errors.ts

* Update errors.ts

* Move to Edge runtime

* Revert to local

* Fix switchable runtimes

* Make nodejs default runtime

* Update pnpm-lock.yaml

* Update handlers

* Fix build errors

* Change headers
  • Loading branch information
cond0r authored Oct 30, 2022
1 parent a5b367a commit c75b0fc
Show file tree
Hide file tree
Showing 316 changed files with 2,471 additions and 2,165 deletions.
9 changes: 5 additions & 4 deletions packages/bigcommerce/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,15 @@
}
},
"dependencies": {
"@cfworker/uuid": "^1.12.4",
"@tsndr/cloudflare-worker-jwt": "^2.1.0",
"@vercel/commerce": "workspace:*",
"@vercel/fetch": "^6.2.0",
"cookie": "^0.4.1",
"immutability-helper": "^3.1.1",
"js-cookie": "^3.0.1",
"jsonwebtoken": "^8.5.1",
"lodash.debounce": "^4.0.8",
"uuidv4": "^6.2.12",
"node-fetch": "^2.6.7"
"uuidv4": "^6.2.13"
},
"peerDependencies": {
"next": "^12",
Expand All @@ -69,8 +70,8 @@
"@types/jsonwebtoken": "^8.5.7",
"@types/lodash.debounce": "^4.0.6",
"@types/node": "^17.0.8",
"@types/react": "^18.0.14",
"@types/node-fetch": "^2.6.2",
"@types/react": "^18.0.14",
"lint-staged": "^12.1.7",
"next": "^12.0.8",
"prettier": "^2.5.1",
Expand Down
35 changes: 16 additions & 19 deletions packages/bigcommerce/src/api/endpoints/cart/add-item.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,14 @@
// @ts-nocheck
import type { CartEndpoint } from '.'
import type { BigcommerceCart } from '../../../types'

import { normalizeCart } from '../../../lib/normalize'
import { parseCartItem } from '../../utils/parse-item'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

const addItem: CartEndpoint['handlers']['addItem'] = async ({
res,
body: { cartId, item },
config,
}) => {
if (!item) {
return res.status(400).json({
data: null,
errors: [{ message: 'Missing item' }],
})
}
if (!item.quantity) item.quantity = 1

const options = {
method: 'POST',
body: JSON.stringify({
Expand All @@ -26,22 +18,27 @@ const addItem: CartEndpoint['handlers']['addItem'] = async ({
: {}),
}),
}

const { data } = cartId
? await config.storeApiFetch(
? await config.storeApiFetch<{ data: BigcommerceCart }>(
`/v3/carts/${cartId}/items?include=line_items.physical_items.options,line_items.digital_items.options`,
options
)
: await config.storeApiFetch(
: await config.storeApiFetch<{ data: BigcommerceCart }>(
'/v3/carts?include=line_items.physical_items.options,line_items.digital_items.options',
options
)

// Create or update the cart cookie
res.setHeader(
'Set-Cookie',
getCartCookie(config.cartCookie, data.id, config.cartCookieMaxAge)
)
res.status(200).json({ data: normalizeCart(data) })
return {
data: normalizeCart(data),
headers: {
'Set-Cookie': getCartCookie(
config.cartCookie,
data.id,
config.cartCookieMaxAge
),
},
}
}

export default addItem
31 changes: 18 additions & 13 deletions packages/bigcommerce/src/api/endpoints/cart/get-cart.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,41 @@
// @ts-nocheck
import type { CartEndpoint } from '.'
import type { BigcommerceCart } from '../../../types'

import getCartCookie from '../../utils/get-cart-cookie'

import { normalizeCart } from '../../../lib/normalize'
import { BigcommerceApiError } from '../../utils/errors'
import getCartCookie from '../../utils/get-cart-cookie'
import type { BigcommerceCart } from '../../../types'
import type { CartEndpoint } from '.'

// Return current cart info
const getCart: CartEndpoint['handlers']['getCart'] = async ({
res,
body: { cartId },
config,
}) => {
let result: { data?: BigcommerceCart } = {}

if (cartId) {
try {
result = await config.storeApiFetch(
const result = await config.storeApiFetch<{
data?: BigcommerceCart
} | null>(
`/v3/carts/${cartId}?include=line_items.physical_items.options,line_items.digital_items.options`
)

return {
data: result?.data ? normalizeCart(result.data) : null,
}
} 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))
return {
headers: { 'Set-Cookie': getCartCookie(config.cartCookie) },
}
} else {
throw error
}
}
}

res.status(200).json({
data: result.data ? normalizeCart(result.data) : null,
})
return {
data: null,
}
}

export default getCart
2 changes: 1 addition & 1 deletion packages/bigcommerce/src/api/endpoints/cart/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import { type GetAPISchema, createEndpoint } from '@vercel/commerce/api'
import cartEndpoint from '@vercel/commerce/api/endpoints/cart'
import type { CartSchema } from '@vercel/commerce/types/cart'
import type { BigcommerceAPI } from '../..'
Expand Down
32 changes: 12 additions & 20 deletions packages/bigcommerce/src/api/endpoints/cart/remove-item.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
import type { CartEndpoint } from '.'

import { normalizeCart } from '../../../lib/normalize'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

const removeItem: CartEndpoint['handlers']['removeItem'] = async ({
res,
body: { cartId, itemId },
config,
}) => {
if (!cartId || !itemId) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}

const result = await config.storeApiFetch<{ data: any } | null>(
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
{ method: 'DELETE' }
)
const data = result?.data ?? null

res.setHeader(
'Set-Cookie',
data
? // Update the cart cookie
getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge)
: // Remove the cart cookie if the cart was removed (empty items)
getCartCookie(config.cartCookie)
)
res.status(200).json({ data: data && normalizeCart(data) })
return {
data: result?.data ? normalizeCart(result.data) : null,
headers: {
'Set-Cookie': result?.data
? // Update the cart cookie
getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge)
: // Remove the cart cookie if the cart was removed (empty items)
getCartCookie(config.cartCookie),
},
}
}

export default removeItem
30 changes: 14 additions & 16 deletions packages/bigcommerce/src/api/endpoints/cart/update-item.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import type { CartEndpoint } from '.'
import type { BigcommerceCart } from '../../../types'

import { normalizeCart } from '../../../lib/normalize'
import { parseCartItem } from '../../utils/parse-item'
import getCartCookie from '../../utils/get-cart-cookie'
import type { CartEndpoint } from '.'

const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
res,
body: { cartId, itemId, item },
config,
}) => {
if (!cartId || !itemId || !item) {
return res.status(400).json({
data: null,
errors: [{ message: 'Invalid request' }],
})
}

const { data } = await config.storeApiFetch(
const { data } = await config.storeApiFetch<{ data: BigcommerceCart }>(
`/v3/carts/${cartId}/items/${itemId}?include=line_items.physical_items.options`,
{
method: 'PUT',
Expand All @@ -25,12 +19,16 @@ const updateItem: CartEndpoint['handlers']['updateItem'] = async ({
}
)

// Update the cart cookie
res.setHeader(
'Set-Cookie',
getCartCookie(config.cartCookie, cartId, config.cartCookieMaxAge)
)
res.status(200).json({ data: normalizeCart(data) })
return {
data: normalizeCart(data),
headers: {
'Set-Cookie': getCartCookie(
config.cartCookie,
cartId,
config.cartCookieMaxAge
),
},
}
}

export default updateItem
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ const LIMIT = 12

// Return current cart info
const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
res,
body: { search, categoryId, brandId, sort },
config,
commerce,
Expand Down Expand Up @@ -73,7 +72,7 @@ const getProducts: ProductsEndpoint['handlers']['getProducts'] = async ({
if (product) products.push(product)
})

res.status(200).json({ data: { products, found } })
return { data: { products, found } }
}

export default getProducts
Loading

0 comments on commit c75b0fc

Please sign in to comment.