为具有18个依赖项的实体编写REST API

时间:2017-04-04 21:58:05

标签: php json rest angular

我正在编写REST API以将表公开给Angular前端,我遇到过这种情况: 除了与主实体相对应的类(我们称之为“Ticket”)之外,我需要显示的数据位于大约10个其他表中。必须通过检查许多关联实体中的行之间建立的关系来访问其中一些数据。总的来说,我需要查询19个表,以便显示与一个Ticket行相关的完整数据集。

困难在于:我可以在这个API中编写代码来从所有这些其他表中检索数据 - 当然,没问题,就像25个方法调用一样,虽然可能有点慢,但是可以容忍。但是为了将数据返回到前端,GET响应将由一个扭曲的JSON块组成,其中包含不同级别的不同数量的成员。由于JSON的复杂性和脆弱性,这将使得利用Angular的数据变得困难。 这个问题的另一端是关于Angular的POSTing和PUTing数据。修改Ticket的表单可以连接到相同的结构以最小化HTTP请求(构造一些令人厌恶的JSON,修改它的一小部分并将其余部分保持不变等),或者可以连接到单个REST端点以单独与表格接口,牺牲了大量的速度,以便在有效载荷方面获得简单性。

这个特定的应用程序(一个内部企业工具)可能永远不会有超过五个或十个用户在任何给定时刻登录,因此从服务器的角度来看,大量的流量不是一个大问题,但是做类似的事情十几个链式HTTP请求显然是一个可怕的设计决策,而另一方面,使用特殊的,基本上条件结构的JSON响应与Angular接口似乎是一个同样令人憎恶的设计决定。

有关如何纠正此问题的任何建议?我是否坚持使用其中一种选择?感谢。

编辑: 数据库看起来或多或少像这样(简化版)。 门票有6个FK;通过这些表和多个关联表,这些表中的每一个都存在关系。

CREATE TABLE profileType (
  profileTypeId INT UNSIGNED NOT NULL,
  profileTypeName VARCHAR (16) NOT NULL,

  UNIQUE (profileTypeName),
  PRIMARY KEY (profileTypeId)
);

CREATE TABLE profile (
  profileId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  profileType INT UNSIGNED NOT NULL,
  profileEmail VARCHAR (128) NOT NULL,
  profileUserName VARCHAR (32) NOT NULL,
  profileFirstName VARCHAR (32) NOT NULL,
  profileLastName VARCHAR (64) NOT NULL,
  profileSalt CHAR (64) NOT NULL,
  profileHash CHAR (128) NOT NULL,
  profileActivationToken VARCHAR (32),

  INDEX (profileFirstName),
  INDEX (profileLastName),
  UNIQUE (profileEmail),
  UNIQUE (profileUserName),
  FOREIGN KEY (profileType) REFERENCES profileType (profileTypeId),
  PRIMARY KEY (profileId)
);

CREATE TABLE site (
  siteId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  siteName VARCHAR (128) NOT NULL,
  siteLab VARCHAR (64) NOT NULL,
  siteG2Id VARCHAR (8) NOT NULL,
  siteIsOsm TINYINT UNSIGNED NOT NULL,
  siteAsBuilt VARCHAR (128),

  INDEX (siteG2Id),
  INDEX (siteLab),
  INDEX (siteIsOsm),
  UNIQUE (siteName),
  PRIMARY KEY (siteId)
);

CREATE TABLE contact (
  contactId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  contactLandPhone CHAR (10),
  contactCellPhone CHAR (10),
  contactEmail VARCHAR (255) NOT NULL,
  contactFirstName VARCHAR (32) NOT NULL,
  contactLastName VARCHAR (64) NOT NULL,

  INDEX (contactLandPhone),
  INDEX (contactCellPhone),
  INDEX (contactFirstName),
  INDEX (contactLastName),
  UNIQUE (contactEmail),
  PRIMARY KEY (contactId)
);

CREATE TABLE contactType (
  contactTypeId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  contactTypeName VARCHAR (64) NOT NULL,

  UNIQUE (contactTypeName),
  PRIMARY KEY (contactTypeId)
);

CREATE TABLE contactContactType (
  contactContactTypeContactId INT UNSIGNED NOT NULL,
  contactContactTypeContactTypeId INT UNSIGNED NOT NULL,

  FOREIGN KEY (contactContactTypeContactId) REFERENCES contact (contactId),
  FOREIGN KEY (contactContactTypeContactTypeId) REFERENCES contactType (contactTypeId),
  PRIMARY KEY (contactContactTypeContactId, contactContactTypeContactTypeId)
);

CREATE TABLE ticketCategory (
  ticketCategoryId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  ticketCategoryName VARCHAR (12) NOT NULL,

  UNIQUE (ticketCategoryName),
  PRIMARY KEY (ticketCategoryId)
);

CREATE TABLE ticketSubCategory (
  ticketSubCategoryId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  ticketSubCategoryCategoryId INT UNSIGNED NOT NULL,
  ticketSubCategoryName VARCHAR (64) NOT NULL,

  UNIQUE (ticketSubCategoryName),
  FOREIGN KEY (ticketSubCategoryCategoryId) REFERENCES ticketCategory (ticketCategoryId),
  PRIMARY KEY (ticketSubCategoryId)
);

CREATE TABLE ticket (
  ticketId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  ticketSiteId INT UNSIGNED NOT NULL,
  ticketCategory INT UNSIGNED NOT NULL,
  ticketSubCategory INT UNSIGNED NOT NULL,
  ticketCaller INT UNSIGNED NOT NULL,
  ticketCreatedBy INT UNSIGNED NOT NULL,
  ticketDateTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
  ticketReason VARCHAR (256) NOT NULL,
  ticketSymptom VARCHAR (256) NOT NULL,
  ticketSummary VARCHAR (512) NOT NULL,
  ticketLastEdited TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL,
  ticketLastEditedBy INT UNSIGNED NOT NULL,
  ticketIsStageTwo TINYINT UNSIGNED NOT NULL,
  ticketIsResolved TINYINT UNSIGNED NOT NULL,
  ticketResolvedDateTime TIMESTAMP NULL DEFAULT NULL,

  INDEX (ticketDateTime),
  INDEX (ticketIsStageTwo),
  INDEX (ticketIsResolved),
  INDEX (ticketResolvedDateTime),
  FOREIGN KEY (ticketSiteId) REFERENCES site (siteId),
  FOREIGN KEY (ticketCategory) REFERENCES ticketCategory (ticketCategoryId),
  FOREIGN KEY (ticketSubCategory) REFERENCES ticketSubCategory (ticketSubCategoryId),
  FOREIGN KEY (ticketCaller) REFERENCES contact (contactId),
  FOREIGN KEY (ticketCreatedBy) REFERENCES profile (profileId),
  FOREIGN KEY (ticketLastEditedBy) REFERENCES profile (profileId),
  PRIMARY KEY (ticketId)
);

CREATE TABLE message (
  messageId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  messageTicketId INT UNSIGNED NOT NULL,
  messageProfileId INT UNSIGNED NOT NULL,
  messageContent VARCHAR (2048),
  messageDateTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
  messageIsStageTwo TINYINT UNSIGNED NOT NULL,

  INDEX (messageDateTime),
  INDEX (messageIsStageTwo),
  FOREIGN KEY (messageTicketId) REFERENCES ticket (ticketId),
  FOREIGN KEY (messageProfileId) REFERENCES profile (profileId),
  PRIMARY KEY (messageId)
);

CREATE TABLE address (
  addressId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  addressSiteId INT UNSIGNED NOT NULL,
  addressStreetOne VARCHAR (64) NOT NULL,
  addressStreetTwo VARCHAR (64),
  addressCity VARCHAR (64),
  addressState CHAR (2),
  addressZip CHAR (5),

  INDEX (addressCity),
  INDEX (addressState),
  INDEX (addressZip),
  FOREIGN KEY (addressSiteId) REFERENCES site(siteId),
  PRIMARY KEY (addressId)
);

CREATE TABLE sentry (
  sentryId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  sentrySiteId INT UNSIGNED NOT NULL,
  sentrySn VARCHAR (32) NOT NULL,
  sentryLocation VARCHAR (64) NOT NULL,
  sentryName VARCHAR (64) NOT NULL,
  sentryEmail VARCHAR (255) NOT NULL,
  sentryEmailUserName VARCHAR (64) NOT NULL,
  sentryIp VARBINARY (16) NOT NULL,
  sentryPort VARCHAR (5) NOT NULL,
  sentryMac CHAR (12) NOT NULL,
  sentryGateway VARBINARY (16) NOT NULL,
  sentryMask VARBINARY (16) NOT NULL,
  sentryFirmwareVersion VARCHAR (16) NOT NULL,
  sentryInstallDate TIMESTAMP NOT NULL,

  INDEX (sentrySn),
  INDEX (sentryName),
  UNIQUE (sentryEmail),
  FOREIGN KEY (sentrySiteId) REFERENCES site(siteId),
  PRIMARY KEY (sentryId)
);

CREATE TABLE monitoring (
  monitoringId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  monitoringName VARCHAR (64) NOT NULL,
  monitoringSecurity VARCHAR (64) NOT NULL,
  monitoringObservation VARCHAR (64) NOT NULL,
  monitoringSiteId INT UNSIGNED NOT NULL,
  monitoringSn VARCHAR (32) NOT NULL,
  monitoringLocation VARCHAR (64) NOT NULL,
  monitoringOs VARCHAR (32) NOT NULL,
  monitoringSwVersion VARCHAR (16) NOT NULL,
  monitoringIp VARBINARY (16) NOT NULL,
  monitoringIsDhcp TINYINT UNSIGNED NOT NULL,
  monitoringOwnerIsYfh TINYINT UNSIGNED NOT NULL,
  monitoringInstallDate TIMESTAMP NOT NULL,

  INDEX (monitoringSn),
  FOREIGN KEY (monitoringSiteId) REFERENCES site(siteId),
  PRIMARY KEY (monitoringId)
);

CREATE TABLE seal (
  sealId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  sealSiteId INT UNSIGNED NOT NULL,
  sealSentryId INT UNSIGNED NOT NULL,
  sealSn VARCHAR (32) NOT NULL,
  sealIsWireless TINYINT UNSIGNED NOT NULL,

  INDEX (sealSn),
  FOREIGN KEY (sealSiteId) REFERENCES site (siteId),
  FOREIGN KEY (sealSentryId) REFERENCES sentry (sentryId),
  PRIMARY KEY (sealId)
);

CREATE TABLE sealSatellite (
  sealSatelliteId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  sealSatelliteSealId INT UNSIGNED NOT NULL,
  sealSatelliteSn VARCHAR (32) NOT NULL,

  UNIQUE (sealSatelliteSn),
  FOREIGN KEY (sealSatelliteSealId) REFERENCES seal (sealId),
  PRIMARY KEY (sealSatelliteId)
);

CREATE TABLE cap (
  capId INT UNSIGNED AUTO_INCREMENT NOT NULL,
  capTicketId INT UNSIGNED NOT NULL,
  capProfileId INT UNSIGNED NOT NULL,
  capDateTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
  capIsStageTwo TINYINT UNSIGNED NOT NULL,
  capContent VARCHAR (2048) NOT NULL,

  INDEX (capIsStageTwo),
  FOREIGN KEY (capProfileId) REFERENCES profile (profileId),
  FOREIGN KEY (capTicketId) REFERENCES ticket (ticketId),
  PRIMARY KEY (capId)
);

CREATE TABLE siteContact (
  siteContactSiteId INT UNSIGNED NOT NULL,
  siteContactContactId INT UNSIGNED NOT NULL,

  FOREIGN KEY (siteContactSiteId) REFERENCES site (siteId),
  FOREIGN KEY (siteContactContactId) REFERENCES contact (contactId),
  PRIMARY KEY (siteContactSiteId, siteContactContactId)
);

CREATE TABLE profileTicket (
  profileTicketProfileId INT UNSIGNED NOT NULL,
  profileTicketTicketId INT UNSIGNED NOT NULL,
  profileTicketTotalTime SMALLINT UNSIGNED NOT NULL,

  FOREIGN KEY (profileTicketProfileId) REFERENCES profile (profileId),
  FOREIGN KEY (profileTicketTicketId) REFERENCES ticket (ticketId),
  PRIMARY KEY (profileTicketProfileId, profileTicketTicketId)
);

CREATE TABLE sentryMonitoring (
  sentryMonitoringSentryId INT UNSIGNED NOT NULL,
  sentryMonitoringMonitoringId INT UNSIGNED NOT NULL,

  FOREIGN KEY (sentryMonitoringSentryId) REFERENCES sentry (sentryId),
  FOREIGN KEY (sentryMonitoringMonitoringId) REFERENCES monitoring (monitoringId),
  PRIMARY KEY (sentryMonitoringSentryId, sentryMonitoringMonitoringId)
);

1 个答案:

答案 0 :(得分:0)

编写API时,您必须考虑的一个基本问题是:此API是针对特定应用程序的,还是存在于使用它的特定应用程序之外?

这个问题的答案推动了很多决策制定过程。在某些情况下,(客户端)应用程序是关键组件,API的重点是为该应用程序提供信息,以便应用程序可以工作。因此,在这种情况下,您可以构建API,以便尽可能地支持特定应用程序的需求。

在其他情况下,API虽然现在是针对此特定应用程序构建的,但也可能用于支持其他应用程序(通常是移动应用程序,但有时还有其他Web应用程序甚至服务器应用程序)。在这种情况下,API具有不同的目标 - 在更一般的情况下有用。因此,更重要的是,API易于用于更广泛的用例 - 即,可能更符合业务领域而不是特定应用程序的需求。然后,让API暴露更多更简单的端点更有意义,如果这样可以更容易在不同情况下使用。

糟糕的是,回答这个基本问题并不总是那么容易 - 而且你自己在特定情况下的经验和知识必须指导你。

PS。我放弃了其他选项,例如,创建更简单的API,然后在其上构建复杂的特定于应用程序的API。但请注意,除了这两个选项之外还有其他选择。