Align Get Menu with v2 endpoint, menu_type, and gzip
This commit is contained in:
parent
0c41ad5858
commit
5ea2d86a48
@ -6,6 +6,9 @@ Source checked: Uber Eats "Menu Integration" section shared by you.
|
||||
|
||||
- Retrieve menu:
|
||||
- `GET /api/v1/uber/menu`
|
||||
- aligned to upstream `GET /v2/eats/stores/{store_id}/menus`
|
||||
- supports `menu_type` query values for delivery/pick-up/dine-in
|
||||
- applies `Accept-Encoding: gzip` for large payload responses
|
||||
- Full menu upload/replace:
|
||||
- `PUT /api/v1/uber/menu/replace` (primary)
|
||||
- Individual item updates:
|
||||
@ -22,4 +25,3 @@ Source checked: Uber Eats "Menu Integration" section shared by you.
|
||||
- Strict typed schemas for full menu payload entities (item, modifier group, category, menu)
|
||||
- Validation rules for image metadata limits and alcoholic item classifications
|
||||
- Dedicated mapper helpers for `core_price` and `bundled_items` enrichment
|
||||
|
||||
|
||||
@ -16,6 +16,16 @@ Item update route:
|
||||
|
||||
- `POST /api/v1/uber/menu/items`
|
||||
|
||||
Menu fetch route:
|
||||
|
||||
- `GET /api/v1/uber/menu`
|
||||
- upstream mapped to `GET /v2/eats/stores/{store_id}/menus`
|
||||
- supports query `menu_type`:
|
||||
- `MENU_TYPE_FULFILLMENT_DELIVERY` (default)
|
||||
- `MENU_TYPE_FULFILLMENT_PICK_UP`
|
||||
- `MENU_TYPE_FULFILLMENT_DINE_IN`
|
||||
- sends `Accept-Encoding: gzip` upstream for large menu payloads
|
||||
|
||||
Best-practice note:
|
||||
|
||||
- Use API-managed menus only for integrated stores (avoid manual Menu Maker edits to prevent drift).
|
||||
|
||||
@ -335,6 +335,38 @@
|
||||
"tags": [
|
||||
"Uber Menu"
|
||||
],
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "merchantId",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "storeId",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "menu_type",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"MENU_TYPE_FULFILLMENT_DELIVERY",
|
||||
"MENU_TYPE_FULFILLMENT_PICK_UP",
|
||||
"MENU_TYPE_FULFILLMENT_DINE_IN"
|
||||
]
|
||||
},
|
||||
"description": "Defaults to MENU_TYPE_FULFILLMENT_DELIVERY."
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Menu fetched"
|
||||
|
||||
@ -232,6 +232,44 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get Menu (v2)",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [
|
||||
{
|
||||
"key": "x-api-key",
|
||||
"value": "{{apiKey}}"
|
||||
}
|
||||
],
|
||||
"url": {
|
||||
"raw": "{{baseUrl}}/api/v1/uber/menu?merchantId={{merchantId}}&storeId={{storeId}}&menu_type=MENU_TYPE_FULFILLMENT_DELIVERY",
|
||||
"host": [
|
||||
"{{baseUrl}}"
|
||||
],
|
||||
"path": [
|
||||
"api",
|
||||
"v1",
|
||||
"uber",
|
||||
"menu"
|
||||
],
|
||||
"query": [
|
||||
{
|
||||
"key": "merchantId",
|
||||
"value": "{{merchantId}}"
|
||||
},
|
||||
{
|
||||
"key": "storeId",
|
||||
"value": "{{storeId}}"
|
||||
},
|
||||
{
|
||||
"key": "menu_type",
|
||||
"value": "MENU_TYPE_FULFILLMENT_DELIVERY"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "List Provisionable Stores",
|
||||
"request": {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
menu: {
|
||||
upsert: "/v1/eats/stores/{storeId}/menus",
|
||||
get: "/v1/eats/stores/{storeId}/menus",
|
||||
get: "/v2/eats/stores/{storeId}/menus",
|
||||
itemsUpdate: "/v1/eats/stores/{storeId}/menus/items"
|
||||
},
|
||||
orders: {
|
||||
|
||||
@ -35,10 +35,28 @@ async function upsertMenu(req, res) {
|
||||
async function getMenu(req, res) {
|
||||
const schema = z.object({
|
||||
merchantId: z.string().min(1),
|
||||
storeId: z.string().min(1)
|
||||
storeId: z.string().min(1),
|
||||
menu_type: z
|
||||
.enum([
|
||||
"MENU_TYPE_FULFILLMENT_DELIVERY",
|
||||
"MENU_TYPE_FULFILLMENT_PICK_UP",
|
||||
"MENU_TYPE_FULFILLMENT_DINE_IN"
|
||||
])
|
||||
.optional(),
|
||||
menuType: z
|
||||
.enum([
|
||||
"MENU_TYPE_FULFILLMENT_DELIVERY",
|
||||
"MENU_TYPE_FULFILLMENT_PICK_UP",
|
||||
"MENU_TYPE_FULFILLMENT_DINE_IN"
|
||||
])
|
||||
.optional()
|
||||
});
|
||||
const payload = schema.parse(req.query);
|
||||
const data = await proxyService.menuGet(payload);
|
||||
const data = await proxyService.menuGet({
|
||||
merchantId: payload.merchantId,
|
||||
storeId: payload.storeId,
|
||||
menuType: payload.menu_type || payload.menuType
|
||||
});
|
||||
return res.json({ success: true, data });
|
||||
}
|
||||
|
||||
|
||||
@ -55,7 +55,17 @@ async function resolveAuthToken({ authMode = "app", merchantId, scopes }) {
|
||||
};
|
||||
}
|
||||
|
||||
async function callUberApi({ merchantId, method, uberPath, query, body, wrapperRoute, authMode, scopes }) {
|
||||
async function callUberApi({
|
||||
merchantId,
|
||||
method,
|
||||
uberPath,
|
||||
query,
|
||||
body,
|
||||
wrapperRoute,
|
||||
authMode,
|
||||
scopes,
|
||||
headers
|
||||
}) {
|
||||
const resolvedAuth = await resolveAuthToken({ authMode, merchantId, scopes });
|
||||
|
||||
try {
|
||||
@ -68,7 +78,8 @@ async function callUberApi({ merchantId, method, uberPath, query, body, wrapperR
|
||||
data: body,
|
||||
headers: {
|
||||
Authorization: buildAuthHeader(resolvedAuth.tokenType, resolvedAuth.accessToken),
|
||||
"Content-Type": "application/json"
|
||||
"Content-Type": "application/json",
|
||||
...(headers || {})
|
||||
}
|
||||
}),
|
||||
maxAttempts: 4,
|
||||
@ -148,12 +159,18 @@ async function menuReplace({ merchantId, storeId, payload }) {
|
||||
});
|
||||
}
|
||||
|
||||
async function menuGet({ merchantId, storeId }) {
|
||||
async function menuGet({ merchantId, storeId, menuType }) {
|
||||
const uberPath = interpolatePath(uberEndpoints.menu.get, { storeId });
|
||||
return callUberApi({
|
||||
merchantId,
|
||||
method: "GET",
|
||||
uberPath,
|
||||
query: {
|
||||
menu_type: menuType || "MENU_TYPE_FULFILLMENT_DELIVERY"
|
||||
},
|
||||
headers: {
|
||||
"Accept-Encoding": "gzip"
|
||||
},
|
||||
wrapperRoute: "/api/v1/uber/menu",
|
||||
authMode: "app",
|
||||
scopes: AUTH_SCOPES.STORE
|
||||
|
||||
@ -63,6 +63,27 @@ router.post("/uber/menu/items", asyncHandler(controller.updateMenuItems));
|
||||
* summary: Fetch store menu
|
||||
* tags:
|
||||
* - Uber Menu
|
||||
* parameters:
|
||||
* - in: query
|
||||
* name: merchantId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: storeId
|
||||
* required: true
|
||||
* schema:
|
||||
* type: string
|
||||
* - in: query
|
||||
* name: menu_type
|
||||
* required: false
|
||||
* schema:
|
||||
* type: string
|
||||
* enum:
|
||||
* - MENU_TYPE_FULFILLMENT_DELIVERY
|
||||
* - MENU_TYPE_FULFILLMENT_PICK_UP
|
||||
* - MENU_TYPE_FULFILLMENT_DINE_IN
|
||||
* description: Defaults to MENU_TYPE_FULFILLMENT_DELIVERY.
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Menu fetched
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user