Generate client libraries

A machine-readable version of the Order with Google data feed and fulfillment API definitions are made available to generate client codes and validate the structure of JSON data. This allows you to spend more time in developing application capabilities and business logic required for the integration.

In this example, we use quicktype CLI to generate an easy-to-use client library.

Download the JSON Schemas

These machine-readable versions of data feeds and APIs are needed for code generation and validation.

Generate codes

Quicktype can be used to regenerate codes when APIs are changed so you can simply update the affected application code. QuickType supports C++, Java, JavaScript, Python and other programming languages.

You can also use other available code generator tools that support JSON Schema definitions to generate the client libraries.

Use Node package manager (npm) to install quicktype in the project directory for your Order with Google integration.

npm install quicktype

TypeScript

  1. Generate client codes for Order with Google data feeds.
    quicktype --lang typescript --src-lang schema inventory-v2-json-schema.json#top_level_definitions/ -o ./ts/fo-inventory.ts
            
  2. Generate client codes for fulfillment actions.
    quicktype --lang typescript --src-lang schema fulfillment-actions-json-schema.json#top_level_definitions/ -o ./ts/fo-fulfillment.ts
            
  3. Copy the generated files to your workspace and implement your business logic.

Usage and validation

Example of creating entities and converting them to JSON:

import { Convert, Fee, OperationHours, Restaurant, Service, ServiceArea, ServiceHours, Menu, MenuSection, Availability, MenuItem, MenuItemOption, MenuItemOffer, FeeType, FeeTypeEnum, RestaurantType } from "./fo-inventory";
import * as inventorySchema from '../inventory-v2-json.schema.json'

const ajv = new Ajv()

var restaurant: Restaurant = {
    "@id": "McDonalds",
    "@type": RestaurantType.Restaurant,
    "addressCountry": "US",
    "addressLocality": "123 Local",
    "addressRegion": "Region",
    "name": "MacDonald's",
    "postalCode": "1234",
    "streetAddress": "123",
    "telephone": "+15552999983",
    "url": "https://example.com"
}

var fee: Fee = {
    "@id": "123",
    "@type": FeeTypeEnum.Fee,
    "priceCurrency": "US",
    "serviceId": "123",
    "feeType": FeeType.Delivery
}

console.log(Convert.restaurantToJson(restaurant));
    

Java

  1. Generate client codes for Order with Google data feeds.
    quicktype --lang java --src-lang schema inventory-v2-json-schema.json#top_level_definitions/ -o ./java/ --package com.example
            
  2. Generate client codes for fulfillment actions.
    quicktype --lang java --src-lang schema fulfillment-actions-json-schema.json#top_level_definitions/ -o ./java/ --package com.example
            
  3. Copy the generated files to your workspace and implement your business logic.

Usage and validation

Example of creating entities and converting them to JSON:

package com.example;

import com.example.Converter;
import com.example.Fee;
import com.example.FeeType;
import com.example.Restaurant;
import com.example.RestaurantType;

public class FoodOrderingResponse {
    public static void main(String[] args) {
        Restaurant restaurant = new Restaurant();
        restaurant.setId("MacDonalds");
        restaurant.setType(RestaurantType.RESTAURANT);
        restaurant.setAddressCountry("US");
        restaurant.setAddressLocality("123 Local");
        restaurant.setAddressRegion("Region");
        restaurant.setName("MacDonald's");
        restaurant.setPostalCode("1234");
        restaurant.setStreetAddress("123");
        restaurant.setTelephone("+15552999983");
        restaurant.setUrl("https://example.com");

        Fee fee = new Fee();
        fee.setId("123");
        fee.setType(FeeTypeEnum.FEE);
        fee.setPriceCurrency("US");
        fee.setServiceId("123");
        fee.setFeeType(FeeType.DELIVERY);

        String restaurantJson = Converter.RestaurantToJsonString(restaurant);
        String feeJson = Converter.FeeToJsonString(fee);
    }
}
    

JavaScript

  1. Generate client codes for Order with Google data feeds.
    quicktype --lang javascript --src-lang schema inventory-v2-json-schema.json#top_level_definitions/ -o inventory.js
            
  2. Generate client codes for fulfillment actions.
    quicktype --lang javascript --src-lang schema fulfillment-actions-json-schema.json#top_level_definitions/ -o fulfillment.js
            
  3. Copy the generated files to your workspace and implement your business logic.

Usage and validation

Example of creating entities and converting them to JSON:

// Converts JSON strings to/from your types
// and asserts the results of JSON.parse at runtime
function toRestaurant(json) {
    return cast(JSON.parse(json), r("Restaurant"));
}

function restaurantToJson(value) {
    return JSON.stringify(uncast(value, r("Restaurant")), null, 2);
}

function invalidValue(typ, val, key = '') {
    if (key) {
        throw Error(`Invalid value for key "${key}". Expected type ${JSON.stringify(typ)} but got ${JSON.stringify(val)}`);
    }
    throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`, );
}

function jsonToJSProps(typ) {
    if (typ.jsonToJS === undefined) {
        const map = {};
        typ.props.forEach((p) => map[p.json] = { key: p.js, typ: p.typ });
        typ.jsonToJS = map;
    }
    return typ.jsonToJS;
}

function jsToJSONProps(typ) {
    if (typ.jsToJSON === undefined) {
        const map = {};
        typ.props.forEach((p) => map[p.js] = { key: p.json, typ: p.typ });
        typ.jsToJSON = map;
    }
    return typ.jsToJSON;
}

function transform(val, typ, getProps, key = '') {
    function transformPrimitive(typ, val) {
        if (typeof typ === typeof val) return val;
        return invalidValue(typ, val, key);
    }

    function transformUnion(typs, val) {
        // val must validate against one typ in typs
        const l = typs.length;
        for (let i = 0; i < l; i++) {
            const typ = typs[i];
            try {
                return transform(val, typ, getProps);
            } catch (_) {}
        }
        return invalidValue(typs, val);
    }

    function transformEnum(cases, val) {
        if (cases.indexOf(val) !== -1) return val;
        return invalidValue(cases, val);
    }

    function transformArray(typ, val) {
        // val must be an array with no invalid elements
        if (!Array.isArray(val)) return invalidValue("array", val);
        return val.map(el => transform(el, typ, getProps));
    }

    function transformDate(val) {
        if (val === null) {
            return null;
        }
        const d = new Date(val);
        if (isNaN(d.valueOf())) {
            return invalidValue("Date", val);
        }
        return d;
    }

    function transformObject(props, additional, val) {
        if (val === null || typeof val !== "object" || Array.isArray(val)) {
            return invalidValue("object", val);
        }
        const result = {};
        Object.getOwnPropertyNames(props).forEach(key => {
            const prop = props[key];
            const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined;
            result[prop.key] = transform(v, prop.typ, getProps, prop.key);
        });
        Object.getOwnPropertyNames(val).forEach(key => {
            if (!Object.prototype.hasOwnProperty.call(props, key)) {
                result[key] = transform(val[key], additional, getProps, key);
            }
        });
        return result;
    }

    if (typ === "any") return val;
    if (typ === null) {
        if (val === null) return val;
        return invalidValue(typ, val);
    }
    if (typ === false) return invalidValue(typ, val);
    while (typeof typ === "object" && typ.ref !== undefined) {
        typ = typeMap[typ.ref];
    }
    if (Array.isArray(typ)) return transformEnum(typ, val);
    if (typeof typ === "object") {
        return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val)
            : typ.hasOwnProperty("arrayItems")    ? transformArray(typ.arrayItems, val)
            : typ.hasOwnProperty("props")         ? transformObject(getProps(typ), typ.additional, val)
            : invalidValue(typ, val);
    }
    // Numbers can be parsed by Date but shouldn't be.
    if (typ === Date && typeof val !== "number") return transformDate(val);
    return transformPrimitive(typ, val);
}

function cast(val, typ) {
    return transform(val, typ, jsonToJSProps);
}

function uncast(val, typ) {
    return transform(val, typ, jsToJSONProps);
}

function a(typ) {
    return { arrayItems: typ };
}

function u(...typs) {
    return { unionMembers: typs };
}

function o(props, additional) {
    return { props, additional };
}

function m(additional) {
    return { props: [], additional };
}

function r(name) {
    return { ref: name };
}

const typeMap = {
    "Restaurant": o([
        { json: "@id", js: "@id", typ: "" },
        { json: "@type", js: "@type", typ: r("Type") },
        { json: "addressCountry", js: "addressCountry", typ: "" },
        { json: "addressLocality", js: "addressLocality", typ: "" },
        { json: "addressRegion", js: "addressRegion", typ: "" },
        { json: "dateModified", js: "dateModified", typ: u(undefined, Date) },
        { json: "description", js: "description", typ: u(undefined, "") },
        { json: "latitude", js: "latitude", typ: u(undefined, 3.14) },
        { json: "longitude", js: "longitude", typ: u(undefined, 3.14) },
        { json: "name", js: "name", typ: "" },
        { json: "postalCode", js: "postalCode", typ: "" },
        { json: "sameAs", js: "sameAs", typ: u(undefined, "") },
        { json: "streetAddress", js: "streetAddress", typ: "" },
        { json: "telephone", js: "telephone", typ: u(undefined, "") },
        { json: "url", js: "url", typ: u(undefined, "") },
    ], false),
    "Type": [
        "Restaurant",
    ],
};

module.exports = {
    "restaurantToJson": restaurantToJson,
    "toRestaurant": toRestaurant,
};
    

Python

  1. Generate client codes for Order with Google data feeds.
    quicktype --lang python --src-lang schema inventory-v2-json-schema.json#top_level_definitions/ -o inventory.py
            
  2. Generate client codes for fulfillment actions.
    quicktype --lang python --src-lang schema fulfillment-actions-json-schema.json#top_level_definitions/ -o fulfillment.py
            
  3. Copy the generated files to your workspace and implement your business logic.

Usage

Example of creating entities and converting them to JSON:

class RestaurantType(Enum):
    RESTAURANT = "Restaurant"

class Restaurant:
    """A required entity to implement. Describes a restaurant."""
    """A unique identifier of the restaurant or delivery provider."""
    id: str
    type: RestaurantType
    """Two-letter ISO 3166-1 alpha-2 country code."""
    address_country: str
    """The locality or city."""
    address_locality: str
    """The region or state."""
    address_region: str
    """The last modified date and time of the Restaurant entity feed in ISO timestamp format but
    with type String.
    """
    date_modified: Optional[datetime]
    """A description of the restaurant."""
    description: Optional[str]
    """Latitude in degrees. Values are restricted to the range [[-90, 90]].

    The precision should be at least 5 decimal places.
    """
    latitude: Optional[float]
    """Longitude in degrees. Values are restricted to the range [[-180, 180]].

    The precision should be at least 5 decimal places.
    """
    longitude: Optional[float]
    """Name of the restaurant."""
    name: str
    """The postal code."""
    postal_code: str
    """The official website for the restaurant."""
    same_as: Optional[str]
    """The street address of the restaurant."""
    street_address: str
    """Telephone number of the restaurant."""
    telephone: Optional[str]
    """The URL that represents the restaurant. The restaurant domain is preferred over the
    aggregator domain.
    """
    url: Optional[str]

    def __init__(self, id: str, type: RestaurantType, address_country: str, address_locality: str, address_region: str, date_modified: Optional[datetime], description: Optional[str], latitude: Optional[float], longitude: Optional[float], name: str, postal_code: str, same_as: Optional[str], street_address: str, telephone: Optional[str], url: Optional[str]) -> None:
        self.id = id
        self.type = type
        self.address_country = address_country
        self.address_locality = address_locality
        self.address_region = address_region
        self.date_modified = date_modified
        self.description = description
        self.latitude = latitude
        self.longitude = longitude
        self.name = name
        self.postal_code = postal_code
        self.same_as = same_as
        self.street_address = street_address
        self.telephone = telephone
        self.url = url

    @staticmethod
    def from_dict(obj: Any) -> 'Restaurant':
        assert isinstance(obj, dict)
        id = from_str(obj.get("@id"))
        type = RestaurantType(obj.get("@type"))
        address_country = from_str(obj.get("addressCountry"))
        address_locality = from_str(obj.get("addressLocality"))
        address_region = from_str(obj.get("addressRegion"))
        date_modified = from_union([from_datetime, from_none], obj.get("dateModified"))
        description = from_union([from_str, from_none], obj.get("description"))
        latitude = from_union([from_float, from_none], obj.get("latitude"))
        longitude = from_union([from_float, from_none], obj.get("longitude"))
        name = from_str(obj.get("name"))
        postal_code = from_str(obj.get("postalCode"))
        same_as = from_union([from_str, from_none], obj.get("sameAs"))
        street_address = from_str(obj.get("streetAddress"))
        telephone = from_union([from_str, from_none], obj.get("telephone"))
        url = from_union([from_str, from_none], obj.get("url"))
        return Restaurant(id, type, address_country, address_locality, address_region, date_modified, description, latitude, longitude, name, postal_code, same_as, street_address, telephone, url)

    def to_dict(self) -> dict:
        result: dict = {}
        result["@id"] = from_str(self.id)
        result["@type"] = to_enum(RestaurantType, self.type)
        result["addressCountry"] = from_str(self.address_country)
        result["addressLocality"] = from_str(self.address_locality)
        result["addressRegion"] = from_str(self.address_region)
        result["dateModified"] = from_union([lambda x: x.isoformat(), from_none], self.date_modified)
        result["description"] = from_union([from_str, from_none], self.description)
        result["latitude"] = from_union([to_float, from_none], self.latitude)
        result["longitude"] = from_union([to_float, from_none], self.longitude)
        result["name"] = from_str(self.name)
        result["postalCode"] = from_str(self.postal_code)
        result["sameAs"] = from_union([from_str, from_none], self.same_as)
        result["streetAddress"] = from_str(self.street_address)
        result["telephone"] = from_union([from_str, from_none], self.telephone)
        result["url"] = from_union([from_str, from_none], self.url)
        return result