From 191164f4cc2b213ee86dafd61195684e0d2f0f2a Mon Sep 17 00:00:00 2001 From: TylerP33 Date: Thu, 21 Mar 2024 15:18:06 -0500 Subject: [PATCH] itemLookUp complete and addItem endpoint --- api/controllers/dataController.js | 4 +- api/controllers/inventoryController.js | 44 ++++++++++++++ api/routes/inventoryRoutes.js | 12 ++++ api/server.js | 2 + api/utils/buildAddItemRequestXML.js | 58 +++++++++++++++++++ ...etchEbayToken.js => fetchEbayReadToken.js} | 5 +- api/utils/fetchEbayUserToken.js | 41 +++++++++++++ 7 files changed, 162 insertions(+), 4 deletions(-) create mode 100644 api/routes/inventoryRoutes.js create mode 100644 api/utils/buildAddItemRequestXML.js rename api/utils/{fetchEbayToken.js => fetchEbayReadToken.js} (85%) create mode 100644 api/utils/fetchEbayUserToken.js diff --git a/api/controllers/dataController.js b/api/controllers/dataController.js index 4e577f8..aa97885 100644 --- a/api/controllers/dataController.js +++ b/api/controllers/dataController.js @@ -1,9 +1,9 @@ import fetch from "node-fetch"; -import fetchEbayToken from "../utils/fetchEbayToken.js"; // Adjust the import path according to your project structure +import fetchEbayReadToken from "../utils/fetchEbayReadToken.js"; // Adjust the import path according to your project structure export const itemLookup = async (req, res) => { const productCode = req.query.productCode; - const oauthToken = await fetchEbayToken(); + const oauthToken = await fetchEbayReadToken(); console.log(productCode); try { const response = await fetch( diff --git a/api/controllers/inventoryController.js b/api/controllers/inventoryController.js index e69de29..fd550e6 100644 --- a/api/controllers/inventoryController.js +++ b/api/controllers/inventoryController.js @@ -0,0 +1,44 @@ +// inventoryController.js +import buildAddItemRequestXML from "../utils/buildAddItemRequestXML.js"; +import fetch from "node-fetch"; +import fetchEbayUserToken from "../utils/fetchEbayUserToken.js"; // Adjust the import path according to your project structure + +export const addItem = async (req, res) => { + const itemDetails = req.body; // Assuming item details are sent in the request body + itemDetails.userToken = await fetchEbayUserToken(); // Fetch and add the user token to itemDetails + + const xmlRequest = buildAddItemRequestXML(itemDetails); + + try { + const response = await fetch("https://api.ebay.com/ws/api.dll", { + method: "POST", + headers: { + "Content-Type": "text/xml", + "X-EBAY-API-SITEID": "0", + "X-EBAY-API-CALL-NAME": "AddItem", + "X-EBAY-API-COMPATIBILITY-LEVEL": "967", // Ensure this is the current compatibility level + "X-EBAY-API-APP-NAME": process.env.EBAY_CLIENT_ID, + "X-EBAY-API-DEV-NAME": process.env.EBAY_DEV_ID, + "X-EBAY-API-CERT-NAME": process.env.EBAY_CLIENT_SECRET, + }, + body: xmlRequest, + }); + + if (!response.ok) { + throw new Error(`eBay API responded with status ${response.status}`); + } + + const responseData = await response.text(); + // Parse the XML response and handle it appropriately + // You might need an XML parser here to handle the response + + res.json({ success: true, data: responseData }); // Send back a success response + } catch (error) { + console.error("Error adding item to eBay:", error); + res.status(500).json({ + success: false, + message: "Failed to add item to eBay", + error: error.message, + }); + } +}; diff --git a/api/routes/inventoryRoutes.js b/api/routes/inventoryRoutes.js new file mode 100644 index 0000000..59628e2 --- /dev/null +++ b/api/routes/inventoryRoutes.js @@ -0,0 +1,12 @@ +// routes/dataRoutes.js +import express from "express"; +import { addItem } from "../controllers/inventoryController.js"; // Adjust the import path according to your project structure + +const router = express.Router(); + +// Use the itemLookup function from dataController for the GET request to '/item-lookup' +router.get("/add-item", addItem); + +// You can add more data-related routes here in the future + +export default router; diff --git a/api/server.js b/api/server.js index 499be5c..5c8234d 100644 --- a/api/server.js +++ b/api/server.js @@ -3,6 +3,7 @@ import express from "express"; import cors from "cors"; import dotenv from "dotenv"; import dataRoutes from "./routes/dataRoutes.js"; +import inventoryRoutes from "./routes/inventoryRoutes.js"; dotenv.config(); @@ -13,6 +14,7 @@ app.use(express.json()); // Use the itemLookupRoute with a base path, e.g., '/api' app.use("/api/data", dataRoutes); +app.use("/api/inventory", inventoryRoutes); const PORT = process.env.PORT || 3000; app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); diff --git a/api/utils/buildAddItemRequestXML.js b/api/utils/buildAddItemRequestXML.js new file mode 100644 index 0000000..2e367d9 --- /dev/null +++ b/api/utils/buildAddItemRequestXML.js @@ -0,0 +1,58 @@ +const buildAddItemRequestXML = (itemDetails) => { + // Constructing the XML payload using template literals + return ` + + + ${itemDetails.userToken} + + + ${itemDetails.title} + + + ${itemDetails.categoryID} + + ${itemDetails.startPrice} + ${itemDetails.conditionID} + ${itemDetails.country} + ${itemDetails.currency} + ${itemDetails.dispatchTimeMax} + ${itemDetails.listingDuration} + ${itemDetails.listingType} + ${itemDetails.paymentMethods} + ${itemDetails.payPalEmailAddress} + + ${itemDetails.imageURLs + .map((url) => `${url}`) + .join("")} + + ${itemDetails.postalCode} + ${itemDetails.quantity} + + ${ + itemDetails.returnsAcceptedOption + } + ${itemDetails.refundOption} + ${ + itemDetails.returnsWithinOption + } + ${itemDetails.returnPolicyDescription} + ${ + itemDetails.shippingCostPaidByOption + } + + + ${itemDetails.shippingType} + + 1 + ${itemDetails.shippingService} + ${ + itemDetails.shippingServiceCost + } + + + ${itemDetails.site} + + `; +}; + +export default buildAddItemRequestXML; diff --git a/api/utils/fetchEbayToken.js b/api/utils/fetchEbayReadToken.js similarity index 85% rename from api/utils/fetchEbayToken.js rename to api/utils/fetchEbayReadToken.js index 15549b2..e7c18f6 100644 --- a/api/utils/fetchEbayToken.js +++ b/api/utils/fetchEbayReadToken.js @@ -1,6 +1,7 @@ +// Need to figoure out expiration and make sure to cycle this appropriately to avoid unnecessary calls import fetch from "node-fetch"; -const fetchEbayToken = async () => { +const fetchEbayReadToken = async () => { const ebayClientId = process.env.EBAY_CLIENT_ID; const ebayClientSecret = process.env.EBAY_CLIENT_SECRET; const credentials = Buffer.from( @@ -35,4 +36,4 @@ const fetchEbayToken = async () => { } }; -export default fetchEbayToken; +export default fetchEbayReadToken; diff --git a/api/utils/fetchEbayUserToken.js b/api/utils/fetchEbayUserToken.js new file mode 100644 index 0000000..216aa5e --- /dev/null +++ b/api/utils/fetchEbayUserToken.js @@ -0,0 +1,41 @@ +import fetch from "node-fetch"; + +const fetchEbayUserToken = async (authorizationCode) => { + const clientId = process.env.EBAY_CLIENT_ID; + const clientSecret = process.env.EBAY_CLIENT_SECRET; + const redirectUri = process.env.EBAY_REDIRECT_URI; // Make sure this matches the URI registered with eBay + const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString( + "base64" + ); + + try { + const response = await fetch( + "https://api.ebay.com/identity/v1/oauth2/token", + { + method: "POST", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + Authorization: `Basic ${credentials}`, + }, + body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=${encodeURIComponent( + redirectUri + )}`, + } + ); + + if (!response.ok) { + const errorBody = await response.text(); + throw new Error( + `Failed to fetch eBay user token: ${response.status} ${response.statusText} - ${errorBody}` + ); + } + + const data = await response.json(); + return data.access_token; // This is the User access token + } catch (error) { + console.error("Error fetching eBay user token:", error); + throw error; + } +}; + +export default fetchEbayUserToken;