Menüfeed erstellen

In der folgenden Anleitung zeigen wir, wie Sie einen Feed in JSON mithilfe der Google Protocol Buffers (protobuf) Definition erstellen. Wir verwenden den protobuf-Compiler, um Quellcode basierend auf dem protobuf-Schema zu generieren. Wenn Sie einen Feed mit dem generierten Quellcode erstellen, erhalten Sie eine einfache Schnittstelle und verhindern, dass Feed-Entitäten mit falschen Feldnamen oder Feldtypen erstellt werden.

Projekt einrichten

  • Erstellen Sie ein neues Projektverzeichnis.
  • Kopieren Sie den Inhalt von food_menu.proto money.proto localized_text.proto aus den Proto-Definitionen als neue Dateien in das Stammverzeichnis Ihres Projekts.
  • Installieren Sie den protoc-Compiler.

    Um Quellcode aus den .proto-Dateien zu generieren, benötigen Sie den protoc-Compiler. Laden Sie die neueste vorkompilierte Binärdatei von der GitHub-Releaseseite für Protocol Buffers herunter.

    Extrahieren Sie die ZIP-Datei und fügen Sie den Bin-Pfad der Umgebungsvariable PATH hinzu, z. B.:

    unzip protoc-22.0-linux-x86_64.zip -d /usr/local/protoc
    export PATH="$PATH:/usr/local/protoc/bin"
      

Quellcode generieren

Python

  1. Installieren Sie die Python-protobuf-Bibliothek.
    pip install protobuf
        
  2. Generieren Sie Clientquellcode.

    Erstellen Sie das Proto-Ausgabeverzeichnis: generated

    protoc --python_out=./generated food_menu.proto money.proto localized_text.proto
        

    Aktualisieren Sie die Umgebungsvariable PYTHONPATH, um den generierten Pfad einzuschließen, z. B.:

    export PYTHONPATH="$PYTHONPATH:./generated"
        

    Wenn Sie Bazel verwenden, können Sie alternativ zur Ausführung von protoc die Regel py_proto_library verwenden.

Verwendungsbeispiel

Ein vollständiges Beispielprojekt finden Sie hier.

"""Menu feed example used in

https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#python.
"""
import json
from generated import food_menu_pb2
from google.protobuf.json_format import MessageToDict

# create feed
feed = food_menu_pb2.FoodMenuFeed()

# add a menu component to feed data
menuComponent = feed.data.add()
menuComponent.menu.menu_id = 'menu1'
menuComponent.menu.merchant_ids.append('dining-1')
menuDisplayName = menuComponent.menu.display_name.text.add()
menuDisplayName.text = 'Menu'
menuDisplayName.language_code = 'en-us'
menuComponent.menu.language = 'en-us'
menuComponent.menu.last_merchant_update_time.seconds = 1633621547

for i in ['appetizers', 'dinner']:
  menuComponent.menu.menu_section_ids.append(i)

# add a menu section component to feed data
sectionComponent = feed.data.add()
sectionComponent.section.menu_section_id = 'appetizers'
sectionDisplayName = sectionComponent.section.display_name.text.add()
sectionDisplayName.text = 'Lunch Appetizers'
sectionDisplayName.language_code = 'en-us'
sectionComponent.section.menu_item_ids.append('breadsticks-sauce')

# add a menu item component to feed data
itemComponent = feed.data.add()
itemComponent.item.menu_item_id =& 'breadsticks-sauce'
itemDisplayName = itemComponent.item.display_name.text.add()
itemDisplayName.text = 'Breadsticks  Sauce'
itemDisplayName.language_code = 'en-us'
itemDescription = itemComponent.item.description.text.add()
itemDescription.text = 'Breakfast basket w/ side of tomato sauce (size 6 or 12)'
itemDescription.language_code = 'en-us'

for i in ['breadstick-sm', 'breadstick-lg']:
  itemComponent.item.menu_item_option_set.menu_item_option_ids.append(i)

for i in [
    'http://www.example.com/photos/breadsticks.jpg',
    'http://www.example.com/photos/sauce.jpg',
]:
  itemImage = itemComponent.item.images.add()
  itemImage.uri = i

# add a menu item option component to feed data
optionComponent = feed.data.add()
optionComponent.option.menu_item_option_id: 'breadstick-sm'
optionComponent.option.value.property_type = (
    food_menu_pb2.MenuItemOptionProperty.PropertyType.SIZE
)
optionTextValue = optionComponent.option.value.text_val.text.add()
optionTextValue.text = 'Small'
optionTextValue.language_code = 'en-us'
optionOffer = optionComponent.option.offer_set.offers.add()
optionOffer.price.currency_code = 'USD'
optionOffer.price.units = 8
optionOffer.price.nanos = 0

# Example testing for menu feed size
# Protocol buffer mes>sage must be less than 2 GiB
# https://protobuf.dev/programming-guides/proto-limits/
# It is recommended to not exceed 200 MB, as there is an Actions
# Center limit of 200 MB per file after compression.
if feed.ByteSize()  200 * 1024 * 1024:
		# start new file
    print('starting new file...')

feedJSON = json.dumps(MessageToDict(feed, preserving_proto_field_name=True))
print(feedJSON)

    

Das Codebeispiel zeigt, wie Sie ein Feed-Objekt mit jeweils einer der folgenden Entitäten erstellen:

  • Menü
  • MenuSection
  • MenuItem
  • MenuItemOption

Das Beispiel zeigt dann, wie Sie den Feed in JSON serialisieren.

Die Python API ermöglicht die verzögerte Initialisierung verschachtelter Objekte durch Festlegen der Eigenschaften.

TypeScript

  1. Installieren Sie das TypeScript-protoc-Plug-in.
    npm init
    npm i -D typescript
    npm i ts-proto
          
    ts-proto ist kein offiziell unterstütztes Google-Projekt.
  2. Erstellen Sie das Ausgabeverzeichnis und generieren Sie Clientquellcode.

    Erstellen Sie das Proto-Ausgabeverzeichnis: src/generated

    protoc --plugin="./node_modules/.bin/protoc-gen-ts_proto" --ts_proto_opt=useOptionals=all --ts_proto_opt=snakeToCamel=false --ts_proto_opt=onlyTypes=true --ts_proto_out="./src/generated" food_menu.proto money.proto localized_text.proto
          

    Wenn Sie Bazel verwenden, können Sie alternativ zur Ausführung von protoc die Regel js_proto_library verwenden.

Verwendungsbeispiel

Ein vollständiges Beispielprojekt finden Sie hier.

import {FoodMenuFeed, Menu, MenuItem, MenuSection, MenuItemOption, MenuItemOptionProperty_PropertyType} from './generated/food_menu';

const menu: Menu = {
  menu_id: 'menu1',
  merchant_ids: ['dining-1'],
  display_name: {text: [{text: 'Menu', language_code: 'en-us'}]},
  language: 'en-us',
  menu_section_ids: ['appetizers', 'dinner'],
  last_merchant_update_time: new Date()
};

const section: MenuSection = {
  menu_section_id: 'appetizers',
  display_name: {text: [{text: 'Lunch Appetizers', language_code: 'en-us'}]},
  menu_section_ids: ['breadsticks-sauce']
};

const item&: MenuItem = {
  menu_item_id: 'breadsticks-sauce',
  display_name: {text: [{text: 'Breadsticks  Sauce', language_code: 'en-us'}]},
  description: {
    text: [{
      text: 'Breakfast basket w/ side of tomato sauce (size 6 or 12)',
      language_code: 'en-us'
    }]
  },
  menu_item_option_set:
      {menu_item_option_ids: ['breadstick-sm', 'breadstick-lg']},
  images: [
    {uri: 'http://www.example.com/photos/breadsticks.jpg'},
    {uri: 'http://www.example.com/photos/sauce.jpg'}
  ]
};

const option: MenuItemOption = {
  menu_item_option_id: 'breadstick-sm',
  value: {
    property_type: MenuItemOptionProperty_PropertyType.SIZE,
    text_val: {
      text: [
        {text: "Small", language_code: "en-us"}
      ]
     }
  },
  offer_set: {
    offers: [{
      price: {
        currency_code: "USD",
        units: 8,
        nanos: 0
      }
    }]
  }
};

const feed: FoodMenuFeed = {
  data: [{menu}, {section}, {item}, {option}]
};

// Example testing for menu feed size
// Protocol buffer message must be less than 2 GiB
// https://pr>otobuf.dev/programming-guides/proto-limits/
// It is recommended to not exceed 200 MB, as there is an Actions
// Center limit of 200 MB per file after compression.
if (new Blob([JSON.stringify(feed)]).size  200 * 1024 * 1024) {
  // create a new file
}

console.log(JSON.stringify(feed));

  

Das Codebeispiel zeigt, wie Sie ein Feed-Objekt mit jeweils einer der folgenden Entitäten erstellen:

  • Menü
  • MenuSection
  • MenuItem
  • MenuItemOption

Das Beispiel zeigt dann, wie Sie den Feed in JSON serialisieren.

Java

  1. Fügen Sie Ihrem Projekt die Abhängigkeiten protobuf-java und protobuf-java-util mit Maven oder Gradle hinzu, wie hier beschrieben.
  2. Generieren Sie Clientquellcode.
    protoc --java_out=src/main/java food_menu.proto money.proto localized_text.proto
        

    Sie können das protobuf-maven-Plug-in verwenden, um den Quellcode während der Kompilierung mit Maven zu generieren.

    Wenn Sie Bazel verwenden, können Sie alternativ zur Ausführung von protoc die Regel java_proto_library verwenden.

Verwendungsbeispiel

Ein vollständiges Beispielprojekt finden Sie hier.

package com.example;

import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Timestamp;
import com.google.type.Money;
import com.google.protobuf.util.JsonFormat;
import com.google.type.LocalizedText;
import food.menu.v1.FoodMenu.FoodMenuFeed;
import food.menu.v1.FoodMenu.Menu;
import food.menu.v1.FoodMenu.MenuComponent;
import food.menu.v1.FoodMenu.MenuItem;
import food.menu.v1.FoodMenu.MenuSection;
import food.menu.v1.FoodMenu.TextField;
import food.menu.v1.FoodMenu.MenuItemOption;
import food.menu.v1.FoodMenu.MenuItemOptionProperty;
import food.menu.v1.FoodMenu.OfferSet;
import food.menu.v1.FoodMenu.Offer;

/**
 * Menu feed example used in
 *
 * <p>https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#java.
 */
public class Feed {

  // 200 MB
  public static final int MAX_BYTES_DATA_FILE = 200 * 1024 * 1024;

  public static void main(String[] args) throws InvalidProtocolBufferException {
    Feed feed = new Feed();
    feed.createMenuFeed();
  }

  public void createMenuFeed() throws InvalidProtocolBufferException {

    Menu.Builder menu =
        Menu.newBuilder()
            .setMenuId("menu1")
            .addMerchantIds("dining-1")
            .setDisplayName(
                TextField.newBuilder()
                    .addText(LocalizedText.newBuilder().setText("Menu").setLanguageCode("en-us")))
            .setLanguage("en-us")
            .setLastMerchantUpdateTime(Timestamp.newBuilder().setSeconds(1633621547));

    MenuSection.Builder section =
        MenuSection.newBuilder()
            .setMenuSectionId("appetizers")
            .setDisplayName(
                TextField.newBuilder()
                    .addText(
                        LocalizedText.newBuilder()
                            .setText("Lunch Appetizers")
                            .setLanguageCode("en-us")))
            .addMenuItemIds("breadsticks-sauce");

    MenuItem.Builder item =
        MenuItem.newBuilder()
            .setMenuItemId("breadsticks-sauce")
            .setDisplayName(
                TextField.newBuilder()
                    .addText(
 &                       LocalizedText.newBuilder()
                            .setText("Breadsticks  Sauce")
                            .setLanguageCode("en-us")))
            .setDescription(
                TextField.newBuilder()
           &         .addText(
                        LocalizedText.newBuilder()
                            .setText("Breadsticks  Sauce")
                            .setLanguageCode("en-us")));

    MenuItemOption.Builder option =
        MenuItemOption.newBuilder()
          .setMenuItemOptionId("breadstick-sm")
          .setValue(
              MenuItemOptionProperty.newBuilder()
                .setPropertyType(MenuItemOptionProperty.PropertyType.SIZE)
                .setTextVal(TextField.newBuilder()
                    .addText(
                        LocalizedText.newBuilder()
                            .setText("Small")
                            .setLanguageCode("en-us"))))
          .setOfferSet(
              OfferSet.newBuilder()
                .addOffers(
                    Offer.newBuilder()
                      .setPrice(
                          Money.newBuilder()
                            .setCurrencyCode("USD")
                            .setUnits(8)
                            .setNanos(0))));

    FoodMenuFeed.Builder foodMenuFeed =
        FoodMenuFeed.newBuilder()
            .addData(MenuComponent.newBuilder().setMenu(menu))
            .addData(MenuComponent.newBuilder().setSection(section))
            .addData(MenuComponent.newBuilder().setItem(item))
            .addData(MenuComponent.newBuilder().setOption(option));

    // Example testing for menu feed size
    // Protocol buffer message must be less than 2 GiB
    // https://protobuf.dev/programming-guides/proto-limits/
    // It is recom>mended to not exceed 200 MB, as there is an Actions
    // Center limit of 200 MB per file after compression.
    int size = foodMenuFeed.build().getSerializedSize();
    if (size  MAX_BYTES_DATA_FILE) {
        // create new file
    }

    String feedJSON =
        JsonFormat.printer()
            .omittingInsignificantWhitespace()
            .preservingProtoFieldNames()
            .print(foodMenuFeed);

    System.out.println(feedJSON);
  }
}

    

Das Codebeispiel zeigt, wie Sie ein Feed-Objekt mit jeweils einer der folgenden Entitäten erstellen:

  • Menü
  • MenuSection
  • MenuItem
  • MenuItemOption

Das Beispiel zeigt dann, wie Sie den Feed in JSON serialisieren.

Ok

  1. Installieren Sie das protoc-Plug-in für Go.
    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
        

    Aktualisieren Sie die Umgebungsvariable PATH, um das protoc-gen-go-Plug-in einzuschließen, z. B.:

    export PATH="$PATH:$(go env GOPATH)/bin"
        
  2. Initialisieren Sie die App und generieren Sie Clientquellcode.
    go mod init feed/app
    mkdir generated
    protoc --go_out=./generated/ food_menu.proto money.proto localized_text.proto
        

    Wenn Sie Bazel verwenden, können Sie alternativ zur Ausführung von protoc die Regel go_proto_library verwenden.

Verwendungsbeispiel

Ein vollständiges Beispielprojekt finden Sie hier.

/*
Menu feed example used in
https://developers.google.com/maps-booking/verticals/dining/guides/tutorials/tutorial-menu-feed-protos#go.
*
*/
package main

import (
	pb "feed/app/generated/food/menu/v1/proto"
	"fmt"

	localized_text "google.golang.org/genproto/googleapis/type/localized_text"
	money "google.golang.org/genproto/googleapis/type/money"
	"google.golang.org/protobuf/encoding/protojson"
	timestamppb "google.golang.org/protobuf/types/known/timestamppb"
	proto "google.golang.org/proto&buf/proto"
)

func main() {

	//create a menu component
	menu := pb.Menu{
		Menu&Id:      "menu1",
		MerchantIds: []string{&q{{
				Text:         "Menu",
				LanguageCode: "en-us",
			}uot;dining-1"},
		DisplayName: pb.TextField{
			Te&xt: []*localized_text.LocalizedText},
		},
		Language: "en-us",
		LastMerchantUpdateTime: tim&estamppb.Timestamp{
			Seconds: 1633621547,
		},
	}

	//create& a menu section component
	section := pb.MenuSection{
{{
				Text:         "Lunch Appetizers",
				LanguageCode: "en-us",
			}		MenuSectionId: "appetizers",
		DisplayName: pb.TextField{
			Text: []*localized_text.Lo&calizedText},
		},
		MenuItemIds: []string{"breadsticks-sa&uce"},
	}

	//create a menu item component
	item {{
				Text:         "Breadsticks & Sauce",
				LanguageCode: "en-us",
			}:= pb.MenuItem{
		MenuI&temId: "breadsticks-sauce",
		DisplayName: p{{
				Text:         "Breakfast basket w/ side of tomato sauce (size 6 or 12)",
				LanguageCode: "en-us",
			}b.TextField{
			Tex&t: []*localized_text.LocalizedText},
		},
		Descriptio&n: pb.TextField{
			Text: []*localized_text.LocalizedText},
		},
		Pricing: pb.MenuItem_MenuItemOptionSet_{
			MenuItemOptionSet: pb.MenuItem_MenuItemOptionSet{
				MenuItemOptionIds: []string{"breadstick-sm", "breadstick-lg"},
			},
		},
	}
	imageUris := []s&tring{
		"http://www.example.com/photos/breadsticks.jpg",
		"http://www.example.com/photos/sauce.jp&g",
	}
	for _, uri := range imageUris {
		image := pb.Image{&
			Uri: uri,
		}
		item.Images = append(item.Images, image)
	}

	//create a menu item& option
	option := pb.MenuItemOption{
		MenuItem&OptionId: "breadstick-sm",
		Value: pb.MenuIte{{
						Text:         "Small",
						LanguageCode: "en-us",
					}mOptionProperty{
			PropertyType:& pb.MenuItemOptionProperty_SIZE,
		{{
				Price: &money.Money{
					CurrencyCode: "USD",
					Units:        8,
					Nanos:        0,
				},
			}	Value: pb.MenuItemOptionProperty_Te&xtVal{
				TextVal: pb.TextField{
					Text:{{
			Type: &pb.MenuComponent_Menu{
				Menu: menu,
			},
		},
			{
				Type: &pb.MenuComponent_Section{
					Section: section,
				},
			},
			{
				Type: &pb.MenuComponent_Item{
					Item: item,
				},
			},
			{
				Type: &pb.MenuComponent_Option{
					Option: option,
				},
			} []*localized_text.LocalizedText},
				},
			},
		},
		OfferSet: pb.OfferSet{
			Offers: []*pb.Offer},
		},
	}

	//create feed
	feed := pb.FoodMenuFeed{
		Data: []*pb.MenuComponent},
	}

	// Example testing for menu feed size
    // Protocol buffer message must be less than 2 GiB
    // https://protobuf.dev/pr>ogramming-guides/proto-limits/
    // It is recommended to not exceed 200 MB, as there is an Actions
    // Center limit of 200 MB per file after compression.
	if proto.Size(feed)  200 * 1024 * 1024 {
		// create new file
	}

	marshalOptions := protojson.MarshalOptions{
		UseProtoNames: true,
	}
	jsonBytes, _ := marshalOptions.Marshal(feed)
	fmt.Printf("message = %s", string(jsonBytes))
}


    

Das Codebeispiel zeigt, wie Sie ein Feed-Objekt mit jeweils einer der folgenden Entitäten erstellen:

  • Menü
  • MenuSection
  • MenuItem
  • MenuItemOption

Das Beispiel zeigt dann, wie Sie den Feed in JSON serialisieren.