proto/blueprint.proto (1,002 lines of code) (raw):
syntax = "proto3";
package com.gu.mobile.mapi.models.v0;
import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
// A prefix only used for the Swift models
option swift_prefix="Proto";
/************************* COLLECTION *************************/
// The following messages are used only to model the contents for our
// fronts endpoints.
message Collection {
string id = 1;
/**
* A palette at the collection level is currently mapped from MAPI's
* "navigation style". It's specified when the look and feel of an entire
* container should be changed, for example when a container is "branded"
* because the content has been paid for.
*/
optional Palette palette_light = 2;
optional Palette palette_dark = 3;
/**
* MAPI can technically return a list of empty rows. This might be because
* MAPI doesn't support the specific content that's included in the
* collection. In this case it's assumed the client will hide the entire
* collection from the reader.
* Another reason for empty rows is that the collection is a titlepiece.
* In fact, we must keep the rows empty in this case in order not to break
* old versions of app that were built before titlepiece is introduced.
*/
repeated Row rows = 4;
optional string title = 5;
/**
* We define branding at the collection level because certain containers
* require a different look and feel, for example content published by
* Guardian Labs.
*/
optional Branding branding = 6;
/**
* A container can be defined as "premium". Currently this is just for the
* Crosswords container for which only premium users are allowed to access
* (although it is visible to all users). Note that the Crosswords
* container is not curated by Editorial in the fronts tool but instead
* created on the fly by MAPI.
*/
optional bool premium_content = 7;
optional FollowUp follow_up = 8;
/**
* This tells the app whether or not to render a "show/hide" button at the
* top right of the container. For now, this is only used for thrashers,
* which should not be hideable by the user.
*/
bool hideable = 9;
optional MyGuardianFollow myguardian_follow = 10;
/**
* For some design on specific types of collections, we want to show
* an image and a description in the collection header. This field is
* used for award text if the collection design is
* COLLECTION_DESIGN_TITLEPIECE.
*/
optional string description = 11;
optional Image image = 12;
/**
* This tells the app which design to use to render the collection
*/
enum CollectionDesign {
COLLECTION_DESIGN_UNSPECIFIED = 0;
COLLECTION_DESIGN_REGULAR = 1;
COLLECTION_DESIGN_PODCAST = 2;
COLLECTION_DESIGN_TITLEPIECE = 3;
}
optional CollectionDesign design = 13;
/**
* When this attribute is true, the vertical spacing is removed from
* the collection.
*/
optional bool compact_padding = 14;
/**
* The property gives the ID of the collection to be used in
* the tracking data.
*/
optional string tracking_id = 15;
/**
* The property is added when we build small story carousel where
* the header is rendered in smaller size to show they are child
* sections within a main collection.
*/
optional bool small_heading = 16 [deprecated = true];
optional AdTargetingParams ad_targeting_params = 17;
optional string ad_unit = 18;
/**
* This tells the app in which style to display, or not display,
* the title. It should not be used any more as a new equivalent
* enum class named "TitleStyle" is defined on the top level.
*/
enum HeadingStyle {
HEADING_STYLE_UNSPECIFIED = 0;
HEADING_STYLE_HIDDEN = 1;
HEADING_STYLE_REGULAR = 2;
HEADING_STYLE_SMALL = 3;
}
/**
* This property is deprecated in favour of the property title_style.
* We still set this property to the same semantic value as
* the title style for backward compatibility.
*/
optional HeadingStyle heading_style = 19;
/**
* The title of this collection for display. It replaces
* the old "title" property.
*/
optional string display_title = 20;
optional google.protobuf.Timestamp last_updated_date = 21;
/**
* Control in what style to display the collection title.
*/
optional TitleStyle title_style = 22;
/**
* The default aspect ratio for trail images in this collection.
*/
optional ImageAspectRatio preferred_image_aspect_ratio = 23;
optional bool tighten_vertical_spacing = 24;
}
/**
* The follow up message contains links to get more information about the
* collection.
*/
message FollowUp {
enum FollowUpType {
FOLLOW_UP_TYPE_UNSPECIFIED = 0;
FOLLOW_UP_TYPE_LIST = 1;
FOLLOW_UP_TYPE_FRONT = 2;
FOLLOW_UP_TYPE_INAPP = 3;
}
FollowUpType type = 1;
string uri = 2;
/**
* At the time of creation MAPI couldn't support blueprint versions of the
* follow-on link so this field was marked as optional. As part of the
* migration work, MAPI will eventually support blueprint endpoints for all
* follow on links.
*/
optional string blueprint_uri = 3;
}
/**
* This is a special type of container on a front that is delivered via
* editorial tools.Thrashers are used to promote either features or
* commercial content.
*/
message Thrasher {
string uri = 1;
}
/************************* LIST *************************/
// The following messages are used only to model the contents of our
// list endpoints (tags, sections etc)
/**
* A list is similar to a collection, except it is responsible for
* serving the contents of list pages such as tags and sections,
* rather than fronts
*/
message List {
string title = 1;
/**
* The native app will call this URL when a user has scrolled to the bottom
* of the list and wants to load more content.
*/
optional string next_page_url = 2;
optional Palette palette_light = 3;
optional Palette palette_dark = 4;
repeated Row rows = 5;
optional Branding branding = 6;
repeated Topic topics = 7;
// use ad_unit instead
optional string ad_targeting_path = 8 [deprecated = true];
optional string previous_page_url = 9;
Tracking tracking = 10;
// Tells the app when rows to insert adverts before (not after!)
repeated int32 adverts = 11;
optional MyGuardianFollow my_guardian_follow = 12;
string id = 13;
/**
* This is only neded for tracking, but keeping out of the tracking
* message incase that changes
*/
optional string web_uri = 14;
AdTargetingParams ad_targeting_params = 15;
/**
* Needed on lists and articles. Collections use the adUnit defined
* in the fronts response (e.g uk/fronts/home)
*/
string ad_unit = 16;
optional google.protobuf.Timestamp last_updated_date = 17;
optional Header header = 18;
optional bool tighten_vertical_spacing = 19;
}
message Header {
string header_text = 1;
optional string description = 2;
HeaderType alignment = 3;
optional Palette palette_light = 4;
optional Palette palette_dark = 5;
optional Image image = 6;
}
enum HeaderType {
HEADER_TYPE_UNSPECIFIED = 0;
HEADER_TYPE_CENTRE = 1;
}
/************************* MY GUARDIAN *************************/
// The following messages are used only to model the contents of our
// My Guardian endpoints (grid, feed etc)
/**
* This message type is similar to Collection but with less information.
* It will be used when the client will decide how to lay out
* the collection instead of the server. This is useful for My Guardian
* where the client will need to deduplicate the content from multiple
* collections.
*/
message LayoutAgnosticCollection {
string id = 1;
/**
* A palette at the collection level is currently mapped from MAPI's
* "navigation style". It's specified when the look and feel of an entire
* container should be changed, for example when a container is "branded"
* because the content has been paid for.
*/
optional Palette palette_light = 2;
optional Palette palette_dark = 3;
/**
* Here we return a list of cards instead of rows. This means that
* the client will need to decide how to layout the cards.
*/
repeated Card cards = 4;
optional string title = 5;
optional FollowUp follow_up = 6;
/**
* The property gives the ID of the collection to be used in
* the tracking data.
*/
optional string tracking_id = 7;
optional Image image = 8;
}
/************************* SHARED *************************/
// The following messages shared between both the higher level
// collection and list messages.
message Palette {
string accent_colour = 1;
string background = 2;
string comment_count = 3;
string element_background = 4;
string headline = 5;
string immersive_kicker = 6;
string main = 7;
string media_background = 8;
string media_icon = 9;
string meta_text = 10;
string pill = 11;
string pillar = 12;
string secondary = 13;
string shadow = 14;
string top_border = 15;
/*
* Used for kicker text colour post Fairground updates. For Live cards,
* `pill` colour provides the background and `kicker_text` is the text
* colour.
*/
string kicker_text = 16;
/*
* The background colour of the pill on media cards.
*/
string media_pill_background = 17;
/*
* The foreground colour of the pill on media cards.
*/
string media_pill_foreground = 18;
}
message Links {
optional string related_uri = 1;
optional string short_url = 2;
string uri = 3;
optional string web_uri = 4;
}
enum MediaType {
MEDIA_TYPE_UNSPECIFIED = 0;
MEDIA_TYPE_VIDEO = 1;
MEDIA_TYPE_AUDIO = 2;
MEDIA_TYPE_IMAGE = 3;
}
message MediaPill {
string name = 1;
string icon = 2;
/*
The detail varies depending on the type of pill:
for a video or podcast, it's the duration,
for a gallery it's the number of images,
for a newsletter it's the frequency
*/
string detail = 3;
}
message Image {
optional string alt_text = 1;
optional string caption = 2;
optional string credit = 3;
optional int32 height = 4;
string url_template = 6;
optional int32 width = 7;
}
message Video {
optional string alt_text = 1;
optional string caption = 2;
optional string credit = 3;
optional int32 height = 4;
optional string orientation = 5;
string url = 6;
optional int32 width = 7;
optional string youtube_id = 8;
optional int32 duration_in_seconds = 9;
optional Image poster_image = 10;
bool is_live_video = 11;
}
message Audio {
string id = 1;
optional string source = 2;
optional int32 duration_in_seconds = 3;
string uri = 4;
string ad_free_uri = 5;
optional string mime_type = 6;
/*
The following fields are used to give article
information about the audio file that is being played
This is used for the `latestEpisode` feature on
the podcast series cards
*/
optional string article_id = 7;
optional Links links = 8;
optional string title = 9;
optional string byline = 10;
}
message PodcastSeries {
string id = 1;
string title = 2;
string url = 3;
optional FollowUp follow_up = 4;
optional Image image = 5;
optional string description = 6;
optional Audio latest_episode = 7;
}
// This message is only applicable to live blogs.
message LiveEvent {
string id = 1;
string title = 2;
string body = 3;
optional google.protobuf.Timestamp published_date = 4;
optional google.protobuf.Timestamp last_updated_date = 5;
}
message Branding {
string branding_type = 1;
string sponsor_name = 2;
string logo = 3;
string sponsor_uri = 4;
string label = 5;
string about_uri = 6;
optional string alt_logo = 7;
}
/**
* Control in what style to display a title.
*/
enum TitleStyle {
TITLE_STYLE_UNSPECIFIED = 0;
TITLE_STYLE_HIDDEN = 1;
TITLE_STYLE_REGULAR = 2;
TITLE_STYLE_SMALL = 3;
}
/**
* The rendering platform support object is required to support opening AR
* articles on native clients.We don't return this message if the corresponding
* article cannot be rendered by the server (instead only by legacy article
* templates).
*/
message RenderingPlatformSupport {
string min_bridget_version = 1;
string uri = 2;
}
/**
* The message provides the link to fetch the audio for listen-to-article
* feature on the article and other information for UI display.
*/
message ListenToArticle {
string audio_uri = 1;
int32 duration_in_seconds = 2;
}
message Article {
string id = 1;
optional string byline = 2;
repeated Image images = 3;
optional Links links = 4;
optional string kicker = 5;
optional string title = 6;
optional string trail_text = 7;
optional int32 rating = 8;
optional int32 comment_count = 9;
optional google.protobuf.Timestamp published_date = 10;
optional google.protobuf.Timestamp last_updated_date = 11;
optional MediaType media_type = 12;
// Only expected for video or audio content.
optional google.protobuf.Duration duration = 13;
// MAPI will never return both images and a profile_image.
optional Image profile_image = 14;
repeated LiveEvent events = 15;
optional Palette palette_light = 16;
optional Palette palette_dark = 17;
// Only applicable to podcasts.
optional string apple_podcast_url = 18;
// Only applicable to podcasts.
optional string google_podcast_url = 19;
// Only applicable to podcasts.
optional string spotify_podcast_url = 20;
repeated Video videos = 21;
/**
* This is an indicator as to whether a live blog is still blogging, or if
* it's been closed.
*/
optional bool is_live = 22;
// Only applicable to podcasts.
optional string pocket_cast_podcast_url = 23;
optional RenderingPlatformSupport rendered_item_prod = 24;
optional RenderingPlatformSupport rendered_item_beta = 25;
// Quoted headline shown for a card if selected in the fronts tool.
optional bool show_quoted_headline = 26;
// Only applicable to cards that display web content (e.g. snap links)
optional string web_content_uri = 27;
Tracking tracking = 28;
// Only applicable to podcast card
optional Audio audio = 29;
// Only applicable to podcast card
optional PodcastSeries podcast_series = 30;
AdTargetingParams ad_targeting_params = 31;
/**
* Needed on lists and articles whereas collections use the adUnit
* defined in the fronts response (e.g uk/fronts/home)
*/
optional string ad_unit = 32;
// field we get from CAPI set by the editorial team
bool should_hide_reader_revenue = 33;
// field we get from CAPI set by the editorial team
bool should_hide_adverts = 34;
// some design types (immersive/interactive) should hide the nav/tab bar
bool should_hide_nav = 35;
/**
* It is available when the listen-to-article is supported on this article
*/
optional ListenToArticle listen_to_article = 36;
/**
* Number of images in a gallery card. This is used to display gallery
* metadata on card when the media_type is MEDIA_TYPE_IMAGE.
*/
optional int32 gallery_image_count = 37;
repeated BasicTag basic_tags = 38;
// Only applicable to navigational card
optional FollowUp follow_up = 39;
// The pill details that media cards should display.
optional MediaPill media_pill = 40;
}
message Card {
enum CardType {
CARD_TYPE_UNSPECIFIED = 0;
CARD_TYPE_ARTICLE = 1;
CARD_TYPE_PODCAST = 2;
CARD_TYPE_VIDEO = 3;
CARD_TYPE_CROSSWORD = 4;
/**
* Display cards have their own separate design (see figma designs for
* ref).
*/
CARD_TYPE_DISPLAY = 5;
CARD_TYPE_NUMBERED = 6;
/**
* An empty card is used to indicate an empty space so that the native
* client do not stretch the previous card to occupy the space
*/
CARD_TYPE_EMPTY = 7;
/**
* Used when a card should display content using a web view. Initially
* this has been implemented for "snap links", which are atoms for a
* front placed inside a regular container alongside other cards.
*/
CARD_TYPE_WEB_CONTENT = 8;
/**
* A card showing a podcast series. Internally it is represented as
* a snaplink with the type "link" and a link url pointing at a podcast
* series tag.
*/
CARD_TYPE_PODCAST_SERIES = 9;
/**
* A card with a different design. It is intended for highlights
* containers.
* This value will be deprecated soon. We should set the card size
* to CARD_SIZE_HIGHLIGHTS instead.
*/
CARD_TYPE_HIGHLIGHT = 10;
CARD_TYPE_NAVIGATION = 11;
/**
* A card for a gallery item.
*/
CARD_TYPE_GALLERY = 12;
}
CardType type = 1;
/**
The article that this card is representing. It is optional
because not all cards will have an article associated with
them i.e Crosswords or Web content.
*/
optional Article article = 2;
/**
* Boosted cards show a boosted headline size.
* It will be deprecated after we have switched to card size and
* boost level to indicate the headline size.
*/
optional bool boosted = 3;
/**
* Compact cards don't show all the information that non-compact cards do,
* and tend to appear in a carousel.
* It will be deprecated after we have switched to card size and
* boost level to indicate the card size.
*/
optional bool compact = 4;
repeated Article sublinks = 5;
optional string html_fallback = 6;
/**
* Individual cards can be branded and not be part of a branded container.
* Cards that are branded tend to show the sponsor logo and should be
* returned with a different palette.
*/
optional Branding branding = 7;
/**
* Individual cards can be defined as "premium content". If premium_content
* is true then it implies the card should be hidden from signed-in users,
* for example if the card has been paid for by an external sponsor.
*/
optional bool premium_content = 8;
optional Palette sublinks_palette_light = 9;
optional Palette sublinks_palette_dark = 10;
/**
* This is the number to be used when the card type is CARD_TYPE_NUMBERED.
*/
optional int32 card_number = 11;
/**
* This optional field is set if this card type is CARD_TYPE_PODCAST_SERIES.
* It provides the details on the podcast series.
*/
optional PodcastSeries podcast_series = 12;
/**
* The correspondingTags is to denote which of the tags that a user has
* selected are applied to a particular content item
*/
repeated MyGuardianFollow corresponding_tags = 37;
/**
* Mega-boosted cards show a even larger headline size.
* It is deprecated as we switch to card size and boost level to
* indicate the headline size.
*/
optional bool mega_boosted = 38 [deprecated = true];
/**
* Indicate how many columns the trail image is expected to take.
* It is deprecated as we switch to card size and boost level to
* indicate in what size to display the trail image.
*/
optional int32 trail_image_size = 39 [deprecated = true];
/**
* Deprecated field. It was the aspect ratio for trail image but
* it was no longer needed because the card size can imply the image
* aspect ratio needed. When a card size can support a new image
* aspect ratio and the old 5:3 crop, the native can check
* the preferred_image_aspect_ratio property in the collection.
*/
reserved 40;
reserved "trail_image_aspect_ratio";
/**
* Define constants for the arrangement of sublinks on a card
*/
enum SublinksArrangement {
SUBLINKS_ARRANGEMENT_UNSPECIFIED = 0;
SUBLINKS_ARRANGEMENT_VERTICAL = 1;
SUBLINKS_ARRANGEMENT_HORIZONTAL = 2;
}
/**
* Indicate how sublinks are arranged.
* It is deprecated as it is replaced by a new field named
* preferred_sublinks_arrangement.
*/
optional SublinksArrangement sublinks_arrangement = 41 [deprecated = true];
/**
* Define different levels for headline size
*/
enum BoostedHeadline {
BOOSTED_HEADLINE_UNSPECIFIED = 0;
BOOSTED_HEADLINE_STANDARD = 1;
BOOSTED_HEADLINE_BOOSTED_1 = 2;
BOOSTED_HEADLINE_BOOSTED_2 = 3;
BOOSTED_HEADLINE_BOOSTED_3 = 4;
BOOSTED_HEADLINE_BOOSTED_4 = 5;
}
/**
* Indicate the size of a headline.
* It is deprecated as we switch to card size and boost level to
* indicate the headline size.
*/
optional BoostedHeadline boosted_headline = 42 [deprecated = true];
/**
* Define constants for positions to display the headline in a card.
*/
enum HeadlinePosition {
HEADLINE_POSITION_UNSPECIFIED = 0;
HEADLINE_POSITION_INLINE = 1;
HEADLINE_POSITION_TOP = 2;
}
/**
* Indictate where to display the headline.
* It is deprecated as the headline position is implied by
* the card size.
*/
optional HeadlinePosition headline_position = 43 [deprecated = true];
/**
* Define card sizes
*/
enum CardSize {
CARD_SIZE_UNSPECIFIED = 0;
CARD_SIZE_X_SMALL = 1;
CARD_SIZE_SMALL = 2;
CARD_SIZE_MEDIUM_HORIZONTAL = 3;
CARD_SIZE_MEDIUM_VERTICAL = 4;
CARD_SIZE_LARGE = 5;
CARD_SIZE_LARGE_HORIZONTAL = 6;
CARD_SIZE_X_LARGE = 7;
CARD_SIZE_HIGHLIGHTS = 8;
CARD_SIZE_X_LARGE_HORIZONTAL = 9;
}
optional CardSize card_size = 44;
optional int32 boost_level = 45;
/**
* Indicate how sublinks are arranged.
*/
optional SublinksArrangement preferred_sublinks_arrangement = 46;
/**
* Control how the top border is displayed.
*/
optional TopBorderStyle top_border_style = 47;
/**
* Control what font weight to use for the headline.
*/
optional FontWeight headline_weight = 48;
optional NavCardType nav_card_type = 49;
}
enum NavCardType {
NAV_CARD_TYPE_UNSPECIFIED = 0;
NAV_CARD_TYPE_NEWS = 1;
NAV_CARD_TYPE_SPORT = 2;
NAV_CARD_TYPE_LIFESTYLE = 3;
NAV_CARD_TYPE_NARRATIVE = 4;
}
enum TopBorderStyle {
TOP_BORDER_STYLE_UNSPECIFIED = 0;
TOP_BORDER_STYLE_HIDDEN = 1;
TOP_BORDER_STYLE_REGULAR = 2;
}
/**
* Define constants for each image aspect ratio supported
*/
enum ImageAspectRatio {
IMAGE_ASPECT_RATIO_UNSPECIFIED = 0;
IMAGE_ASPECT_RATIO_LANDSCAPE_5_3 = 1;
IMAGE_ASPECT_RATIO_LANDSCAPE_5_4 = 2;
IMAGE_ASPECT_RATIO_PORTRAIT_4_5 = 3;
IMAGE_ASPECT_RATIO_SQUARE = 4;
}
/**
* Define different levels for font weight
*/
enum FontWeight {
FONT_WEIGHT_UNSPECIFIED = 0;
FONT_WEIGHT_STANDARD = 1;
FONT_WEIGHT_LIGHT = 2;
}
message Column {
/**
* By default, if there are multiple cards in the cards array then it's
* expected the client will display these as stacked vertical elements.
*/
repeated Card cards = 1;
optional Palette palette_light = 2;
optional Palette palette_dark = 3;
// The card(s) in the column assume this preferred width.
int32 preferred_width = 4;
/**
* Decide whether to show horizontal dividers between cards which
* are stacked in this column.
*/
optional bool show_horizontal_dividers = 5;
}
message Row {
enum RowType {
ROW_TYPE_UNSPECIFIED = 0;
// Layout is the "default" way of laying out rows and columns.
ROW_TYPE_LAYOUT = 1;
ROW_TYPE_CAROUSEL = 2;
/**
* Used when the entire row only contains web content, for example
* when thrashers are displayed inside a fixed/thrasher container.
*/
ROW_TYPE_WEB_CONTENT = 3;
/**
* New carousel style on some new collection types such as
* small story carousel on tablet
*/
ROW_TYPE_PROGRAMMATIC_CAROUSEL = 4;
}
repeated Column columns = 1;
/**
* Deprecate the palette_light property in a Row as we did
* not and will not use this property.
*/
reserved "palette_light";
reserved 2;
/**
* Deprecate the palette_dark property in a Row as we did
* not and will not use this property.
*/
reserved "palette_dark";
reserved 3;
/**
* Tablet devices support a 4 column display, whereas mobile devices
* support a 2 column display. If a mobile device receives a row with a
* preferred number of columns greater than 2, the additional columns are
* "wrapped" onto an extra row (a bit like CSS flex-wrap).
*/
int32 preferred_number_of_columns = 4;
optional Thrasher thrasher = 5;
RowType type = 6;
optional string title = 7;
/**
* When this attribute is true, the spacing in between cards in the row is
* reduced.
*/
optional bool tighten_spacing = 8;
/**
* Clicking the row title takes users to the page indicated by
* this attribute. The row title is not clickable if it is empty.
*/
optional FollowUp follow_up = 9;
/** Deprecated. It was the old heading style. */
reserved "heading_style";
reserved 10;
/**
* The property gives the ID for tracking data which is sent by
* the apps when users tap the row title.
*/
optional string tracking_id = 11;
/**
* Control in what style to display the row title.
*/
optional TitleStyle title_style = 12;
/**
* Decide whether to show vertical dividers in between cards on
* this row
*/
optional bool show_vertical_dividers = 13;
/**
* Decide whether to show horizontal dividers at the top of this row
*/
optional bool show_horizontal_dividers = 14;
}
message Topic {
string type = 1;
// let's change this to "id" in the future, name is a bit misleading
string name = 2;
string display_name = 3;
}
message MyGuardianFollow {
enum FollowType {
FOLLOW_TYPE_UNSPECIFIED = 0;
FOLLOW_TYPE_CONTRIBUTOR = 1;
FOLLOW_TYPE_KEYWORD = 2;
FOLLOW_TYPE_SERIES = 3;
FOLLOW_TYPE_SECTION = 4;
FOLLOW_TYPE_NEWSPAPER_BOOK_SECTION = 5;
FOLLOW_TYPE_NEWSPAPER_BOOK = 6;
FOLLOW_TYPE_BLOG = 7;
FOLLOW_TYPE_TONE = 8;
FOLLOW_TYPE_PUBLICATION = 9;
FOLLOW_TYPE_TRACKING = 10;
FOLLOW_TYPE_PAID_CONTENT = 11;
FOLLOW_TYPE_CAMPAIGN = 12;
FOLLOW_TYPE_TYPE = 13;
}
string id = 1;
string web_title = 2;
FollowType type = 3;
}
/** Used for advert targeting. We should perhaps consider moving
this into its own Commercial message along with adTargetingPath
in the future */
message AdTargetingParams {
map<string, string> ad_targeting = 4;
}
/** Tracking messages */
message Tracking {
Permutive permutive = 1;
/** For some lists and articles we return nielsen tracking data
depending on the section they belong to */
optional string nielsen_section = 2;
repeated BasicTag commissioning_desks = 3;
}
message Permutive {
string id = 1;
string type = 2;
optional string title = 3;
optional string section = 4;
repeated string authors = 5;
repeated string keywords = 6;
optional google.protobuf.Timestamp published_at = 7;
optional string series = 8;
}
/** For some articles we return commissioning desk tracking (aka BasicTag)
data based on if the article has a "tracking" tag which is set in CAPI.
Commissioning desk data will never be included at the upper list level.
*/
message BasicTag {
string id = 1;
string web_title = 2;
}
/************************* FOOTBALL *************************/
// The following messages are used to model the contents for our
// blueprint football endpoints. Currently a WIP and not in prod/beta.
/**
* A football team
*/
message Team {
/**
* Each team will have a unique numerical ID
*/
string id = 1;
/**
* The name of the team, i.e "Luton Town"
*/
string name = 2;
/**
* The short code name for the team, i.e "LUT"
*/
string short_code = 3;
/**
* The team's crest or flag for countries
*/
Image crest = 4;
}
/**
* Some leagues can have multiple tables, i.e group stage tables
*/
message TableGroups {
/**
* The name of the competition, i.e "UEFA Nations League"
*/
string competition_name = 1;
/**
* The table (or tables) for that league.
*/
repeated Table tables = 2;
}
/**
* A football table for either a competition or league.
* One competition/league may be composed of many tables
* in the case of those with groups. E.g., world cups
* have group stages.
*/
message Table {
/**
* The group name, for example "Group A". Only useful
* for competitions with groups.
*/
optional string group_name = 1;
/**
* Each team and their position in the table
*/
repeated TablePosition teams = 2;
}
/**
* A team, their position within a league and other stats,
* i.e Luton Town at 2nd place with n goal difference etc.
*/
message TablePosition {
/**
* A football team
*/
Team team = 1;
/**
* The team's position in the table, i.e 2 for 2nd place
*/
int32 position = 2;
/**
* The number of games played
*/
int32 played = 3;
/**
* The number of games won
*/
int32 won = 4;
/**
* The number of games drawn
*/
int32 drawn = 5;
/**
* The number of games lost
*/
int32 lost = 6;
/**
* The number of goals scored
*/
int32 goals_for = 7;
/**
* The number of goals conceded
*/
int32 goals_against = 8;
/**
* The goal difference
*/
int32 goal_difference = 9;
/**
* The number of points
*/
int32 points = 10;
// protolint:disable:next REPEATED_FIELD_NAMES_PLURALIZED
/**
* The recent form of the team
*
*/
repeated Form recent_form = 11;
/**
* Whether to show a divider after this team in the table
* to illustrate the relegation/promotion line
*/
bool show_divider = 12;
/**
* Tells you if a previous game was won, drawn or lost
*/
enum Form {
FORM_UNSPECIFIED = 0;
FORM_WIN = 1;
FORM_DRAW = 2;
FORM_LOSS = 3;
}
/**
* The in-app follow-up if the team is clicked.
* This will be used to navigate to the tag page for that team
*/
optional FollowUp follow_up = 13;
}
/**
* Each results/fixtures response will contain a list of match
* days for the chosen league. Fixtures will be returned in
* chronological order and matches in reverse chronological order.
*/
message CompetitionWithMatchDays {
/**
* The match days for the league
*/
repeated MatchDay match_days = 1;
/**
* The name of the competition, i.e "Premier League"
*/
string competition_name = 2;
}
message MatchDay {
/**
* The date of the match day. Will be the start of the day.
*/
google.protobuf.Timestamp date = 1;
/**
* i.e "Premier League" or if live "Premier League live"
*/
string match_day_name = 3;
/**
* The matches for the competition on the date
*/
repeated Match matches = 2;
}
message Match {
string id = 1;
Team home_team = 2;
Team away_team = 3;
google.protobuf.Timestamp kick_off = 4;
/**
* The score of the match, i.e "2-1". Optional as the match may not
* have started yet.
*/
optional string score = 5;
/**
* Could be the status of the match, i.e "FT" for full time
or an aggregate score, i.e "2-1" for a two legged match.
*/
optional string match_detail = 6;
/**
* The URL to retrieve the match report (if it exists),
* stats and topic for notification.
*/
optional string match_info_uri = 7;
}