Change all components to use the service for rest-api-interface

Change-Id: I3acf9269ff43f463aca59aa10ca131b037cede9d
diff --git a/polygerrit-ui/README.md b/polygerrit-ui/README.md
index 052a750..c6dd897 100644
--- a/polygerrit-ui/README.md
+++ b/polygerrit-ui/README.md
@@ -296,7 +296,7 @@
 existing helpers to create an object with all required properties:
 ```
 // Before:
-sinon.stub(element.$.restAPI, 'getPreferences').returns(
+sinon.stub(element.restApiService, 'getPreferences').returns(
     Promise.resolve({default_diff_view: 'UNIFIED'}));
 
 // After:
diff --git a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
index 7c9f28b..46968eb 100644
--- a/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-access-section/gr-access-section_html.ts
@@ -153,5 +153,4 @@
     </div>
     <!-- end deletedContainer -->
   </fieldset>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
index 44ab784..1b377dc 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list.ts
@@ -32,9 +32,9 @@
 import {AppElementAdminParams} from '../../gr-app-types';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {GroupId, GroupInfo, GroupName} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrCreateGroupDialog} from '../gr-create-group-dialog/gr-create-group-dialog';
 import {fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -46,7 +46,6 @@
   $: {
     createOverlay: GrOverlay;
     createNewModal: GrCreateGroupDialog;
-    restAPI: RestApiService & Element;
   };
 }
 
@@ -97,6 +96,8 @@
   @property({type: String})
   _filter = '';
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -131,11 +132,11 @@
   }
 
   _getCreateGroupCapability() {
-    return this.$.restAPI.getAccount().then(account => {
+    return this.restApiService.getAccount().then(account => {
       if (!account) {
         return;
       }
-      return this.$.restAPI
+      return this.restApiService
         .getAccountCapabilities(['createGroup'])
         .then(capabilities => {
           if (capabilities?.createGroup) {
@@ -147,7 +148,7 @@
 
   _getGroups(filter: string, groupsPerPage: number, offset?: number) {
     this._groups = [];
-    return this.$.restAPI
+    return this.restApiService
       .getGroups(filter, groupsPerPage, offset)
       .then(groups => {
         if (!groups) {
@@ -163,7 +164,7 @@
   }
 
   _refreshGroupsList() {
-    this.$.restAPI.invalidateGroupsCache();
+    this.restApiService.invalidateGroupsCache();
     return this._getGroups(this._filter, this._groupsPerPage, this._offset);
   }
 
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
index 93de8b4..7574f79 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_html.ts
@@ -78,5 +78,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.js b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.js
index 93d41c3..77a2a41 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-group-list/gr-admin-group-list_test.js
@@ -131,7 +131,7 @@
   suite('filter', () => {
     test('_paramsChanged', done => {
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getGroups')
           .callsFake(() => Promise.resolve(groups));
       const value = {
@@ -139,7 +139,7 @@
         offset: 25,
       };
       element._paramsChanged(value).then(() => {
-        assert.isTrue(element.$.restAPI.getGroups.lastCall
+        assert.isTrue(element.restApiService.getGroups.lastCall
             .calledWithExactly('test', 25, 25));
         done();
       });
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
index 7fb713f..8fe23e8 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view.ts
@@ -52,7 +52,6 @@
   SubsectionInterface,
 } from '../../../utils/admin-nav-util';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AppElementAdminParams,
   AppElementGroupParams,
@@ -67,12 +66,12 @@
 import {GroupNameChangedDetail} from '../gr-group/gr-group';
 import {ValueChangeDetail} from '../../shared/gr-dropdown-list/gr-dropdown-list';
 import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element';
+import {appContext} from '../../../services/app-context';
 
 const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
 
 export interface GrAdminView {
   $: {
-    restAPI: RestApiService & Element;
     jsAPI: GrJsApiInterface;
   };
 }
@@ -183,6 +182,8 @@
   @property({type: Boolean})
   _showPluginList?: boolean;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -191,7 +192,7 @@
 
   reload() {
     const promises: [Promise<AccountDetailInfo | undefined>, Promise<void>] = [
-      this.$.restAPI.getAccount(),
+      this.restApiService.getAccount(),
       getPluginLoader().awaitPluginsLoaded(),
     ];
     return Promise.all(promises).then(result => {
@@ -212,7 +213,7 @@
       return getAdminLinks(
         this._account,
         () =>
-          this.$.restAPI.getAccountCapabilities().then(capabilities => {
+          this.restApiService.getAccountCapabilities().then(capabilities => {
             if (!capabilities) {
               throw new Error('getAccountCapabilities returns undefined');
             }
@@ -423,7 +424,7 @@
     if (!groupId) return;
 
     const promises: Array<Promise<void>> = [];
-    this.$.restAPI.getGroupConfig(groupId).then(group => {
+    this.restApiService.getGroupConfig(groupId).then(group => {
       if (!group || !group.name) {
         return;
       }
@@ -433,13 +434,13 @@
       this.reload();
 
       promises.push(
-        this.$.restAPI.getIsAdmin().then(isAdmin => {
+        this.restApiService.getIsAdmin().then(isAdmin => {
           this._isAdmin = !!isAdmin;
         })
       );
 
       promises.push(
-        this.$.restAPI.getIsGroupOwner(group.name).then(isOwner => {
+        this.restApiService.getIsGroupOwner(group.name).then(isOwner => {
           this._groupOwner = isOwner;
         })
       );
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
index 5e85a93..4dacd38 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_html.ts
@@ -178,6 +178,5 @@
       <gr-repo-dashboards repo="[[params.repo]]"></gr-repo-dashboards>
     </main>
   </template>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
index 44fd4d6..15211cf 100644
--- a/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-admin-view/gr-admin-view_test.js
@@ -83,11 +83,11 @@
   });
 
   test('_filteredLinks admin', done => {
-    sinon.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
+    sinon.stub(element.restApiService, 'getAccount').returns(Promise.resolve({
       name: 'test-user',
     }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -111,11 +111,11 @@
   });
 
   test('_filteredLinks non admin authenticated', done => {
-    sinon.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
+    sinon.stub(element.restApiService, 'getAccount').returns(Promise.resolve({
       name: 'test-user',
     }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({})
         );
@@ -171,11 +171,11 @@
 
   test('Repo shows up in nav', done => {
     element._repoName = 'Test Repo';
-    sinon.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
+    sinon.stub(element.restApiService, 'getAccount').returns(Promise.resolve({
       name: 'test-user',
     }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -202,11 +202,11 @@
     element._groupIsInternal = true;
     element._isAdmin = true;
     element._groupOwner = false;
-    sinon.stub(element.$.restAPI, 'getAccount').returns(Promise.resolve({
+    sinon.stub(element.restApiService, 'getAccount').returns(Promise.resolve({
       name: 'test-user',
     }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -232,7 +232,7 @@
 
   test('Nav is reloaded when repo changes', () => {
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -240,7 +240,7 @@
           viewPlugins: true,
         }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccount')
         .callsFake(() => Promise.resolve({_id: 1}));
     sinon.stub(element, 'reload');
@@ -254,7 +254,7 @@
   test('Nav is reloaded when group changes', () => {
     sinon.stub(element, '_computeGroupName');
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -262,7 +262,7 @@
           viewPlugins: true,
         }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccount')
         .callsFake(() => Promise.resolve({_id: 1}));
     sinon.stub(element, 'reload');
@@ -321,7 +321,7 @@
       detail: GerritNav.RepoDetailView.ACCESS,
     };
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccountCapabilities')
         .callsFake(() => Promise.resolve({
           createGroup: true,
@@ -329,7 +329,7 @@
           viewPlugins: true,
         }));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getAccount')
         .callsFake(() => Promise.resolve({_id: 1}));
     flush();
@@ -484,7 +484,7 @@
   suite('_computeSelectedClass', () => {
     setup(() => {
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getAccountCapabilities')
           .callsFake(() => Promise.resolve({
             createGroup: true,
@@ -492,7 +492,7 @@
             viewPlugins: true,
           }));
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getAccount')
           .callsFake(() => Promise.resolve({_id: 1}));
 
@@ -576,12 +576,12 @@
           _loadGroupDetails: () => {},
         });
 
-        sinon.stub(element.$.restAPI, 'getGroupConfig')
+        sinon.stub(element.restApiService, 'getGroupConfig')
             .returns(Promise.resolve({
               name: 'foo',
               id: 'c0f83e941ce90caea30e6ad88f0d4ea0e841a7a9',
             }));
-        sinon.stub(element.$.restAPI, 'getIsGroupOwner')
+        sinon.stub(element.restApiService, 'getIsGroupOwner')
             .returns(Promise.resolve(true));
         return element.reload();
       });
@@ -619,8 +619,8 @@
       });
 
       test('external group', () => {
-        element.$.restAPI.getGroupConfig.restore();
-        sinon.stub(element.$.restAPI, 'getGroupConfig')
+        element.restApiService.getGroupConfig.restore();
+        sinon.stub(element.restApiService, 'getGroupConfig')
             .returns(Promise.resolve({
               name: 'foo',
               id: 'external-id',
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
index 2a6c7a8..8a64cb8 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog.ts
@@ -36,16 +36,15 @@
 } from '../../../types/common';
 import {InheritedBooleanInfoConfiguredValue} from '../../../constants/constants';
 import {hasOwnProperty} from '../../../utils/common-util';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrAutocomplete} from '../../shared/gr-autocomplete/gr-autocomplete';
 import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
+import {appContext} from '../../../services/app-context';
 
 const SUGGESTIONS_LIMIT = 15;
 const REF_PREFIX = 'refs/heads/';
 
 export interface GrCreateChangeDialog {
   $: {
-    restAPI: RestApiService & Element;
     privateChangeCheckBox: HTMLInputElement;
     branchInput: GrAutocomplete;
     tagNameInput: HTMLInputElement;
@@ -93,6 +92,8 @@
   @property({type: Boolean})
   _privateChangesEnabled?: boolean;
 
+  restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = (input: string) => this._getRepoBranchesSuggestions(input);
@@ -108,14 +109,14 @@
     const promises = [];
 
     promises.push(
-      this.$.restAPI.getProjectConfig(this.repoName).then(config => {
+      this.restApiService.getProjectConfig(this.repoName).then(config => {
         if (!config) return;
         this.privateByDefault = config.private_by_default;
       })
     );
 
     promises.push(
-      this.$.restAPI.getConfig().then(config => {
+      this.restApiService.getConfig().then(config => {
         if (!config) {
           return;
         }
@@ -143,7 +144,7 @@
     }
     const isPrivate = this.$.privateChangeCheckBox.checked;
     const isWip = true;
-    return this.$.restAPI
+    return this.restApiService
       .createChange(
         this.repoName,
         this.branch,
@@ -169,7 +170,7 @@
     if (input.startsWith(REF_PREFIX)) {
       input = input.substring(REF_PREFIX.length);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getRepoBranches(input, this.repoName, SUGGESTIONS_LIMIT)
       .then(response => {
         if (!response) return [];
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_html.ts
index 77e2c3b..47f3818 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_html.ts
@@ -113,5 +113,4 @@
       </span>
     </section>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
index e529730..0a4e23d 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-change-dialog/gr-create-change-dialog_test.ts
@@ -68,7 +68,7 @@
     };
 
     const saveStub = sinon
-      .stub(element.$.restAPI, 'createChange')
+      .stub(element.restApiService, 'createChange')
       .callsFake(() => Promise.resolve(createChange()));
 
     element.branch = 'test-branch' as BranchName;
@@ -104,7 +104,7 @@
     };
 
     const saveStub = sinon
-      .stub(element.$.restAPI, 'createChange')
+      .stub(element.restApiService, 'createChange')
       .callsFake(() => Promise.resolve(createChange()));
 
     element.branch = 'test-branch' as BranchName;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
index 1d8b7db..338494b 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog.ts
@@ -25,14 +25,8 @@
 import {encodeURL, getBaseUrl} from '../../../utils/url-util';
 import {page} from '../../../utils/page-wrapper-utils';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GroupName} from '../../../types/common';
-
-export interface GrCreateGroupDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 @customElement('gr-create-group-dialog')
 export class GrCreateGroupDialog extends GestureEventListeners(
@@ -51,6 +45,8 @@
   @property({type: Boolean})
   _groupCreated = false;
 
+  private restApiService = appContext.restApiService;
+
   _computeGroupUrl(groupId: string) {
     return getBaseUrl() + '/admin/groups/' + encodeURL(groupId, true);
   }
@@ -62,12 +58,12 @@
 
   handleCreateGroup() {
     const name = this._name as GroupName;
-    return this.$.restAPI.createGroup({name}).then(groupRegistered => {
+    return this.restApiService.createGroup({name}).then(groupRegistered => {
       if (groupRegistered.status !== 201) {
         return;
       }
       this._groupCreated = true;
-      return this.$.restAPI.getGroupConfig(name).then(group => {
+      return this.restApiService.getGroupConfig(name).then(group => {
         // TODO(TS): should group always defined ?
         page.show(this._computeGroupUrl(group!.group_id!));
       });
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_html.ts
index d4ecc5d..daf8780 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_html.ts
@@ -38,5 +38,4 @@
       </section>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
index d32ff30..bf0c244 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-group-dialog/gr-create-group-dialog_test.js
@@ -47,10 +47,10 @@
   });
 
   test('test for redirecting to group on successful creation', done => {
-    sinon.stub(element.$.restAPI, 'createGroup')
+    sinon.stub(element.restApiService, 'createGroup')
         .returns(Promise.resolve({status: 201}));
 
-    sinon.stub(element.$.restAPI, 'getGroupConfig')
+    sinon.stub(element.restApiService, 'getGroupConfig')
         .returns(Promise.resolve({group_id: 551}));
 
     const showStub = sinon.stub(page, 'show');
@@ -62,10 +62,10 @@
   });
 
   test('test for unsuccessful group creation', done => {
-    sinon.stub(element.$.restAPI, 'createGroup')
+    sinon.stub(element.restApiService, 'createGroup')
         .returns(Promise.resolve({status: 409}));
 
-    sinon.stub(element.$.restAPI, 'getGroupConfig')
+    sinon.stub(element.restApiService, 'getGroupConfig')
         .returns(Promise.resolve({group_id: 551}));
 
     const showStub = sinon.stub(page, 'show');
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
index e0a5042..10f5296 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog.ts
@@ -28,19 +28,13 @@
 import {page} from '../../../utils/page-wrapper-utils';
 import {customElement, property, observe} from '@polymer/decorators';
 import {BranchName, RepoName} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 enum DetailType {
   branches = 'branches',
   tags = 'tags',
 }
 
-export interface GrCreatePointerDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-create-pointer-dialog')
 export class GrCreatePointerDialog extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -75,6 +69,8 @@
     this.hasNewItemName = !!name;
   }
 
+  private restApiService = appContext.restApiService;
+
   handleCreateItem() {
     if (!this.repoName) {
       throw new Error('repoName name is not set');
@@ -85,7 +81,7 @@
     const USE_HEAD = this._itemRevision ? this._itemRevision : 'HEAD';
     const url = `${getBaseUrl()}/admin/repos/${encodeURL(this.repoName, true)}`;
     if (this.itemDetail === DetailType.branches) {
-      return this.$.restAPI
+      return this.restApiService
         .createRepoBranch(this.repoName, this._itemName, {revision: USE_HEAD})
         .then(itemRegistered => {
           if (itemRegistered.status === 201) {
@@ -93,7 +89,7 @@
           }
         });
     } else if (this.itemDetail === DetailType.tags) {
-      return this.$.restAPI
+      return this.restApiService
         .createRepoTag(this.repoName, this._itemName, {
           revision: USE_HEAD,
           message: this._itemAnnotation || undefined,
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_html.ts
index 0b3d81ae..452aab7 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_html.ts
@@ -80,5 +80,4 @@
       </section>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.js b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.js
index 79a18d5..9c281b1 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-pointer-dialog/gr-create-pointer-dialog_test.js
@@ -36,7 +36,7 @@
 
   test('branch created', done => {
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'createRepoBranch')
         .callsFake(() => Promise.resolve({}));
 
@@ -58,7 +58,7 @@
 
   test('tag created', done => {
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'createRepoTag')
         .callsFake(() => Promise.resolve({}));
 
@@ -80,7 +80,7 @@
 
   test('tag created with annotations', done => {
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'createRepoTag')
         .callsFake(() => Promise.resolve({}));
 
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
index 6f0ac19..d8b69c2 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog.ts
@@ -28,10 +28,10 @@
 import {encodeURL, getBaseUrl} from '../../../utils/url-util';
 import {page} from '../../../utils/page-wrapper-utils';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {ProjectInput, RepoName} from '../../../types/common';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {AutocompleteQuery} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -39,12 +39,6 @@
   }
 }
 
-export interface GrCreateRepoDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-create-repo-dialog')
 export class GrCreateRepoDialog extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -78,6 +72,8 @@
   @property({type: Object})
   _queryGroups: AutocompleteQuery;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = (input: string) => this._getRepoSuggestions(input);
@@ -103,16 +99,18 @@
   }
 
   handleCreateRepo() {
-    return this.$.restAPI.createRepo(this._repoConfig).then(repoRegistered => {
-      if (repoRegistered.status === 201) {
-        this._repoCreated = true;
-        page.show(this._computeRepoUrl(this._repoConfig.name));
-      }
-    });
+    return this.restApiService
+      .createRepo(this._repoConfig)
+      .then(repoRegistered => {
+        if (repoRegistered.status === 201) {
+          this._repoCreated = true;
+          page.show(this._computeRepoUrl(this._repoConfig.name));
+        }
+      });
   }
 
   _getRepoSuggestions(input: string) {
-    return this.$.restAPI.getSuggestedProjects(input).then(response => {
+    return this.restApiService.getSuggestedProjects(input).then(response => {
       const repos = [];
       for (const key in response) {
         if (!hasOwnProperty(response, key)) {
@@ -128,7 +126,7 @@
   }
 
   _getGroupSuggestions(input: string) {
-    return this.$.restAPI.getSuggestedGroups(input).then(response => {
+    return this.restApiService.getSuggestedGroups(input).then(response => {
       const groups = [];
       for (const key in response) {
         if (!hasOwnProperty(response, key)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
index 02aabfe..070ee86 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_html.ts
@@ -99,5 +99,4 @@
       </section>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
index 1e1fb0e..0af2e23 100644
--- a/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-create-repo-dialog/gr-create-repo-dialog_test.js
@@ -44,7 +44,7 @@
       owners: ['testId'],
     };
 
-    const saveStub = sinon.stub(element.$.restAPI,
+    const saveStub = sinon.stub(element.restApiService,
         'createRepo').callsFake(() => Promise.resolve({}));
 
     assert.isFalse(element.hasNewRepoName);
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
index e5a1586..f17f25f 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
@@ -27,10 +27,7 @@
 import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {
-  ErrorCallback,
-  RestApiService,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   GroupInfo,
   AccountInfo,
@@ -38,14 +35,10 @@
   GroupAuditEventInfo,
 } from '../../../types/common';
 import {firePageError, fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
 
-export interface GrGroupAuditLog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-group-audit-log')
 export class GrGroupAuditLog extends ListViewMixin(
   GestureEventListeners(LegacyElementMixin(PolymerElement))
@@ -63,6 +56,8 @@
   @property({type: Boolean})
   _loading = true;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -84,7 +79,7 @@
       firePageError(this, response);
     };
 
-    return this.$.restAPI
+    return this.restApiService
       .getGroupAuditLog(this.groupId, errFn)
       .then(auditLog => {
         if (!auditLog) {
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
index 1212685..32db13f 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_html.ts
@@ -66,5 +66,4 @@
       </template>
     </tbody>
   </table>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
index 1bbfcae..ce4e4c3 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log_test.js
@@ -80,7 +80,7 @@
 
       const response = {status: 404};
       sinon.stub(
-          element.$.restAPI, 'getGroupAuditLog')
+          element.restApiService, 'getGroupAuditLog')
           .callsFake((group, errFn) => {
             errFn(response);
           });
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index 01571a2..d09b0f51 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -31,10 +31,7 @@
 import {htmlTemplate} from './gr-group-members_html';
 import {getBaseUrl} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {
-  RestApiService,
-  ErrorCallback,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {
   GroupId,
@@ -51,6 +48,7 @@
   firePageError,
   fireTitleChange,
 } from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const SUGGESTIONS_LIMIT = 15;
 const SAVING_ERROR_TEXT =
@@ -60,7 +58,6 @@
 
 export interface GrGroupMembers {
   $: {
-    restAPI: RestApiService & Element;
     overlay: GrOverlay;
   };
 }
@@ -119,6 +116,8 @@
 
   _itemId?: AccountId | GroupId;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._queryMembers = input => this._getAccountSuggestions(input);
@@ -144,41 +143,45 @@
       firePageError(this, response);
     };
 
-    return this.$.restAPI.getGroupConfig(this.groupId, errFn).then(config => {
-      if (!config || !config.name) {
-        return Promise.resolve();
-      }
+    return this.restApiService
+      .getGroupConfig(this.groupId, errFn)
+      .then(config => {
+        if (!config || !config.name) {
+          return Promise.resolve();
+        }
 
-      this._groupName = config.name;
+        this._groupName = config.name;
 
-      promises.push(
-        this.$.restAPI.getIsAdmin().then(isAdmin => {
-          this._isAdmin = !!isAdmin;
-        })
-      );
+        promises.push(
+          this.restApiService.getIsAdmin().then(isAdmin => {
+            this._isAdmin = !!isAdmin;
+          })
+        );
 
-      promises.push(
-        this.$.restAPI.getIsGroupOwner(this._groupName).then(isOwner => {
-          this._groupOwner = !!isOwner;
-        })
-      );
+        promises.push(
+          this.restApiService.getIsGroupOwner(this._groupName).then(isOwner => {
+            this._groupOwner = !!isOwner;
+          })
+        );
 
-      promises.push(
-        this.$.restAPI.getGroupMembers(this._groupName).then(members => {
-          this._groupMembers = members;
-        })
-      );
+        promises.push(
+          this.restApiService.getGroupMembers(this._groupName).then(members => {
+            this._groupMembers = members;
+          })
+        );
 
-      promises.push(
-        this.$.restAPI.getIncludedGroup(this._groupName).then(includedGroup => {
-          this._includedGroups = includedGroup;
-        })
-      );
+        promises.push(
+          this.restApiService
+            .getIncludedGroup(this._groupName)
+            .then(includedGroup => {
+              this._includedGroups = includedGroup;
+            })
+        );
 
-      return Promise.all(promises).then(() => {
-        this._loading = false;
+        return Promise.all(promises).then(() => {
+          this._loading = false;
+        });
       });
-    });
   }
 
   _computeLoadingClass(loading: boolean) {
@@ -210,13 +213,13 @@
     if (!this._groupName) {
       return Promise.reject(new Error('group name undefined'));
     }
-    return this.$.restAPI
+    return this.restApiService
       .saveGroupMember(this._groupName, this._groupMemberSearchId as AccountId)
       .then(config => {
         if (!config || !this._groupName) {
           return;
         }
-        this.$.restAPI.getGroupMembers(this._groupName).then(members => {
+        this.restApiService.getGroupMembers(this._groupName).then(members => {
           this._groupMembers = members;
         });
         this._groupMemberSearchName = '';
@@ -230,24 +233,26 @@
     }
     this.$.overlay.close();
     if (this._itemType === 'member') {
-      return this.$.restAPI
+      return this.restApiService
         .deleteGroupMember(this._groupName, this._itemId! as AccountId)
         .then(itemDeleted => {
           if (itemDeleted.status === 204 && this._groupName) {
-            this.$.restAPI.getGroupMembers(this._groupName).then(members => {
-              this._groupMembers = members;
-            });
+            this.restApiService
+              .getGroupMembers(this._groupName)
+              .then(members => {
+                this._groupMembers = members;
+              });
           }
         });
     } else if (this._itemType === 'includedGroup') {
-      return this.$.restAPI
+      return this.restApiService
         .deleteIncludedGroup(this._groupName, this._itemId! as GroupId)
         .then(itemDeleted => {
           if (
             (itemDeleted.status === 204 || itemDeleted.status === 205) &&
             this._groupName
           ) {
-            this.$.restAPI
+            this.restApiService
               .getIncludedGroup(this._groupName)
               .then(includedGroup => {
                 this._includedGroups = includedGroup;
@@ -283,7 +288,7 @@
         new Error('group name or includedGroupSearchId undefined')
       );
     }
-    return this.$.restAPI
+    return this.restApiService
       .saveIncludedGroup(
         this._groupName,
         this._includedGroupSearchId.replace(/\+/g, ' ') as GroupId,
@@ -302,9 +307,11 @@
         if (!config || !this._groupName) {
           return;
         }
-        this.$.restAPI.getIncludedGroup(this._groupName).then(includedGroup => {
-          this._includedGroups = includedGroup;
-        });
+        this.restApiService
+          .getIncludedGroup(this._groupName)
+          .then(includedGroup => {
+            this._includedGroups = includedGroup;
+          });
         this._includedGroupSearchName = '';
         this._includedGroupSearchId = '';
       });
@@ -330,7 +337,7 @@
     if (input.length === 0) {
       return Promise.resolve([]);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getSuggestedAccounts(input, SUGGESTIONS_LIMIT)
       .then(accounts => {
         const accountSuggestions = [];
@@ -357,7 +364,7 @@
   }
 
   _getGroupSuggestions(input: string) {
-    return this.$.restAPI.getSuggestedGroups(input).then(response => {
+    return this.restApiService.getSuggestedGroups(input).then(response => {
       const groups = [];
       for (const key in response) {
         if (!hasOwnProperty(response, key)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
index 2d3f8fc..6b6cb31 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_html.ts
@@ -180,5 +180,4 @@
       item-type="[[_itemType]]"
     ></gr-confirm-delete-item-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
index b5d2217..59820b8 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members_test.js
@@ -139,7 +139,7 @@
     stubBaseUrl('https://test/site');
     element.groupId = 1;
     groupStub = sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getGroupConfig')
         .callsFake(() => Promise.resolve(groups));
     return element._loadGroupDetails();
@@ -162,7 +162,7 @@
 
     const memberName = 'test-admin';
 
-    const saveStub = sinon.stub(element.$.restAPI, 'saveGroupMember')
+    const saveStub = sinon.stub(element.restApiService, 'saveGroupMember')
         .callsFake(() => Promise.resolve({}));
 
     const button = element.$.saveGroupMember;
@@ -188,7 +188,7 @@
     const includedGroupName = 'testName';
 
     const saveIncludedGroupStub = sinon.stub(
-        element.$.restAPI, 'saveIncludedGroup')
+        element.restApiService, 'saveIncludedGroup')
         .callsFake(() => Promise.resolve({}));
 
     const button = element.$.saveIncludedGroups;
@@ -219,7 +219,7 @@
       status: 404,
       ok: false,
     };
-    sinon.stub(element.$.restAPI._restApiHelper, 'fetch').callsFake(
+    sinon.stub(element.restApiService._restApiHelper, 'fetch').callsFake(
         () => Promise.resolve(errorResponse));
 
     element.$.groupMemberSearchInput.text = memberName;
@@ -237,7 +237,7 @@
     const alertStub = sinon.stub();
     element.addEventListener('show-alert', alertStub);
     const err = new Error();
-    sinon.stub(element.$.restAPI._restApiHelper, 'fetch').callsFake(
+    sinon.stub(element.restApiService._restApiHelper, 'fetch').callsFake(
         () => Promise.reject(err));
 
     element.$.groupMemberSearchInput.text = memberName;
@@ -367,7 +367,7 @@
 
     const response = {status: 404};
     sinon.stub(
-        element.$.restAPI, 'getGroupConfig')
+        element.restApiService, 'getGroupConfig')
         .callsFake((group, errFn) => {
           errFn(response);
         });
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 4525543..ce8ad9c 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -33,12 +33,10 @@
   AutocompleteQuery,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
 import {GroupId, GroupInfo, GroupName} from '../../../types/common';
-import {
-  ErrorCallback,
-  RestApiService,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {firePageError, fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
 
@@ -55,7 +53,6 @@
 
 export interface GrGroup {
   $: {
-    restAPI: RestApiService & Element;
     loading: HTMLDivElement;
   };
 }
@@ -127,6 +124,8 @@
   @property({type: Boolean})
   _isAdmin = false;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = (input: string) => this._getGroupSuggestions(input);
@@ -149,41 +148,43 @@
       firePageError(this, response);
     };
 
-    return this.$.restAPI.getGroupConfig(this.groupId, errFn).then(config => {
-      if (!config || !config.name) {
-        return Promise.resolve();
-      }
+    return this.restApiService
+      .getGroupConfig(this.groupId, errFn)
+      .then(config => {
+        if (!config || !config.name) {
+          return Promise.resolve();
+        }
 
-      this._groupName = config.name;
-      this._groupIsInternal = !!config.id.match(INTERNAL_GROUP_REGEX);
+        this._groupName = config.name;
+        this._groupIsInternal = !!config.id.match(INTERNAL_GROUP_REGEX);
 
-      promises.push(
-        this.$.restAPI.getIsAdmin().then(isAdmin => {
-          this._isAdmin = !!isAdmin;
-        })
-      );
+        promises.push(
+          this.restApiService.getIsAdmin().then(isAdmin => {
+            this._isAdmin = !!isAdmin;
+          })
+        );
 
-      promises.push(
-        this.$.restAPI.getIsGroupOwner(config.name).then(isOwner => {
-          this._groupOwner = !!isOwner;
-        })
-      );
+        promises.push(
+          this.restApiService.getIsGroupOwner(config.name).then(isOwner => {
+            this._groupOwner = !!isOwner;
+          })
+        );
 
-      // If visible to all is undefined, set to false. If it is defined
-      // as false, setting to false is fine. If any optional values
-      // are added with a default of true, then this would need to be an
-      // undefined check and not a truthy/falsy check.
-      if (config.options && !config.options.visible_to_all) {
-        config.options.visible_to_all = false;
-      }
-      this._groupConfig = config;
+        // If visible to all is undefined, set to false. If it is defined
+        // as false, setting to false is fine. If any optional values
+        // are added with a default of true, then this would need to be an
+        // undefined check and not a truthy/falsy check.
+        if (config.options && !config.options.visible_to_all) {
+          config.options.visible_to_all = false;
+        }
+        this._groupConfig = config;
 
-      fireTitleChange(this, config.name);
+        fireTitleChange(this, config.name);
 
-      return Promise.all(promises).then(() => {
-        this._loading = false;
+        return Promise.all(promises).then(() => {
+          this._loading = false;
+        });
       });
-    });
   }
 
   _computeLoadingClass(loading: boolean) {
@@ -200,7 +201,7 @@
       return Promise.reject(new Error('invalid groupId or config name'));
     }
     const groupName = groupConfig.name;
-    return this.$.restAPI
+    return this.restApiService
       .saveGroupName(this.groupId, groupName)
       .then(config => {
         if (config.status === 200) {
@@ -228,7 +229,7 @@
       owner = decodeURIComponent(this._groupConfigOwner);
     }
     if (!owner) return;
-    return this.$.restAPI.saveGroupOwner(this.groupId, owner).then(() => {
+    return this.restApiService.saveGroupOwner(this.groupId, owner).then(() => {
       this._owner = false;
     });
   }
@@ -236,7 +237,7 @@
   _handleSaveDescription() {
     if (!this.groupId || !this._groupConfig || !this._groupConfig.description)
       return;
-    return this.$.restAPI
+    return this.restApiService
       .saveGroupDescription(this.groupId, this._groupConfig.description)
       .then(() => {
         this._description = false;
@@ -250,9 +251,11 @@
 
     const options = {visible_to_all: visible};
 
-    return this.$.restAPI.saveGroupOptions(this.groupId, options).then(() => {
-      this._options = false;
-    });
+    return this.restApiService
+      .saveGroupOptions(this.groupId, options)
+      .then(() => {
+        this._options = false;
+      });
   }
 
   @observe('_groupConfig.name')
@@ -292,7 +295,7 @@
   }
 
   _getGroupSuggestions(input: string) {
-    return this.$.restAPI.getSuggestedGroups(input).then(response => {
+    return this.restApiService.getSuggestedGroups(input).then(response => {
       const groups: AutocompleteSuggestion[] = [];
       for (const key in response) {
         if (!hasOwnProperty(response, key)) {
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
index aed73bf..4dcc1b8 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_html.ts
@@ -165,5 +165,4 @@
       </div>
     </div>
   </main>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
index 34f6b6a..c006251 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group_test.js
@@ -41,7 +41,7 @@
     });
     element = basicFixture.instantiate();
     groupStub = sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getGroupConfig')
         .callsFake(() => Promise.resolve(group));
   });
@@ -56,7 +56,7 @@
 
   test('default values are populated with internal group', done => {
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getIsGroupOwner')
         .callsFake(() => Promise.resolve(true));
     element.groupId = 1;
@@ -72,11 +72,11 @@
     groupExternal.id = 'external-group-id';
     groupStub.restore();
     groupStub = sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getGroupConfig')
         .callsFake(() => Promise.resolve(groupExternal));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getIsGroupOwner')
         .callsFake(() => Promise.resolve(true));
     element.groupId = 1;
@@ -97,12 +97,12 @@
     element._groupName = groupName;
 
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getIsGroupOwner')
         .callsFake(() => Promise.resolve(true));
 
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'saveGroupName')
         .callsFake(() => Promise.resolve({status: 200}));
 
@@ -136,7 +136,7 @@
     element._groupOwner = true;
 
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getIsGroupOwner')
         .callsFake(() => Promise.resolve({status: 200}));
 
@@ -163,7 +163,7 @@
     groupStub.restore();
 
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getGroupConfig')
         .callsFake(() => Promise.resolve({}));
 
@@ -189,7 +189,7 @@
       name: 'test-group',
     };
     element.groupId = 'gg';
-    sinon.stub(element.$.restAPI, 'saveGroupName')
+    sinon.stub(element.restApiService, 'saveGroupName')
         .returns(Promise.resolve({status: 200}));
 
     const showStub = sinon.stub(element, 'dispatchEvent');
@@ -240,7 +240,7 @@
 
     const response = {status: 404};
     sinon.stub(
-        element.$.restAPI, 'getGroupConfig').callsFake((group, errFn) => {
+        element.restApiService, 'getGroupConfig').callsFake((group, errFn) => {
       errFn(response);
     });
 
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
index c998cd8..e81543c 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
@@ -34,7 +34,6 @@
   PermissionArray,
 } from '../../../utils/access-util';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {
   LabelNameToLabelTypeInfoMap,
@@ -56,6 +55,7 @@
   EditableProjectAccessGroups,
 } from '../gr-repo-access/gr-repo-access-interfaces';
 import {PolymerDomRepeatEvent} from '../../../types/types';
+import {appContext} from '../../../services/app-context';
 
 const MAX_AUTOCOMPLETE_RESULTS = 20;
 
@@ -65,7 +65,6 @@
 
 export interface GrPermission {
   $: {
-    restAPI: RestApiService & Element;
     groupAutocomplete: GrAutocomplete;
   };
 }
@@ -142,6 +141,8 @@
   @property({type: Boolean})
   _originalExclusiveValue?: boolean;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = () => this._getGroupSuggestions();
@@ -337,7 +338,7 @@
   }
 
   _getGroupSuggestions(): Promise<AutocompleteSuggestion[]> {
-    return this.$.restAPI
+    return this.restApiService
       .getSuggestedGroups(this._groupFilter || '', MAX_AUTOCOMPLETE_RESULTS)
       .then(response => {
         const groups: GroupSuggestion[] = [];
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
index 9795c92..6ae982b 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_html.ts
@@ -140,5 +140,4 @@
     </div>
     <!-- end deletedContainer -->
   </section>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.js b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.js
index 32430ec..c9b0131 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.js
@@ -25,7 +25,7 @@
 
   setup(() => {
     element = basicFixture.instantiate();
-    sinon.stub(element.$.restAPI, 'getSuggestedGroups').returns(
+    sinon.stub(element.restApiService, 'getSuggestedGroups').returns(
         Promise.resolve({
           'Administrators': {
             id: '4c97682e6ce61b7247f3381b6f1789356666de7f',
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
index 9337042..03f0eff 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
@@ -27,20 +27,15 @@
   ListViewParams,
 } from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {PluginInfo} from '../../../types/common';
 import {firePageError} from '../../../utils/event-util';
 import {fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 interface PluginInfoWithName extends PluginInfo {
   name: string;
 }
-export interface GrPluginList {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-plugin-list')
 export class GrPluginList extends ListViewMixin(
   GestureEventListeners(LegacyElementMixin(PolymerElement))
@@ -83,6 +78,8 @@
   @property({type: String})
   _filter = '';
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -101,7 +98,7 @@
     const errFn: ErrorCallback = response => {
       firePageError(this, response);
     };
-    return this.$.restAPI
+    return this.restApiService
       .getPlugins(filter, pluginsPerPage, offset, errFn)
       .then(plugins => {
         if (!plugins) {
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_html.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_html.ts
index d5318b5..eeca478 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_html.ts
@@ -78,5 +78,4 @@
       </tbody>
     </table>
   </gr-list-view>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
index 7303748..6aa247f 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list_test.js
@@ -131,7 +131,7 @@
   suite('filter', () => {
     test('_paramsChanged', done => {
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getPlugins')
           .callsFake(() => Promise.resolve(plugins));
       const value = {
@@ -139,11 +139,11 @@
         offset: 25,
       };
       element._paramsChanged(value).then(() => {
-        assert.equal(element.$.restAPI.getPlugins.lastCall.args[0],
+        assert.equal(element.restApiService.getPlugins.lastCall.args[0],
             'test');
-        assert.equal(element.$.restAPI.getPlugins.lastCall.args[1],
+        assert.equal(element.restApiService.getPlugins.lastCall.args[1],
             25);
-        assert.equal(element.$.restAPI.getPlugins.lastCall.args[2],
+        assert.equal(element.restApiService.getPlugins.lastCall.args[2],
             25);
         done();
       });
@@ -168,7 +168,7 @@
   suite('404', () => {
     test('fires page-error', done => {
       const response = {status: 404};
-      sinon.stub(element.$.restAPI, 'getPlugins').callsFake(
+      sinon.stub(element.restApiService, 'getPlugins').callsFake(
           (filter, pluginsPerPage, opt_offset, errFn) => {
             errFn(response);
           });
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
index 31e1f65..79ee2c8 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.ts
@@ -38,7 +38,6 @@
   UrlEncodedRepoName,
   ProjectAccessGroups,
 } from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {GrAccessSection} from '../gr-access-section/gr-access-section';
@@ -53,17 +52,12 @@
   PrimitiveValue,
 } from './gr-repo-access-interfaces';
 import {firePageError, fireAlert} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const NOTHING_TO_SAVE = 'No changes to save.';
 
 const MAX_AUTOCOMPLETE_RESULTS = 50;
 
-export interface GrRepoAccess {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 /**
  * Fired when save is a no-op
  *
@@ -127,6 +121,8 @@
 
   private _originalInheritsFrom?: ProjectInfo | null;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = () => this._getInheritFromSuggestions();
@@ -163,7 +159,7 @@
 
     // Always reset sections when a project changes.
     this._sections = [];
-    const sectionsPromises = this.$.restAPI
+    const sectionsPromises = this.restApiService
       .getRepoAccessRights(repo, errFn)
       .then(res => {
         if (!res) {
@@ -199,7 +195,7 @@
         return toSortedPermissionsArray(this._local);
       });
 
-    const capabilitiesPromises = this.$.restAPI
+    const capabilitiesPromises = this.restApiService
       .getCapabilities(errFn)
       .then(res => {
         if (!res) {
@@ -209,13 +205,15 @@
         return res;
       });
 
-    const labelsPromises = this.$.restAPI.getRepo(repo, errFn).then(res => {
-      if (!res) {
-        return Promise.resolve(undefined);
-      }
+    const labelsPromises = this.restApiService
+      .getRepo(repo, errFn)
+      .then(res => {
+        if (!res) {
+          return Promise.resolve(undefined);
+        }
 
-      return res.labels;
-    });
+        return res.labels;
+      });
 
     return Promise.all([
       sectionsPromises,
@@ -247,7 +245,7 @@
   }
 
   _getInheritFromSuggestions(): Promise<AutocompleteSuggestion[]> {
-    return this.$.restAPI
+    return this.restApiService
       .getRepos(this._inheritFromFilter, MAX_AUTOCOMPLETE_RESULTS)
       .then(response => {
         const projects: AutocompleteSuggestion[] = [];
@@ -537,7 +535,7 @@
     if (!repo) {
       return Promise.resolve();
     }
-    return this.$.restAPI
+    return this.restApiService
       .setRepoAccessRights(repo, obj)
       .then(() => {
         this._reload(repo);
@@ -562,7 +560,7 @@
     if (!this.repo) {
       return;
     }
-    return this.$.restAPI
+    return this.restApiService
       .setRepoAccessRightsForReview(this.repo, obj)
       .then(change => {
         GerritNav.navigateToChange(change);
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
index 4e76360..a16ad28 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_html.ts
@@ -143,5 +143,4 @@
       </div>
     </div>
   </main>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
index d3204e1..2af4b6f1 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access_test.js
@@ -104,7 +104,7 @@
     stub('gr-rest-api-interface', {
       getAccount() { return Promise.resolve(null); },
     });
-    repoStub = sinon.stub(element.$.restAPI, 'getRepo').returns(
+    repoStub = sinon.stub(element.restApiService, 'getRepo').returns(
         Promise.resolve(repoRes));
     element._loading = false;
     element._ownerOf = [];
@@ -118,14 +118,14 @@
   });
 
   test('_repoChanged', done => {
-    const accessStub = sinon.stub(element.$.restAPI,
+    const accessStub = sinon.stub(element.restApiService,
         'getRepoAccessRights');
 
     accessStub.withArgs('New Repo').returns(
         Promise.resolve(JSON.parse(JSON.stringify(accessRes))));
     accessStub.withArgs('Another New Repo')
         .returns(Promise.resolve(JSON.parse(JSON.stringify(accessRes2))));
-    const capabilitiesStub = sinon.stub(element.$.restAPI,
+    const capabilitiesStub = sinon.stub(element.restApiService,
         'getCapabilities');
     capabilitiesStub.returns(Promise.resolve(capabilitiesRes));
 
@@ -160,9 +160,9 @@
         name: 'Access Database',
       },
     };
-    const accessStub = sinon.stub(element.$.restAPI, 'getRepoAccessRights')
+    const accessStub = sinon.stub(element.restApiService, 'getRepoAccessRights')
         .returns(Promise.resolve(JSON.parse(JSON.stringify(accessRes2))));
-    const capabilitiesStub = sinon.stub(element.$.restAPI,
+    const capabilitiesStub = sinon.stub(element.restApiService,
         'getCapabilities').returns(Promise.resolve(capabilitiesRes));
 
     element._repoChanged().then(() => {
@@ -241,7 +241,7 @@
     const response = {status: 404};
 
     sinon.stub(
-        element.$.restAPI, 'getRepoAccessRights')
+        element.restApiService, 'getRepoAccessRights')
         .callsFake((repoName, errFn) => {
           errFn(response);
         });
@@ -378,7 +378,7 @@
 
     test('_handleSaveForReview', () => {
       const saveStub =
-          sinon.stub(element.$.restAPI, 'setRepoAccessRightsForReview');
+          sinon.stub(element.restApiService, 'setRepoAccessRightsForReview');
       sinon.stub(element, '_computeAddAndRemove').returns({
         add: {},
         remove: {},
@@ -1161,11 +1161,11 @@
           },
         },
       };
-      sinon.stub(element.$.restAPI, 'getRepoAccessRights').returns(
+      sinon.stub(element.restApiService, 'getRepoAccessRights').returns(
           Promise.resolve(JSON.parse(JSON.stringify(accessRes))));
       sinon.stub(GerritNav, 'navigateToChange');
       let resolver;
-      const saveStub = sinon.stub(element.$.restAPI,
+      const saveStub = sinon.stub(element.restApiService,
           'setRepoAccessRights')
           .returns(new Promise(r => resolver = r));
 
@@ -1208,11 +1208,11 @@
           },
         },
       };
-      sinon.stub(element.$.restAPI, 'getRepoAccessRights').returns(
+      sinon.stub(element.restApiService, 'getRepoAccessRights').returns(
           Promise.resolve(JSON.parse(JSON.stringify(accessRes))));
       sinon.stub(GerritNav, 'navigateToChange');
       let resolver;
-      const saveForReviewStub = sinon.stub(element.$.restAPI,
+      const saveForReviewStub = sinon.stub(element.restApiService,
           'setRepoAccessRightsForReview')
           .returns(new Promise(r => resolver = r));
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index 14cfedd..c57c52f 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -30,10 +30,7 @@
 import {htmlTemplate} from './gr-repo-commands_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {
-  ErrorCallback,
-  RestApiService,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   BranchName,
   ConfigInfo,
@@ -47,6 +44,7 @@
   firePageError,
   fireTitleChange,
 } from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const GC_MESSAGE = 'Garbage collection completed successfully.';
 const CONFIG_BRANCH = 'refs/meta/config' as BranchName;
@@ -58,7 +56,6 @@
 
 export interface GrRepoCommands {
   $: {
-    restAPI: RestApiService & Element;
     createChangeOverlay: GrOverlay;
     createNewChangeModal: GrCreateChangeDialog;
   };
@@ -95,6 +92,8 @@
   @property({type: Boolean})
   _runningGC = false;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -111,7 +110,7 @@
       firePageError(this, response);
     };
 
-    this.$.restAPI.getProjectConfig(this.repo, errFn).then(config => {
+    this.restApiService.getProjectConfig(this.repo, errFn).then(config => {
       if (!config) return;
       // Do not process the response, if the component is not attached to the
       // DOM anymore, which at least in tests can happen.
@@ -131,7 +130,7 @@
 
   _handleRunningGC() {
     this._runningGC = true;
-    return this.$.restAPI
+    return this.restApiService
       .runRepoGC(this.repo)
       .then(response => {
         if (response?.status === 200) {
@@ -164,7 +163,7 @@
    */
   _handleEditRepoConfig() {
     this._editingConfig = true;
-    return this.$.restAPI
+    return this.restApiService
       .createChange(
         this.repo,
         CONFIG_BRANCH,
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
index 3880e4a..d69692d 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_html.ts
@@ -88,5 +88,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
index efe4012..60d5f20 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands_test.js
@@ -31,7 +31,7 @@
     // Note that this probably does not achieve what it is supposed to, because
     // getProjectConfig() is called as soon as the element is attached, so
     // stubbing it here has not effect anymore.
-    repoStub = sinon.stub(element.$.restAPI, 'getProjectConfig')
+    repoStub = sinon.stub(element.restApiService, 'getProjectConfig')
         .returns(Promise.resolve({}));
   });
 
@@ -68,7 +68,7 @@
     let alertStub;
 
     setup(() => {
-      createChangeStub = sinon.stub(element.$.restAPI, 'createChange');
+      createChangeStub = sinon.stub(element.restApiService, 'createChange');
       urlStub = sinon.stub(GerritNav, 'getEditUrlForDiff');
       sinon.stub(GerritNav, 'navigateToRelativeUrl');
       handleSpy = sinon.spy(element, '_handleEditRepoConfig');
@@ -119,7 +119,7 @@
 
       const response = {status: 404};
       sinon.stub(
-          element.$.restAPI, 'getProjectConfig')
+          element.restApiService, 'getProjectConfig')
           .callsFake((repo, errFn) => {
             errFn(response);
           });
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
index 99f85fa..fd10a63 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
@@ -24,21 +24,16 @@
 import {htmlTemplate} from './gr-repo-dashboards_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {RepoName, DashboardId, DashboardInfo} from '../../../types/common';
 import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {firePageError} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 interface DashboardRef {
   section: string;
   dashboards: DashboardInfo[];
 }
 
-export interface GrRepoDashboards {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-repo-dashboards')
 export class GrRepoDashboards extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -56,6 +51,8 @@
   @property({type: Array})
   _dashboards?: DashboardRef[];
 
+  private restApiService = appContext.restApiService;
+
   _repoChanged(repo?: RepoName) {
     this._loading = true;
     if (!repo) {
@@ -66,7 +63,7 @@
       firePageError(this, response);
     };
 
-    return this.$.restAPI
+    return this.restApiService
       .getRepoDashboards(repo, errFn)
       .then((res?: DashboardInfo[]) => {
         if (!res) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_html.ts
index 7cdd10e..51ea417 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_html.ts
@@ -67,5 +67,4 @@
       </template>
     </tbody>
   </table>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.js b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.js
index b4d3575..f5d4365 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards_test.js
@@ -30,7 +30,7 @@
 
   suite('dashboard table', () => {
     setup(() => {
-      sinon.stub(element.$.restAPI, 'getRepoDashboards').returns(
+      sinon.stub(element.restApiService, 'getRepoDashboards').returns(
           Promise.resolve([
             {
               id: 'default:contributor',
@@ -124,7 +124,7 @@
     test('fires page-error', done => {
       const response = {status: 404};
       sinon.stub(
-          element.$.restAPI, 'getRepoDashboards')
+          element.restApiService, 'getRepoDashboards')
           .callsFake((repo, errFn) => {
             errFn(response);
           });
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index 17414c0..168596a 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -36,10 +36,7 @@
 import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {encodeURL} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {
-  ErrorCallback,
-  RestApiService,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {GrCreatePointerDialog} from '../gr-create-pointer-dialog/gr-create-pointer-dialog';
 import {
@@ -54,12 +51,12 @@
 import {PolymerDomRepeatEvent} from '../../../types/types';
 import {RepoDetailView} from '../../core/gr-navigation/gr-navigation';
 import {firePageError} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const PGP_START = '-----BEGIN PGP SIGNATURE-----';
 
 export interface GrRepoDetailList {
   $: {
-    restAPI: RestApiService & Element;
     overlay: GrOverlay;
     createOverlay: GrOverlay;
     createNewModal: GrCreatePointerDialog;
@@ -121,8 +118,10 @@
   @property({type: String})
   _revisedRef?: GitRef;
 
+  private readonly restApiService = appContext.restApiService;
+
   _determineIfOwner(repo: RepoName) {
-    return this.$.restAPI
+    return this.restApiService
       .getRepoAccess(repo)
       .then(access => (this._isOwner = !!access && !!access[repo].is_owner));
   }
@@ -187,7 +186,7 @@
     };
 
     if (detailType === RepoDetailView.BRANCHES) {
-      return this.$.restAPI
+      return this.restApiService
         .getRepoBranches(filter, repo, itemsPerPage, offset, errFn)
         .then(items => {
           if (!items) {
@@ -197,7 +196,7 @@
           this._loading = false;
         });
     } else if (detailType === RepoDetailView.TAGS) {
-      return this.$.restAPI
+      return this.restApiService
         .getRepoTags(filter, repo, itemsPerPage, offset, errFn)
         .then(items => {
           if (!items) {
@@ -245,7 +244,7 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _computeEditingClass(isEditing: boolean) {
@@ -273,7 +272,7 @@
   }
 
   _setRepoHead(repo: RepoName, ref: GitRef, e: PolymerDomRepeatEvent<GitRef>) {
-    return this.$.restAPI.setRepoHead(repo, ref).then(res => {
+    return this.restApiService.setRepoHead(repo, ref).then(res => {
       if (res.status < 400) {
         this._isEditing = false;
         e.model.set('item.revision', ref);
@@ -305,7 +304,7 @@
       return Promise.reject(new Error('undefined repo or refName'));
     }
     if (this.detailType === RepoDetailView.BRANCHES) {
-      return this.$.restAPI
+      return this.restApiService
         .deleteRepoBranches(this._repo, this._refName)
         .then(itemDeleted => {
           if (itemDeleted.status === 204) {
@@ -319,7 +318,7 @@
           }
         });
     } else if (this.detailType === RepoDetailView.TAGS) {
-      return this.$.restAPI
+      return this.restApiService
         .deleteRepoTags(this._repo, this._refName)
         .then(itemDeleted => {
           if (itemDeleted.status === 204) {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
index 196797f..4435d3a 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_html.ts
@@ -220,5 +220,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
index 7727821..f20fd1e 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list_test.js
@@ -118,7 +118,7 @@
 
       test('Edit HEAD button not admin', done => {
         sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
-        sinon.stub(element.$.restAPI, 'getRepoAccess').returns(
+        sinon.stub(element.restApiService, 'getRepoAccess').returns(
             Promise.resolve({
               test: {is_owner: false},
             }));
@@ -142,7 +142,7 @@
             .querySelector('.revisionWithEditing');
 
         sinon.stub(element, '_getLoggedIn').returns(Promise.resolve(true));
-        sinon.stub(element.$.restAPI, 'getRepoAccess').returns(
+        sinon.stub(element.restApiService, 'getRepoAccess').returns(
             Promise.resolve({
               test: {is_owner: true},
             }));
@@ -219,7 +219,7 @@
       test('_handleSaveRevision with invalid rev', done => {
         const event = {model: {set: sinon.stub()}};
         element._isEditing = true;
-        sinon.stub(element.$.restAPI, 'setRepoHead').returns(
+        sinon.stub(element.restApiService, 'setRepoHead').returns(
             Promise.resolve({
               status: 400,
             })
@@ -235,7 +235,7 @@
       test('_handleSaveRevision with valid rev', done => {
         const event = {model: {set: sinon.stub()}};
         element._isEditing = true;
-        sinon.stub(element.$.restAPI, 'setRepoHead').returns(
+        sinon.stub(element.restApiService, 'setRepoHead').returns(
             Promise.resolve({
               status: 200,
             })
@@ -280,7 +280,7 @@
     suite('filter', () => {
       test('_paramsChanged', done => {
         sinon.stub(
-            element.$.restAPI,
+            element.restApiService,
             'getRepoBranches')
             .callsFake(() => Promise.resolve(branches));
         const params = {
@@ -290,13 +290,13 @@
           offset: 25,
         };
         element._paramsChanged(params).then(() => {
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[0],
+          assert.equal(element.restApiService.getRepoBranches.lastCall.args[0],
               'test');
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[1],
+          assert.equal(element.restApiService.getRepoBranches.lastCall.args[1],
               'test');
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[2],
+          assert.equal(element.restApiService.getRepoBranches.lastCall.args[2],
               25);
-          assert.equal(element.$.restAPI.getRepoBranches.lastCall.args[3],
+          assert.equal(element.restApiService.getRepoBranches.lastCall.args[3],
               25);
           done();
         });
@@ -306,7 +306,7 @@
     suite('404', () => {
       test('fires page-error', done => {
         const response = {status: 404};
-        sinon.stub(element.$.restAPI, 'getRepoBranches').callsFake(
+        sinon.stub(element.restApiService, 'getRepoBranches').callsFake(
             (filter, repo, reposBranchesPerPage, opt_offset, errFn) => {
               errFn(response);
             });
@@ -458,7 +458,7 @@
     suite('filter', () => {
       test('_paramsChanged', done => {
         sinon.stub(
-            element.$.restAPI,
+            element.restApiService,
             'getRepoTags')
             .callsFake(() => Promise.resolve(tags));
         const params = {
@@ -468,13 +468,13 @@
           offset: 25,
         };
         element._paramsChanged(params).then(() => {
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[0],
+          assert.equal(element.restApiService.getRepoTags.lastCall.args[0],
               'test');
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[1],
+          assert.equal(element.restApiService.getRepoTags.lastCall.args[1],
               'test');
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[2],
+          assert.equal(element.restApiService.getRepoTags.lastCall.args[2],
               25);
-          assert.equal(element.$.restAPI.getRepoTags.lastCall.args[3],
+          assert.equal(element.restApiService.getRepoTags.lastCall.args[3],
               25);
           done();
         });
@@ -520,7 +520,7 @@
     suite('404', () => {
       test('fires page-error', done => {
         const response = {status: 404};
-        sinon.stub(element.$.restAPI, 'getRepoTags').callsFake(
+        sinon.stub(element.restApiService, 'getRepoTags').callsFake(
             (filter, repo, reposTagsPerPage, opt_offset, errFn) => {
               errFn(response);
             });
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
index a566eb0..4d6fcd0 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list.ts
@@ -29,12 +29,12 @@
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property, observe, computed} from '@polymer/decorators';
 import {AppElementAdminParams} from '../../gr-app-types';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {RepoName, ProjectInfoWithName} from '../../../types/common';
 import {GrCreateRepoDialog} from '../gr-create-repo-dialog/gr-create-repo-dialog';
 import {ProjectState} from '../../../constants/constants';
 import {fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -44,7 +44,6 @@
 
 export interface GrRepoList {
   $: {
-    restAPI: RestApiService & Element;
     createOverlay: GrOverlay;
     createNewModal: GrCreateRepoDialog;
   };
@@ -90,6 +89,8 @@
     return this.computeShownItems(this._repos);
   }
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -125,11 +126,11 @@
   }
 
   _getCreateRepoCapability() {
-    return this.$.restAPI.getAccount().then(account => {
+    return this.restApiService.getAccount().then(account => {
       if (!account) {
         return;
       }
-      return this.$.restAPI
+      return this.restApiService
         .getAccountCapabilities(['createProject'])
         .then(capabilities => {
           if (capabilities?.createProject) {
@@ -141,18 +142,20 @@
 
   _getRepos(filter: string, reposPerPage: number, offset?: number) {
     this._repos = [];
-    return this.$.restAPI.getRepos(filter, reposPerPage, offset).then(repos => {
-      // Late response.
-      if (filter !== this._filter || !repos) {
-        return;
-      }
-      this._repos = repos;
-      this._loading = false;
-    });
+    return this.restApiService
+      .getRepos(filter, reposPerPage, offset)
+      .then(repos => {
+        // Late response.
+        if (filter !== this._filter || !repos) {
+          return;
+        }
+        this._repos = repos;
+        this._loading = false;
+      });
   }
 
   _refreshReposList() {
-    this.$.restAPI.invalidateReposCache();
+    this.restApiService.invalidateReposCache();
     return this._getRepos(this._filter, this._reposPerPage, this._offset);
   }
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
index 4889845..20c72f9 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_html.ts
@@ -115,5 +115,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
index e2a29f2..baa33a7 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-list/gr-repo-list_test.js
@@ -109,21 +109,21 @@
     });
 
     test('_paramsChanged', done => {
-      sinon.stub(element.$.restAPI, 'getRepos')
+      sinon.stub(element.restApiService, 'getRepos')
           .callsFake( () => Promise.resolve(repos));
       const value = {
         filter: 'test',
         offset: 25,
       };
       element._paramsChanged(value).then(() => {
-        assert.isTrue(element.$.restAPI.getRepos.lastCall
+        assert.isTrue(element.restApiService.getRepos.lastCall
             .calledWithExactly('test', 25, 25));
         done();
       });
     });
 
     test('latest repos requested are always set', done => {
-      const repoStub = sinon.stub(element.$.restAPI, 'getRepos');
+      const repoStub = sinon.stub(element.restApiService, 'getRepos');
       repoStub.withArgs('test').returns(Promise.resolve(repos));
       repoStub.withArgs('filter').returns(Promise.resolve(reposFiltered));
       element._filter = 'test';
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index 16435e5..acde142 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -31,10 +31,7 @@
 import {htmlTemplate} from './gr-repo_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property, observe} from '@polymer/decorators';
-import {
-  RestApiService,
-  ErrorCallback,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   ConfigInfo,
   RepoName,
@@ -49,6 +46,7 @@
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {firePageError, fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const STATES = {
   active: {value: ProjectState.ACTIVE, label: 'Active'},
@@ -84,11 +82,6 @@
   },
 };
 
-export interface GrRepo {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-repo')
 export class GrRepo extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -145,6 +138,8 @@
   @property({type: Object})
   _schemesObj?: SchemesInfoMap;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -186,7 +181,7 @@
         if (loggedIn) {
           const repo = this.repo;
           if (!repo) throw new Error('undefined repo');
-          this.$.restAPI.getRepoAccess(repo).then(access => {
+          this.restApiService.getRepoAccess(repo).then(access => {
             if (!access || this.repo !== repo) {
               return;
             }
@@ -199,7 +194,7 @@
     );
 
     promises.push(
-      this.$.restAPI.getProjectConfig(this.repo, errFn).then(config => {
+      this.restApiService.getProjectConfig(this.repo, errFn).then(config => {
         if (!config) {
           return;
         }
@@ -221,7 +216,7 @@
     );
 
     promises.push(
-      this.$.restAPI.getConfig().then(config => {
+      this.restApiService.getConfig().then(config => {
         if (!config) {
           return;
         }
@@ -245,7 +240,7 @@
     if (!_loggedIn) {
       return;
     }
-    this.$.restAPI.getPreferences().then(prefs => {
+    this.restApiService.getPreferences().then(prefs => {
       if (prefs?.download_scheme) {
         // Note (issue 5180): normalize the download scheme with lower-case.
         this._selectedScheme = prefs.download_scheme.toLowerCase();
@@ -313,7 +308,7 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _formatRepoConfigForSave(repoConfig: ConfigInfo): ConfigInput {
@@ -346,7 +341,7 @@
   _handleSaveRepoConfig() {
     if (!this._repoConfig || !this.repo)
       return Promise.reject(new Error('undefined repoConfig or repo'));
-    return this.$.restAPI
+    return this.restApiService
       .saveRepoConfig(
         this.repo,
         this._formatRepoConfigForSave(this._repoConfig)
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
index 2e86758..5bfb7e6 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_html.ts
@@ -436,5 +436,4 @@
       </div>
     </div>
   </main>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.js b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.js
index 93a9d64..29a83941 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo_test.js
@@ -106,7 +106,7 @@
     });
     element = basicFixture.instantiate();
     repoStub = sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getProjectConfig')
         .callsFake(() => Promise.resolve(repoConf));
   });
@@ -171,7 +171,7 @@
     element.repo = REPO;
     sinon.stub(element, '_getLoggedIn').callsFake(() => Promise.resolve(true));
     sinon.stub(
-        element.$.restAPI,
+        element.restApiService,
         'getRepoAccess')
         .callsFake(() => Promise.resolve({'test-repo': {}}));
     element._loadRepo().then(() => {
@@ -247,7 +247,7 @@
 
     const response = {status: 404};
     sinon.stub(
-        element.$.restAPI, 'getProjectConfig').callsFake((repo, errFn) => {
+        element.restApiService, 'getProjectConfig').callsFake((repo, errFn) => {
       errFn(response);
     });
     element.addEventListener('page-error', e => {
@@ -264,7 +264,7 @@
       sinon.stub(element, '_getLoggedIn')
           .callsFake(() => Promise.resolve(true));
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getRepoAccess')
           .callsFake(() => Promise.resolve({'test-repo': {is_owner: true}}));
     });
@@ -322,7 +322,7 @@
         enable_reviewer_by_email: 'TRUE',
       };
 
-      const saveStub = sinon.stub(element.$.restAPI, 'saveRepoConfig')
+      const saveStub = sinon.stub(element.restApiService, 'saveRepoConfig')
           .callsFake(() => Promise.resolve({}));
 
       const button = element.root.querySelector('gr-button');
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts
index 98403e0..c4d7688 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor_html.ts
@@ -156,5 +156,4 @@
       >Undo</gr-button
     >
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
index 3391901..1484e6e 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view.ts
@@ -36,12 +36,12 @@
   EmailAddress,
   PreferencesInput,
 } from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {ChangeListToggleReviewedDetail} from '../gr-change-list-item/gr-change-list-item';
 import {ChangeStarToggleStarDetail} from '../../shared/gr-change-star/gr-change-star';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {ChangeListViewState} from '../../../types/types';
 import {fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const LookupQueryPatterns = {
   CHANGE_ID: /^\s*i?[0-9a-f]{7,40}\s*$/i,
@@ -57,7 +57,6 @@
 
 export interface GrChangeListView {
   $: {
-    restAPI: RestApiService & Element;
     prevArrow: HTMLAnchorElement;
     nextArrow: HTMLAnchorElement;
   };
@@ -113,6 +112,8 @@
   @property({type: String})
   _repo: string | null = null;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   created() {
     super.created();
@@ -146,7 +147,7 @@
     // in an async so that attachment to the DOM can take place first.
     this.async(() => fireTitleChange(this, this._query));
 
-    this.$.restAPI
+    this.restApiService
       .getPreferences()
       .then(prefs => {
         if (!prefs) {
@@ -183,9 +184,9 @@
   }
 
   _loadPreferences() {
-    return this.$.restAPI.getLoggedIn().then(loggedIn => {
+    return this.restApiService.getLoggedIn().then(loggedIn => {
       if (loggedIn) {
-        this.$.restAPI.getPreferences().then(preferences => {
+        this.restApiService.getPreferences().then(preferences => {
           this.preferences = preferences;
         });
       } else {
@@ -195,7 +196,7 @@
   }
 
   _getChanges() {
-    return this.$.restAPI.getChanges(
+    return this.restApiService.getChanges(
       this._changesPerPage,
       this._query,
       this._offset
@@ -282,11 +283,14 @@
   }
 
   _handleToggleStar(e: CustomEvent<ChangeStarToggleStarDetail>) {
-    this.$.restAPI.saveChangeStarred(e.detail.change._number, e.detail.starred);
+    this.restApiService.saveChangeStarred(
+      e.detail.change._number,
+      e.detail.starred
+    );
   }
 
   _handleToggleReviewed(e: CustomEvent<ChangeListToggleReviewedDetail>) {
-    this.$.restAPI.saveChangeReviewed(
+    this.restApiService.saveChangeReviewed(
       e.detail.change._number,
       e.detail.reviewed
     );
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
index 0e8f843..9914e70 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list-view/gr-change-list-view_html.ts
@@ -98,5 +98,4 @@
       </a>
     </nav>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
index 3acdaf9..3639657 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list.ts
@@ -43,7 +43,6 @@
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
 import {changeIsOpen, isOwner} from '../../../utils/change-util';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrCursorManager} from '../../shared/gr-cursor-manager/gr-cursor-manager';
 import {
   AccountInfo,
@@ -69,7 +68,6 @@
 }
 export interface GrChangeList {
   $: {
-    restAPI: RestApiService & Element;
     cursor: GrCursorManager;
   };
 }
@@ -147,6 +145,8 @@
 
   flagsService = appContext.flagsService;
 
+  private restApiService = appContext.restApiService;
+
   keyboardShortcuts() {
     return {
       [Shortcut.CURSOR_NEXT_CHANGE]: '_nextChange',
@@ -169,7 +169,7 @@
   /** @override */
   ready() {
     super.ready();
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this._config = config;
     });
   }
diff --git a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
index 06957d9..990525c 100644
--- a/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-change-list/gr-change-list_html.ts
@@ -163,5 +163,4 @@
     scroll-mode="keep-visible"
     focus-on-move=""
   ></gr-cursor-manager>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
index 0cf9357..5fc831a 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view.ts
@@ -47,7 +47,6 @@
   RepoName,
 } from '../../../types/common';
 import {AppElementDashboardParams, AppElementParams} from '../../gr-app-types';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
 import {GrCreateCommandsDialog} from '../gr-create-commands-dialog/gr-create-commands-dialog';
 import {
@@ -64,7 +63,6 @@
 
 export interface GrDashboardView {
   $: {
-    restAPI: RestApiService & Element;
     confirmDeleteDialog: GrDialog;
     commandsDialog: GrCreateCommandsDialog;
     destinationDialog: GrCreateDestinationDialog;
@@ -120,6 +118,8 @@
 
   private reporting = appContext.reportingService;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
   }
@@ -135,9 +135,9 @@
   }
 
   _loadPreferences() {
-    return this.$.restAPI.getLoggedIn().then(loggedIn => {
+    return this.restApiService.getLoggedIn().then(loggedIn => {
       if (loggedIn) {
-        this.$.restAPI.getPreferences().then(preferences => {
+        this.restApiService.getPreferences().then(preferences => {
           this.preferences = preferences;
         });
       } else {
@@ -153,7 +153,7 @@
     const errFn = (response?: Response | null) => {
       firePageError(this, response);
     };
-    return this.$.restAPI
+    return this.restApiService
       .getDashboard(project, dashboard, errFn)
       .then(response => {
         if (!response) {
@@ -206,7 +206,7 @@
     const {project, dashboard, title, user, sections} = params;
     const dashboardPromise: Promise<UserDashboard | undefined> = project
       ? this._getProjectDashboard(project, dashboard)
-      : this.$.restAPI
+      : this.restApiService
           .getConfig()
           .then(config =>
             Promise.resolve(
@@ -272,7 +272,7 @@
       }
     }
 
-    return this.$.restAPI.getChanges(undefined, queries).then(changes => {
+    return this.restApiService.getChanges(undefined, queries).then(changes => {
       if (!changes) {
         throw new Error('getChanges returns undefined');
       }
@@ -351,11 +351,14 @@
   }
 
   _handleToggleStar(e: CustomEvent<ChangeStarToggleStarDetail>) {
-    this.$.restAPI.saveChangeStarred(e.detail.change._number, e.detail.starred);
+    this.restApiService.saveChangeStarred(
+      e.detail.change._number,
+      e.detail.starred
+    );
   }
 
   _handleToggleReviewed(e: CustomEvent<ChangeListToggleReviewedDetail>) {
-    this.$.restAPI.saveChangeReviewed(
+    this.restApiService.saveChangeReviewed(
       e.detail.change._number,
       e.detail.reviewed
     );
@@ -402,7 +405,7 @@
 
   _handleConfirmDelete() {
     this.$.confirmDeleteDialog.disabled = true;
-    return this.$.restAPI.deleteDraftComments('-is:open').then(() => {
+    return this.restApiService.deleteDraftComments('-is:open').then(() => {
       this._closeConfirmDeleteOverlay();
       this._reload(this.params);
     });
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
index 6dae176..c23a1cc 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_html.ts
@@ -125,5 +125,4 @@
     on-confirm="_handleDestinationConfirm"
   ></gr-create-destination-dialog>
   <gr-create-commands-dialog id="commandsDialog"></gr-create-commands-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
index f788e74..1fa24ba 100644
--- a/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-dashboard-view/gr-dashboard-view_test.js
@@ -39,7 +39,7 @@
     });
     element = basicFixture.instantiate();
 
-    getChangesStub = sinon.stub(element.$.restAPI, 'getChanges').callsFake(
+    getChangesStub = sinon.stub(element.restApiService, 'getChanges').callsFake(
         (_, qs) => Promise.resolve(qs.map(() => [])));
 
     let resolver;
@@ -124,14 +124,14 @@
       const deleteDraftCommentsPromise = new Promise(resolve => {
         deleteDraftCommentsPromiseResolver = resolve;
       });
-      sinon.stub(element.$.restAPI, 'deleteDraftComments')
+      sinon.stub(element.restApiService, 'deleteDraftComments')
           .returns(deleteDraftCommentsPromise);
 
       // Open confirmation dialog and tap confirm button.
       await element.$.confirmDeleteOverlay.open();
       MockInteractions.tap(element.$.confirmDeleteDialog.$.confirm);
       flush();
-      assert.isTrue(element.$.restAPI.deleteDraftComments
+      assert.isTrue(element.restApiService.deleteDraftComments
           .calledWithExactly('-is:open'));
       assert.isTrue(element.$.confirmDeleteDialog.disabled);
       assert.equal(element._reload.callCount, 0);
@@ -254,7 +254,7 @@
 
   suite('_getProjectDashboard', () => {
     test('dashboard with foreach', () => {
-      sinon.stub(element.$.restAPI, 'getDashboard')
+      sinon.stub(element.restApiService, 'getDashboard')
           .callsFake( () => Promise.resolve({
             title: 'title',
             foreach: 'foreach for ${project}',
@@ -280,7 +280,7 @@
     });
 
     test('dashboard without foreach', () => {
-      sinon.stub(element.$.restAPI, 'getDashboard').callsFake(
+      sinon.stub(element.restApiService, 'getDashboard').callsFake(
           () => Promise.resolve({
             title: 'title',
             sections: [
@@ -308,7 +308,7 @@
       {name: 'test2', query: 'test2', hideIfEmpty: true},
     ];
     getChangesStub.restore();
-    sinon.stub(element.$.restAPI, 'getChanges')
+    sinon.stub(element.restApiService, 'getChanges')
         .returns(Promise.resolve([[], ['nonempty']]));
 
     return element._fetchDashboardChanges({sections}, false).then(() => {
@@ -323,7 +323,7 @@
       {name: 'test2', query: 'test2'},
     ];
     getChangesStub.restore();
-    sinon.stub(element.$.restAPI, 'getChanges')
+    sinon.stub(element.restApiService, 'getChanges')
         .returns(Promise.resolve([[], []]));
 
     return element._fetchDashboardChanges({sections}, false).then(() => {
@@ -374,7 +374,7 @@
 
   test('404 page', done => {
     const response = {status: 404};
-    sinon.stub(element.$.restAPI, 'getDashboard').callsFake(
+    sinon.stub(element.restApiService, 'getDashboard').callsFake(
         async (project, dashboard, errFn) => {
           errFn(response);
         });
diff --git a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
index d1221d15..2dd2913 100644
--- a/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-repo-header/gr-repo-header_html.ts
@@ -30,5 +30,4 @@
     <hr />
     <div><span>Detail:</span> <a href$="[[_repoUrl]]">Repo settings</a></div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
index 055c82c..b4a1466 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header.ts
@@ -28,15 +28,9 @@
 import {htmlTemplate} from './gr-user-header_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {AccountDetailInfo, AccountId} from '../../../types/common';
 import {getDisplayName} from '../../../utils/display-name-util';
-
-export interface GrUserHeader {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 @customElement('gr-user-header')
 export class GrUserHeader extends GestureEventListeners(
@@ -61,6 +55,8 @@
   @property({type: String})
   _status = '';
 
+  private restApiService = appContext.restApiService;
+
   _accountChanged(userId?: AccountId) {
     if (!userId) {
       this._accountDetails = null;
@@ -68,7 +64,7 @@
       return;
     }
 
-    this.$.restAPI.getAccountDetails(userId).then(details => {
+    this.restApiService.getAccountDetails(userId).then(details => {
       this._accountDetails = details ?? null;
       this._status = details?.status ?? '';
     });
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
index 002a4ba..a8a6a56 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_html.ts
@@ -66,5 +66,4 @@
       <a href$="[[_computeDashboardUrl(_accountDetails)]]">View dashboard</a>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.js b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.js
index a808f3c..78560907 100644
--- a/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.js
+++ b/polygerrit-ui/app/elements/change-list/gr-user-header/gr-user-header_test.js
@@ -28,7 +28,7 @@
   });
 
   test('loads and clears account info', done => {
-    sinon.stub(element.$.restAPI, 'getAccountDetails')
+    sinon.stub(element.restApiService, 'getAccountDetails')
         .returns(Promise.resolve({
           name: 'foo',
           email: 'bar',
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 9473700..020762c 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -65,7 +65,6 @@
   ActionPriority,
   ActionType,
   ErrorCallback,
-  RestApiService,
 } from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   ActionInfo,
@@ -323,7 +322,6 @@
 export interface GrChangeActions {
   $: {
     jsAPI: GrJsApiInterface;
-    restAPI: RestApiService & Element;
     mainContent: Element;
     overlay: GrOverlay;
     confirmRebase: GrConfirmRebaseDialog;
@@ -549,6 +547,8 @@
   @property({type: Object})
   _config?: ServerInfo;
 
+  private restApiService = appContext.restApiService;
+
   /** @override */
   created() {
     super.created();
@@ -564,7 +564,7 @@
   ready() {
     super.ready();
     this.$.jsAPI.addElement(TargetElement.CHANGE_ACTIONS, this);
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this._config = config;
     });
     this._handleLoadingComplete();
@@ -600,7 +600,7 @@
     const change = this.change;
 
     this._loading = true;
-    return this.$.restAPI
+    return this.restApiService
       .getChangeRevisionActions(this.changeNum, this.latestPatchNum)
       .then(revisionActions => {
         if (!revisionActions) {
@@ -1086,7 +1086,7 @@
     if (!this.changeNum) {
       return;
     }
-    this.$.restAPI
+    this.restApiService
       .getChangeActionURL(this.changeNum, patchNum, '/' + action.__key)
       .then(url => (action.__url = url));
   }
@@ -1148,7 +1148,7 @@
     /* A chromium plugin expects that the modifyRevertMsg hook will only
     be called after the revert button is pressed, hence we populate the
     revert dialog after revert button is pressed. */
-    this.$.restAPI.getChanges(0, query).then(changes => {
+    this.restApiService.getChanges(0, query).then(changes => {
       if (!changes) {
         console.error('changes is undefined');
         return;
@@ -1162,7 +1162,7 @@
     const change = this.change;
     if (!change) return;
     const query = `submissionid:${change.submission_id}`;
-    this.$.restAPI.getChanges(0, query).then(changes => {
+    this.restApiService.getChanges(0, query).then(changes => {
       if (!changes) {
         console.error('changes is undefined');
         return;
@@ -1594,14 +1594,14 @@
     if (!labels) {
       return Promise.resolve(undefined);
     }
-    return this.$.restAPI.saveChangeReview(newChangeId, CURRENT, {labels});
+    return this.restApiService.saveChangeReview(newChangeId, CURRENT, {labels});
   }
 
   _handleResponse(action: UIActionInfo, response?: Response) {
     if (!response) {
       return;
     }
-    return this.$.restAPI.getResponseObject(response).then(obj => {
+    return this.restApiService.getResponseObject(response).then(obj => {
       switch (action.__key) {
         case ChangeActions.REVERT: {
           const revertChangeInfo: ChangeInfo = (obj as unknown) as ChangeInfo;
@@ -1729,7 +1729,7 @@
         new Error('Properties change and changeNum must be set.')
       );
     }
-    return fetchChangeUpdates(change, this.$.restAPI).then(result => {
+    return fetchChangeUpdates(change, this.restApiService).then(result => {
       if (!result.isLatest) {
         this.dispatchEvent(
           new CustomEvent('show-alert', {
@@ -1760,7 +1760,7 @@
         return Promise.resolve(undefined);
       }
       const patchNum = revisionAction ? this.latestPatchNum : undefined;
-      return this.$.restAPI
+      return this.restApiService
         .executeChangeAction(
           changeNum,
           method,
@@ -1790,14 +1790,16 @@
       ListChangesOption.MESSAGES,
       ListChangesOption.ALL_REVISIONS
     );
-    this.$.restAPI.getChanges(0, query, undefined, options).then(changes => {
-      if (!changes) {
-        console.error('getChanges returns undefined');
-        return;
-      }
-      this.$.confirmCherrypick.updateChanges(changes);
-      this._showActionDialog(this.$.confirmCherrypick);
-    });
+    this.restApiService
+      .getChanges(0, query, undefined, options)
+      .then(changes => {
+        if (!changes) {
+          console.error('getChanges returns undefined');
+          return;
+        }
+        this.$.confirmCherrypick.updateChanges(changes);
+        this._showActionDialog(this.$.confirmCherrypick);
+      });
   }
 
   _handleMoveTap() {
@@ -2052,7 +2054,7 @@
       const check = () => {
         attempsRemaining--;
         // Pass a no-op error handler to avoid the "not found" error toast.
-        this.$.restAPI
+        this.restApiService
           .getChange(changeNum, () => {})
           .then(response => {
             // If the response is 404, the response will be undefined.
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
index 4e315af..0a3e536 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_html.ts
@@ -270,5 +270,4 @@
     </gr-dialog>
   </gr-overlay>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
index 1098760..3b6a2bf 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions_test.js
@@ -25,6 +25,7 @@
   createChangeMessages,
   createRevisions,
 } from '../../../test/test-data-generators.js';
+import {appContext} from '../../../services/app-context.js';
 
 const basicFixture = fixtureFromElement('gr-change-actions');
 
@@ -104,10 +105,8 @@
           enabled: true,
         },
       };
-      sinon.stub(element.$.confirmCherrypick.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-      sinon.stub(element.$.confirmMove.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
+      sinon.stub(appContext.restApiService, 'getRepoBranches').returns(
+          Promise.resolve([]));
 
       return element.reload();
     });
@@ -143,14 +142,14 @@
     });
 
     test('plugin revision actions', done => {
-      sinon.stub(element.$.restAPI, 'getChangeActionURL').returns(
+      sinon.stub(element.restApiService, 'getChangeActionURL').returns(
           Promise.resolve('the-url'));
       element.revisionActions = {
         'plugin~action': {},
       };
       assert.isOk(element.revisionActions['plugin~action']);
       flush(() => {
-        assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
+        assert.isTrue(element.restApiService.getChangeActionURL.calledWith(
             element.changeNum, element.latestPatchNum, '/plugin~action'));
         assert.equal(element.revisionActions['plugin~action'].__url, 'the-url');
         done();
@@ -158,14 +157,14 @@
     });
 
     test('plugin change actions', async () => {
-      sinon.stub(element.$.restAPI, 'getChangeActionURL').returns(
+      sinon.stub(element.restApiService, 'getChangeActionURL').returns(
           Promise.resolve('the-url'));
       element.actions = {
         'plugin~action': {},
       };
       assert.isOk(element.actions['plugin~action']);
       await flush();
-      assert.isTrue(element.$.restAPI.getChangeActionURL.calledWith(
+      assert.isTrue(element.restApiService.getChangeActionURL.calledWith(
           element.changeNum, undefined, '/plugin~action'));
       assert.equal(element.actions['plugin~action'].__url, 'the-url');
     });
@@ -273,7 +272,7 @@
 
     test('submit change', () => {
       const showSpy = sinon.spy(element, '_showActionDialog');
-      sinon.stub(element.$.restAPI, 'getFromProjectLookup')
+      sinon.stub(element.restApiService, 'getFromProjectLookup')
           .returns(Promise.resolve('test'));
       sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
       element.change = {
@@ -295,7 +294,7 @@
 
     test('submit change, tap on icon', done => {
       sinon.stub(element.$.confirmSubmitDialog, 'resetFocus').callsFake( done);
-      sinon.stub(element.$.restAPI, 'getFromProjectLookup')
+      sinon.stub(element.restApiService, 'getFromProjectLookup')
           .returns(Promise.resolve('test'));
       sinon.stub(element.$.overlay, 'open').returns(Promise.resolve());
       element.change = {
@@ -399,7 +398,7 @@
 
     test('rebase change fires reload event', done => {
       const eventStub = sinon.stub(element, 'dispatchEvent');
-      sinon.stub(element.$.restAPI, 'getResponseObject').returns(
+      sinon.stub(element.restApiService, 'getResponseObject').returns(
           Promise.resolve({}));
       element._handleResponse({__key: 'rebase'}, {});
       flush(() => {
@@ -429,24 +428,21 @@
       });
     });
 
-    test('two dialogs are not shown at the same time', done => {
+    test('two dialogs are not shown at the same time', async () => {
       element._hasKnownChainState = true;
-      flush(() => {
-        const rebaseButton = element.shadowRoot
-            .querySelector('gr-button[data-action-key="rebase"]');
-        assert.ok(rebaseButton);
-        MockInteractions.tap(rebaseButton);
-        flush();
-        assert.isFalse(element.$.confirmRebase.hidden);
-        sinon.stub(element.$.restAPI, 'getChanges')
-            .returns(Promise.resolve([]));
-        element._handleCherrypickTap();
-        flush(() => {
-          assert.isTrue(element.$.confirmRebase.hidden);
-          assert.isFalse(element.$.confirmCherrypick.hidden);
-          done();
-        });
-      });
+      await flush();
+      const rebaseButton = element.shadowRoot
+          .querySelector('gr-button[data-action-key="rebase"]');
+      assert.ok(rebaseButton);
+      MockInteractions.tap(rebaseButton);
+      await flush();
+      assert.isFalse(element.$.confirmRebase.hidden);
+      sinon.stub(element.restApiService, 'getChanges')
+          .returns(Promise.resolve([]));
+      element._handleCherrypickTap();
+      await flush();
+      assert.isTrue(element.$.confirmRebase.hidden);
+      assert.isFalse(element.$.confirmCherrypick.hidden);
     });
 
     test('fullscreen-overlay-opened hides content', () => {
@@ -473,7 +469,7 @@
       const labels = {'Foo': 1, 'Bar-Baz': -2};
       const changeId = 1234;
       sinon.stub(element.$.jsAPI, 'getLabelValuesPostRevert').returns(labels);
-      const saveStub = sinon.stub(element.$.restAPI, 'saveChangeReview')
+      const saveStub = sinon.stub(element.restApiService, 'saveChangeReview')
           .returns(Promise.resolve());
       return element._setLabelValuesOnRevert(changeId).then(() => {
         assert.isTrue(saveStub.calledOnce);
@@ -748,7 +744,7 @@
           },
         ];
         setup(done => {
-          sinon.stub(element.$.restAPI, 'getChanges')
+          sinon.stub(element.restApiService, 'getChanges')
               .returns(Promise.resolve(changes));
           element._handleCherrypickTap();
           flush(() => {
@@ -994,7 +990,7 @@
         element.change = {
           current_revision: 'abc1234',
         };
-        sinon.stub(element.$.restAPI, 'getChanges')
+        sinon.stub(element.restApiService, 'getChanges')
             .returns(Promise.resolve([
               {change_id: '12345678901234', topic: 'T', subject: 'random'},
               {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
@@ -1019,7 +1015,7 @@
             submission_id: '199 0',
             current_revision: '2000',
           };
-          getChangesStub = sinon.stub(element.$.restAPI, 'getChanges')
+          getChangesStub = sinon.stub(element.restApiService, 'getChanges')
               .returns(Promise.resolve([
                 {change_id: '12345678901234', topic: 'T', subject: 'random'},
                 {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
@@ -1129,7 +1125,7 @@
             submission_id: '199',
             current_revision: '2000',
           };
-          sinon.stub(element.$.restAPI, 'getChanges')
+          sinon.stub(element.restApiService, 'getChanges')
               .returns(Promise.resolve([
                 {change_id: '12345678901234', topic: 'T', subject: 'random'},
               ]));
@@ -1810,7 +1806,7 @@
         };
 
         test('succeed', () => {
-          sinon.stub(element.$.restAPI, 'getChange')
+          sinon.stub(element.restApiService, 'getChange')
               .callsFake( makeGetChange(5));
           return element._waitForChangeReachable(123).then(success => {
             assert.isTrue(success);
@@ -1818,7 +1814,7 @@
         });
 
         test('fail', () => {
-          sinon.stub(element.$.restAPI, 'getChange')
+          sinon.stub(element.restApiService, 'getChange')
               .callsFake( makeGetChange(6));
           return element._waitForChangeReachable(123).then(success => {
             assert.isFalse(success);
@@ -1855,16 +1851,16 @@
       suite('happy path', () => {
         let sendStub;
         setup(() => {
-          sinon.stub(element.$.restAPI, 'getChangeDetail')
+          sinon.stub(element.restApiService, 'getChangeDetail')
               .returns(Promise.resolve({
                 ...createChange(),
                 // element has latest info
                 revisions: createRevisions(element.latestPatchNum),
                 messages: createChangeMessages(1),
               }));
-          sendStub = sinon.stub(element.$.restAPI, 'executeChangeAction')
+          sendStub = sinon.stub(element.restApiService, 'executeChangeAction')
               .returns(Promise.resolve({}));
-          getResponseObjectStub = sinon.stub(element.$.restAPI,
+          getResponseObjectStub = sinon.stub(element.restApiService,
               'getResponseObject');
           sinon.stub(GerritNav,
               'navigateToChange').returns(Promise.resolve(true));
@@ -1882,7 +1878,7 @@
           setup(() => {
             element.change.submission_id = '199';
             element.change.current_revision = '2000';
-            sinon.stub(element.$.restAPI, 'getChanges')
+            sinon.stub(element.restApiService, 'getChanges')
                 .returns(Promise.resolve([
                   {change_id: '12345678901234', topic: 'T', subject: 'random'},
                   {change_id: '23456', topic: 'T', subject: 'a'.repeat(100)},
@@ -1974,14 +1970,14 @@
 
       suite('failure modes', () => {
         test('non-latest', () => {
-          sinon.stub(element.$.restAPI, 'getChangeDetail')
+          sinon.stub(element.restApiService, 'getChangeDetail')
               .returns(Promise.resolve({
                 ...createChange(),
                 // new patchset was uploaded
                 revisions: createRevisions(element.latestPatchNum + 1),
                 messages: createChangeMessages(1),
               }));
-          const sendStub = sinon.stub(element.$.restAPI,
+          const sendStub = sinon.stub(element.restApiService,
               'executeChangeAction');
 
           return element._send('DELETE', payload, '/endpoint', true, cleanup)
@@ -1994,14 +1990,14 @@
         });
 
         test('send fails', () => {
-          sinon.stub(element.$.restAPI, 'getChangeDetail')
+          sinon.stub(element.restApiService, 'getChangeDetail')
               .returns(Promise.resolve({
                 ...createChange(),
                 // element has latest info
                 revisions: createRevisions(element.latestPatchNum),
                 messages: createChangeMessages(1),
               }));
-          const sendStub = sinon.stub(element.$.restAPI,
+          const sendStub = sinon.stub(element.restApiService,
               'executeChangeAction').callsFake(
               (num, method, patchNum, endpoint, payload, onErr) => {
                 onErr();
@@ -2062,10 +2058,8 @@
       element.changeNum = '42';
       element.latestPatchNum = '2';
 
-      sinon.stub(element.$.confirmCherrypick.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
-      sinon.stub(element.$.confirmMove.$.restAPI,
-          'getRepoBranches').returns(Promise.resolve([]));
+      sinon.stub(appContext.restApiService, 'getRepoBranches').returns(
+          Promise.resolve([]));
       return element.reload();
     });
 
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index 9910fb6..d67cc73 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -73,7 +73,6 @@
   TopicName,
 } from '../../../types/common';
 import {assertNever} from '../../../utils/common-util';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
 import {GrLinkedChip} from '../../shared/gr-linked-chip/gr-linked-chip';
 import {appContext} from '../../../services/app-context';
@@ -117,7 +116,6 @@
 
 export interface GrChangeMetadata {
   $: {
-    restAPI: RestApiService & Element;
     webLinks: HTMLElement;
   };
 }
@@ -213,6 +211,8 @@
 
   flagsService = appContext.flagsService;
 
+  restApiService = appContext.restApiService;
+
   /** @override */
   ready() {
     super.ready();
@@ -250,13 +250,13 @@
         return;
       }
       this.set(['change', 'assignee'], acct);
-      this.$.restAPI.setAssignee(this.change._number, acct._account_id);
+      this.restApiService.setAssignee(this.change._number, acct._account_id);
     } else {
       if (!this.change.assignee) {
         return;
       }
       this.set(['change', 'assignee'], undefined);
-      this.$.restAPI.deleteAssignee(this.change._number);
+      this.restApiService.deleteAssignee(this.change._number);
     }
   }
 
@@ -309,7 +309,7 @@
     const topic = e.detail.length ? e.detail : undefined;
     this._settingTopic = true;
     const topicChangedForChangeNumber = this.change._number;
-    this.$.restAPI
+    this.restApiService
       .setChangeTopic(topicChangedForChangeNumber, topic)
       .then(newTopic => {
         if (this.change?._number !== topicChangedForChangeNumber) return;
@@ -357,7 +357,7 @@
     }
     const newHashtag = this._newHashtag;
     this._newHashtag = '' as Hashtag;
-    this.$.restAPI
+    this.restApiService
       .setChangeHashtag(this.change._number, {add: [newHashtag]})
       .then(newHashtag => {
         this.set(['change', 'hashtags'], newHashtag);
@@ -512,7 +512,7 @@
     }
     const target = (dom(e) as EventApi).rootTarget as GrLinkedChip;
     target.disabled = true;
-    this.$.restAPI
+    this.restApiService
       .setChangeTopic(this.change._number)
       .then(() => {
         target.disabled = false;
@@ -533,7 +533,7 @@
     }
     const target = (dom(e) as EventApi).rootTarget as GrLinkedChip;
     target.disabled = true;
-    this.$.restAPI
+    this.restApiService
       .setChangeHashtag(this.change._number, {remove: [target.text as Hashtag]})
       .then(newHashtags => {
         target.disabled = false;
@@ -677,7 +677,7 @@
       return undefined;
     }
     const provider = GrReviewerSuggestionsProvider.create(
-      this.$.restAPI,
+      this.restApiService,
       change._number,
       SUGGESTIONS_PROVIDERS_USERS_TYPES.ANY
     );
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
index 16b2582..a2f72b7 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_html.ts
@@ -432,5 +432,4 @@
       ></gr-endpoint-param>
     </gr-endpoint-decorator>
   </gr-external-style>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
index e95e3ba..3ee3470 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
@@ -839,8 +839,8 @@
       let setStub: SinonStubbedMember<RestApiService['setAssignee']>;
 
       setup(() => {
-        deleteStub = sinon.stub(element.$.restAPI, 'deleteAssignee');
-        setStub = sinon.stub(element.$.restAPI, 'setAssignee');
+        deleteStub = sinon.stub(element.restApiService, 'deleteAssignee');
+        setStub = sinon.stub(element.restApiService, 'setAssignee');
         element.serverConfig = {
           ...createServerInfo(),
           change: {
@@ -887,7 +887,7 @@
     test('changing topic', () => {
       const newTopic = 'the new topic' as TopicName;
       const setChangeTopicStub = sinon
-        .stub(element.$.restAPI, 'setChangeTopic')
+        .stub(element.restApiService, 'setChangeTopic')
         .returns(Promise.resolve(newTopic));
       element._handleTopicChanged(new CustomEvent('test', {detail: newTopic}));
       const topicChangedSpy = sinon.spy();
@@ -904,7 +904,7 @@
     test('topic removal', () => {
       const newTopic = 'the new topic' as TopicName;
       const setChangeTopicStub = sinon
-        .stub(element.$.restAPI, 'setChangeTopic')
+        .stub(element.restApiService, 'setChangeTopic')
         .returns(Promise.resolve(newTopic));
       const chip = element.shadowRoot!.querySelector('gr-linked-chip');
       const remove = chip!.$.remove;
@@ -925,7 +925,7 @@
       element._newHashtag = 'new hashtag' as Hashtag;
       const newHashtag: Hashtag[] = ['new hashtag' as Hashtag];
       const setChangeHashtagStub = sinon
-        .stub(element.$.restAPI, 'setChangeHashtag')
+        .stub(element.restApiService, 'setChangeHashtag')
         .returns(Promise.resolve(newHashtag));
       element._handleHashtagChanged();
       assert.isTrue(
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 24841fc..1731874 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -76,7 +76,6 @@
 import {changeStatuses, changeStatusString} from '../../../utils/change-util';
 import {EventType as PluginEventType} from '../../plugins/gr-plugin-types';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrJsApiInterface} from '../../shared/gr-js-api-interface/gr-js-api-interface-element';
 import {GrApplyFixDialog} from '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
 import {GrFileListHeader} from '../gr-file-list-header/gr-file-list-header';
@@ -205,7 +204,6 @@
 
 export interface GrChangeView {
   $: {
-    restAPI: RestApiService & Element;
     jsAPI: GrJsApiInterface;
     commentAPI: GrCommentApi;
     applyFixDialog: GrApplyFixDialog;
@@ -538,6 +536,8 @@
 
   _isChecksEnabled = false;
 
+  restApiService = appContext.restApiService;
+
   keyboardShortcuts() {
     return {
       [Shortcut.SEND_REPLY]: null, // DOC_ONLY binding
@@ -615,7 +615,7 @@
     this._getLoggedIn().then(loggedIn => {
       this._loggedIn = loggedIn;
       if (loggedIn) {
-        this.$.restAPI.getAccount().then(acct => {
+        this.restApiService.getAccount().then(acct => {
           this._account = acct;
         });
       }
@@ -847,7 +847,7 @@
     this.$.jsAPI.handleCommitMessage(this._change, message);
 
     this.$.commitMessageEditor.disabled = true;
-    this.$.restAPI
+    this.restApiService
       .putChangeCommitMessage(this._changeNum, message)
       .then(resp => {
         this.$.commitMessageEditor.disabled = false;
@@ -1242,7 +1242,7 @@
     }
 
     if (value.changeNum && value.project) {
-      this.$.restAPI.setInProjectLookup(value.changeNum, value.project);
+      this.restApiService.setInProjectLookup(value.changeNum, value.project);
     }
 
     const patchChanged =
@@ -1861,16 +1861,16 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _getServerConfig() {
-    return this.$.restAPI.getConfig();
+    return this.restApiService.getConfig();
   }
 
   _getProjectConfig() {
     if (!this._change) throw new Error('missing required change property');
-    return this.$.restAPI
+    return this.restApiService
       .getProjectConfig(this._change.project)
       .then(config => {
         this._projectConfig = config;
@@ -1878,7 +1878,7 @@
   }
 
   _getPreferences() {
-    return this.$.restAPI.getPreferences();
+    return this.restApiService.getPreferences();
   }
 
   _prepareCommitMsgForLinkify(msg: string) {
@@ -1928,8 +1928,9 @@
   _getChangeDetail() {
     if (!this._changeNum)
       throw new Error('missing required changeNum property');
-    const detailCompletes = this.$.restAPI.getChangeDetail(this._changeNum, r =>
-      this._handleGetChangeDetailError(r)
+    const detailCompletes = this.restApiService.getChangeDetail(
+      this._changeNum,
+      r => this._handleGetChangeDetailError(r)
     );
     const editCompletes = this._getEdit();
     const prefCompletes = this._getPreferences();
@@ -2018,7 +2019,7 @@
   _getEdit() {
     if (!this._changeNum)
       return Promise.reject(new Error('missing required changeNum property'));
-    return this.$.restAPI.getChangeEdit(this._changeNum, true);
+    return this.restApiService.getChangeEdit(this._changeNum, true);
   }
 
   _getLatestCommitMessage() {
@@ -2027,7 +2028,7 @@
     const lastpatchNum = computeLatestPatchNum(this._allPatchSets);
     if (lastpatchNum === undefined)
       throw new Error('missing lastPatchNum property');
-    return this.$.restAPI
+    return this.restApiService
       .getChangeCommitInfo(this._changeNum, lastpatchNum)
       .then(commitInfo => {
         if (!commitInfo) return;
@@ -2065,7 +2066,7 @@
       throw new Error('missing required _patchRange property');
     if (this._patchRange.patchNum === undefined)
       throw new Error('missing required patchNum property');
-    return this.$.restAPI
+    return this.restApiService
       .getChangeCommitInfo(this._changeNum, this._patchRange.patchNum)
       .then(commitInfo => {
         this._commitInfo = commitInfo;
@@ -2303,11 +2304,13 @@
     }
 
     this._mergeable = null;
-    return this.$.restAPI.getMergeable(this._changeNum).then(mergableInfo => {
-      if (mergableInfo) {
-        this._mergeable = mergableInfo.mergeable;
-      }
-    });
+    return this.restApiService
+      .getMergeable(this._changeNum)
+      .then(mergableInfo => {
+        if (mergableInfo) {
+          this._mergeable = mergableInfo.mergeable;
+        }
+      });
   }
 
   _computeCanStartReview(change: ChangeInfo) {
@@ -2490,7 +2493,7 @@
     this._updateCheckTimerHandle = this.async(() => {
       if (!this._change) throw new Error('missing required change property');
       const change = this._change;
-      fetchChangeUpdates(change, this.$.restAPI).then(result => {
+      fetchChangeUpdates(change, this.restApiService).then(result => {
         let toastMessage = null;
         if (!result.isLatest) {
           toastMessage = ReloadToastMessage.NEWER_REVISION;
@@ -2689,7 +2692,10 @@
   }
 
   _handleToggleStar(e: CustomEvent<{change: ChangeInfo; starred: boolean}>) {
-    this.$.restAPI.saveChangeStarred(e.detail.change._number, e.detail.starred);
+    this.restApiService.saveChangeStarred(
+      e.detail.change._number,
+      e.detail.starred
+    );
   }
 
   _getRevisionInfo(change: ChangeInfo | ParsedChangeInfo) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
index fbf01dc..c4b701f 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_html.ts
@@ -793,6 +793,5 @@
     </gr-reply-dialog>
   </gr-overlay>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-comment-api id="commentAPI"></gr-comment-api>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index 6262300..c896a99 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -704,7 +704,7 @@
         messages: createChangeMessages(1),
       };
       element._change.labels = {};
-      sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+      sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
         Promise.resolve({
           ...createChange(),
           // element has latest info
@@ -1474,7 +1474,7 @@
 
   test('diffMode defaults to side by side without preferences', done => {
     sinon
-      .stub(element.$.restAPI, 'getPreferences')
+      .stub(element.restApiService, 'getPreferences')
       .returns(Promise.resolve(createPreferences()));
     // No user prefs or diff view mode set.
 
@@ -1485,7 +1485,7 @@
   });
 
   test('diffMode defaults to preference when not already set', done => {
-    sinon.stub(element.$.restAPI, 'getPreferences').returns(
+    sinon.stub(element.restApiService, 'getPreferences').returns(
       Promise.resolve({
         ...createPreferences(),
         default_diff_view: DiffViewMode.UNIFIED,
@@ -1500,7 +1500,7 @@
 
   test('existing diffMode overrides preference', done => {
     element.viewState.diffMode = DiffViewMode.SIDE_BY_SIDE;
-    sinon.stub(element.$.restAPI, 'getPreferences').returns(
+    sinon.stub(element.restApiService, 'getPreferences').returns(
       Promise.resolve({
         ...createPreferences(),
         default_diff_view: DiffViewMode.UNIFIED,
@@ -1647,7 +1647,7 @@
     element._change = createChange();
     // Response code is 500, because we want to avoid window reloading
     const putStub = sinon
-      .stub(element.$.restAPI, 'putChangeCommitMessage')
+      .stub(element.restApiService, 'putChangeCommitMessage')
       .returns(Promise.resolve(new Response(null, {status: 500})));
 
     const mockEvent = (content: string) => {
@@ -1764,7 +1764,7 @@
 
   test('topic is coalesced to null', done => {
     sinon.stub(element, '_changeChanged');
-    sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+    sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
       Promise.resolve({
         ...createChange(),
         labels: {},
@@ -1781,7 +1781,7 @@
 
   test('commit sha is populated from getChangeDetail', done => {
     sinon.stub(element, '_changeChanged');
-    sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+    sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
       Promise.resolve({
         ...createChange(),
         labels: {},
@@ -1799,7 +1799,7 @@
   test('edit is added to change', () => {
     sinon.stub(element, '_changeChanged');
     const changeRevision = createRevision();
-    sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+    sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
       Promise.resolve({
         ...createChange(),
         labels: {},
@@ -1957,7 +1957,7 @@
 
   test('revert dialog opened with revert param', done => {
     sinon
-      .stub(element.$.restAPI, 'getLoggedIn')
+      .stub(element.restApiService, 'getLoggedIn')
       .callsFake(() => Promise.resolve(true));
     const awaitPluginsLoadedStub = sinon
       .stub(getPluginLoader(), 'awaitPluginsLoaded')
@@ -2034,7 +2034,7 @@
         messages: createChangeMessages(1),
       };
       element._change.labels = {};
-      sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+      sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
         Promise.resolve({
           ...createChange(),
           // element has latest info
@@ -2126,7 +2126,7 @@
         messages: createChangeMessages(1),
       };
       element._change.labels = {};
-      sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+      sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
         Promise.resolve({
           ...createChange(),
           // new patchset was uploaded
@@ -2306,7 +2306,7 @@
 
       test('_startUpdateCheckTimer negative delay', () => {
         const getChangeDetailStub = sinon
-          .stub(element.$.restAPI, 'getChangeDetail')
+          .stub(element.restApiService, 'getChangeDetail')
           .callsFake(() =>
             Promise.resolve({
               ...createChange(),
@@ -2328,7 +2328,7 @@
 
       test('_startUpdateCheckTimer up-to-date', async () => {
         const getChangeDetailStub = sinon
-          .stub(element.$.restAPI, 'getChangeDetail')
+          .stub(element.restApiService, 'getChangeDetail')
           .callsFake(() =>
             Promise.resolve({
               ...createChange(),
@@ -2351,7 +2351,7 @@
       });
 
       test('_startUpdateCheckTimer out-of-date shows an alert', done => {
-        sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+        sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
           Promise.resolve({
             ...createChange(),
             // new patchset was uploaded
@@ -2374,7 +2374,7 @@
       });
 
       test('_startUpdateCheckTimer respects _loading', async () => {
-        sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+        sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
           Promise.resolve({
             ...createChange(),
             // new patchset was uploaded
@@ -2396,7 +2396,7 @@
       });
 
       test('_startUpdateCheckTimer new status shows an alert', done => {
-        sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+        sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
           Promise.resolve({
             ...createChange(),
             // element has latest info
@@ -2418,7 +2418,7 @@
       });
 
       test('_startUpdateCheckTimer new messages shows an alert', done => {
-        sinon.stub(element.$.restAPI, 'getChangeDetail').callsFake(() =>
+        sinon.stub(element.restApiService, 'getChangeDetail').callsFake(() =>
           Promise.resolve({
             ...createChange(),
             revisions: {rev1: createRevision()},
@@ -2660,7 +2660,7 @@
   test('_selectedRevision updates when patchNum is changed', () => {
     const revision1: RevisionInfo = createRevision(1);
     const revision2: RevisionInfo = createRevision(2);
-    sinon.stub(element.$.restAPI, 'getChangeDetail').returns(
+    sinon.stub(element.restApiService, 'getChangeDetail').returns(
       Promise.resolve({
         ...createChange(),
         revisions: {
@@ -2689,7 +2689,7 @@
     const revision1 = createRevision(1);
     const revision2 = createRevision(2);
     const revision3 = createEditRevision();
-    sinon.stub(element.$.restAPI, 'getChangeDetail').returns(
+    sinon.stub(element.restApiService, 'getChangeDetail').returns(
       Promise.resolve({
         ...createChange(),
         revisions: {
@@ -2839,7 +2839,7 @@
     setup(() => {
       element._change = {...createChange(), labels: {}};
       getMergeableStub = sinon
-        .stub(element.$.restAPI, 'getMergeable')
+        .stub(element.restApiService, 'getMergeable')
         .returns(Promise.resolve({...createMergeable(), mergeable: true}));
     });
 
@@ -2873,7 +2873,7 @@
   test('_paramsChanged sets in projectLookup', () => {
     sinon.stub(element.$.relatedChanges, 'reload');
     sinon.stub(element, '_reload').returns(Promise.resolve([]));
-    const setStub = sinon.stub(element.$.restAPI, 'setInProjectLookup');
+    const setStub = sinon.stub(element.restApiService, 'setInProjectLookup');
     element._paramsChanged({
       view: GerritNav.View.CHANGE,
       changeNum: 101 as NumericChangeId,
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index e05bac0..6a4d5b1 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -35,7 +35,6 @@
 } from '../../../types/common';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   GrAutocomplete,
   AutocompleteSuggestion,
@@ -68,7 +67,6 @@
 // is converted
 export interface GrConfirmCherrypickDialog {
   $: {
-    restAPI: RestApiService & Element;
     branchInput: GrAutocomplete;
   };
 }
@@ -142,6 +140,8 @@
   @property({type: Object})
   reporting: ReportingService;
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._statuses = {};
@@ -301,7 +301,7 @@
       };
       // revisions and current_revision must exist hence casting
       const patchNum = change.revisions![change.current_revision!]._number;
-      this.$.restAPI
+      this.restApiService
         .executeChangeAction(
           change._number,
           HttpMethod.POST,
@@ -366,7 +366,7 @@
     if (input.startsWith('refs/heads/')) {
       input = input.substring('refs/heads/'.length);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getRepoBranches(input, this.project, SUGGESTIONS_LIMIT)
       .then((response: BranchInfo[] | undefined) => {
         const branches = [];
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
index 072f110..f784425 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_html.ts
@@ -212,5 +212,4 @@
       </template>
     </div>
   </gr-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
index 07f8f63..cc4bb8f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog_test.js
@@ -113,7 +113,7 @@
 
     test('cherry pick topic submit', done => {
       element.branch = 'master';
-      const executeChangeActionStub = sinon.stub(element.$.restAPI,
+      const executeChangeActionStub = sinon.stub(element.restApiService,
           'executeChangeAction').returns(Promise.resolve([]));
       MockInteractions.tap(element.shadowRoot.
           querySelector('gr-dialog').$.confirm);
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
index e9cf19e..60e2443 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog.ts
@@ -24,17 +24,12 @@
 import {htmlTemplate} from './gr-confirm-move-dialog_html';
 import {KeyboardShortcutMixin} from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {RepoName, BranchName} from '../../../types/common';
 import {AutocompleteSuggestion} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {appContext} from '../../../services/app-context';
 
 const SUGGESTIONS_LIMIT = 15;
 
-export interface GrConfirmMoveDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-confirm-move-dialog')
 export class GrConfirmMoveDialog extends KeyboardShortcutMixin(
   GestureEventListeners(LegacyElementMixin(PolymerElement))
@@ -73,6 +68,8 @@
     };
   }
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = () => this._getProjectBranchesSuggestions();
@@ -108,7 +105,7 @@
     if (input.startsWith('refs/heads/')) {
       input = input.substring('refs/heads/'.length);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getRepoBranches(input, this.project, SUGGESTIONS_LIMIT)
       .then(response => {
         const branches: AutocompleteSuggestion[] = [];
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
index b5b46d6..de75a39 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-move-dialog/gr-confirm-move-dialog_html.ts
@@ -79,5 +79,4 @@
       ></iron-autogrow-textarea>
     </div>
   </gr-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
index db0e1ff..15061d2 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
@@ -30,7 +30,7 @@
   AutocompleteQuery,
   AutocompleteSuggestion,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 interface RebaseChange {
   name: string;
@@ -43,7 +43,6 @@
 
 export interface GrConfirmRebaseDialog {
   $: {
-    restAPI: RestApiService & Element;
     parentInput: GrAutocomplete;
     rebaseOnParentInput: HTMLInputElement;
     rebaseOnOtherInput: HTMLInputElement;
@@ -92,6 +91,8 @@
   @property({type: Array})
   _recentChanges?: RebaseChange[];
 
+  private restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = input => this._getChangeSuggestions(input);
@@ -104,7 +105,7 @@
   // in case there are new/updated changes in the generic query since the
   // last time it was run.
   fetchRecentChanges() {
-    return this.$.restAPI
+    return this.restApiService
       .getChanges(undefined, 'is:open -age:90d')
       .then(response => {
         if (!response) return [];
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
index 687d31f..7d28de6 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_html.ts
@@ -127,5 +127,4 @@
       </div>
     </div>
   </gr-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.js b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.js
index 8bce572..8b3b73a 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog_test.js
@@ -118,7 +118,7 @@
         },
       ];
 
-      sinon.stub(element.$.restAPI, 'getChanges').returns(Promise.resolve(
+      sinon.stub(element.restApiService, 'getChanges').returns(Promise.resolve(
           [
             {
               _number: 123,
@@ -141,13 +141,13 @@
       return element._getRecentChanges()
           .then(() => {
             assert.deepEqual(element._recentChanges, recentChanges);
-            assert.equal(element.$.restAPI.getChanges.callCount, 1);
+            assert.equal(element.restApiService.getChanges.callCount, 1);
             // When called a second time, should not re-request recent changes.
             element._getRecentChanges();
           })
           .then(() => {
             assert.equal(element._getRecentChanges.callCount, 2);
-            assert.equal(element.$.restAPI.getChanges.callCount, 1);
+            assert.equal(element.restApiService.getChanges.callCount, 1);
           });
     });
 
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
index 84668ed..6c7b1c2 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-submit-dialog/gr-confirm-submit-dialog_html.ts
@@ -81,5 +81,4 @@
       </gr-endpoint-decorator>
     </div>
   </gr-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index c9a7058..e5405e3 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -53,8 +53,8 @@
 import {ChangeComments} from '../../diff/gr-comment-api/gr-comment-api';
 import {GrDiffModeSelector} from '../../diff/gr-diff-mode-selector/gr-diff-mode-selector';
 import {DiffViewMode} from '../../../constants/constants';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrButton} from '../../shared/gr-button/gr-button';
+import {appContext} from '../../../services/app-context';
 
 // Maximum length for patch set descriptions.
 const PATCH_DESC_MAX_LENGTH = 500;
@@ -69,7 +69,6 @@
 export interface GrFileListHeader {
   $: {
     modeSelect: GrDiffModeSelector;
-    restAPI: RestApiService & Element;
     expandBtn: GrButton;
     collapseBtn: GrButton;
   };
@@ -169,6 +168,8 @@
   @property({type: Object})
   revisionInfo?: RevisionInfo;
 
+  private readonly restApiService = appContext.restApiService;
+
   @computed('loggedIn', 'change', 'account')
   get _descriptionReadOnly(): boolean {
     if (
@@ -294,7 +295,7 @@
       this.patchNum
     )!;
     const sha = this._getPatchsetHash(this.change.revisions, rev);
-    return this.$.restAPI
+    return this.restApiService
       .setDescription(this.changeNum, this.patchNum, desc)
       .then((res: Response) => {
         if (res.ok) {
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
index 1355412..d9beff4 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_html.ts
@@ -273,5 +273,4 @@
       </div>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
index 3469b3a..cee0262 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header_test.js
@@ -86,7 +86,7 @@
   });
 
   test('description editing', () => {
-    const putDescStub = sinon.stub(element.$.restAPI, 'setDescription')
+    const putDescStub = sinon.stub(element.restApiService, 'setDescription')
         .returns(Promise.resolve({ok: true}));
 
     element.changeNum = '42';
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
index d925f96..a77da9e 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list.ts
@@ -54,7 +54,6 @@
   specialFilePathCompare,
 } from '../../../utils/path-list-util';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   ConfigInfo,
   ElementPropertyDeepChange,
@@ -107,7 +106,6 @@
 
 export interface GrFileList {
   $: {
-    restAPI: RestApiService & Element;
     diffPreferencesDialog: GrDiffPreferencesDialog;
     diffCursor: GrDiffCursor;
     fileCursor: GrCursorManager;
@@ -334,6 +332,8 @@
 
   private readonly reporting = appContext.reportingService;
 
+  private readonly restApiService = appContext.restApiService;
+
   get keyBindings() {
     return {
       esc: '_handleEscKey',
@@ -457,7 +457,7 @@
     const promises = [];
 
     promises.push(
-      this.$.restAPI
+      this.restApiService
         .getChangeOrEditFiles(changeNum, patchRange)
         .then(filesByPath => {
           this._filesByPath = filesByPath;
@@ -544,11 +544,11 @@
   }
 
   _getDiffPreferences() {
-    return this.$.restAPI.getDiffPreferences();
+    return this.restApiService.getDiffPreferences();
   }
 
   _getPreferences() {
-    return this.$.restAPI.getPreferences();
+    return this.restApiService.getPreferences();
   }
 
   private _toggleFileExpanded(file: PatchSetFile) {
@@ -765,7 +765,7 @@
       throw new Error('changeNum and patchRange must be set');
     }
 
-    return this.$.restAPI.saveFileReviewed(
+    return this.restApiService.saveFileReviewed(
       this.changeNum,
       this.patchRange.patchNum,
       path,
@@ -774,14 +774,14 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _getReviewedFiles(changeNum: NumericChangeId, patchRange: PatchRange) {
     if (this.editMode) {
       return Promise.resolve([]);
     }
-    return this.$.restAPI.getReviewedFiles(changeNum, patchRange.patchNum);
+    return this.restApiService.getReviewedFiles(changeNum, patchRange.patchNum);
   }
 
   _normalizeChangeFilesResponse(
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
index d93ce68..b99c96a 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_html.ts
@@ -763,7 +763,6 @@
     on-reload-diff-preference="_handleReloadingDiffPreference"
   >
   </gr-diff-preferences-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
   <gr-diff-cursor id="diffCursor"></gr-diff-cursor>
   <gr-cursor-manager
diff --git a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
index c750bd2..8f484e9 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-file-list/gr-file-list_test.js
@@ -1837,7 +1837,7 @@
       });
 
       test('_getReviewedFiles does not call API', () => {
-        const apiSpy = sinon.spy(element.$.restAPI, 'getReviewedFiles');
+        const apiSpy = sinon.spy(element.restApiService, 'getReviewedFiles');
         element.editMode = true;
         return element._getReviewedFiles().then(files => {
           assert.equal(files.length, 0);
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
index 1957f5c..cf96c98 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog.ts
@@ -24,13 +24,7 @@
 import {htmlTemplate} from './gr-included-in-dialog_html';
 import {customElement, property} from '@polymer/decorators';
 import {IncludedInInfo, NumericChangeId} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
-
-export interface GrIncludedInDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 interface DisplayGroup {
   title: string;
@@ -63,18 +57,22 @@
   @property({type: String})
   _filterText = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
     if (!this.changeNum) {
       return Promise.reject(new Error('missing required property changeNum'));
     }
     this._filterText = '';
-    return this.$.restAPI.getChangeIncludedIn(this.changeNum).then(configs => {
-      if (!configs) {
-        return;
-      }
-      this._includedIn = configs;
-      this._loaded = true;
-    });
+    return this.restApiService
+      .getChangeIncludedIn(this.changeNum)
+      .then(configs => {
+        if (!configs) {
+          return;
+        }
+        this._includedIn = configs;
+        this._loaded = true;
+      });
   }
 
   _resetData() {
diff --git a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
index 8e90f3b..2029209 100644
--- a/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-included-in-dialog/gr-included-in-dialog_html.ts
@@ -100,5 +100,4 @@
       </ul>
     </div>
   </template>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
index 8b0cf4b..e6c20fb 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message.ts
@@ -41,9 +41,9 @@
   NumericChangeId,
   ChangeMessageId,
 } from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {CommentThread} from '../../../utils/comment-util';
 import {hasOwnProperty} from '../../../utils/common-util';
+import {appContext} from '../../../services/app-context';
 
 const PATCH_SET_PREFIX_PATTERN = /^(?:Uploaded\s*)?(?:P|p)atch (?:S|s)et \d+:\s*(.*)/;
 const LABEL_TITLE_SCORE_PATTERN = /^(-?)([A-Za-z0-9-]+?)([+-]\d+)?[.]?$/;
@@ -58,12 +58,6 @@
   id: ChangeMessageId;
 }
 
-export interface GrMessage {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 interface ChangeMessage extends ChangeMessageInfo {
   // TODO(TS): maybe should be an enum instead
   type: string;
@@ -192,6 +186,8 @@
   })
   _commentCountText = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   created() {
     super.created();
     this.addEventListener('click', e => this._handleClick(e));
@@ -199,13 +195,13 @@
 
   attached() {
     super.attached();
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this.config = config;
     });
-    this.$.restAPI.getLoggedIn().then(loggedIn => {
+    this.restApiService.getLoggedIn().then(loggedIn => {
       this._loggedIn = loggedIn;
     });
-    this.$.restAPI.getIsAdmin().then(isAdmin => {
+    this.restApiService.getIsAdmin().then(isAdmin => {
       this._isAdmin = !!isAdmin;
     });
   }
@@ -472,7 +468,7 @@
     e.preventDefault();
     if (!this.message || !this.message.id || !this.changeNum) return;
     this._isDeletingChangeMsg = true;
-    this.$.restAPI
+    this.restApiService
       .deleteChangeCommitMessage(this.changeNum, this.message.id)
       .then(() => {
         this._isDeletingChangeMsg = false;
@@ -488,7 +484,7 @@
 
   @observe('projectName')
   _projectNameChanged(name: string) {
-    this.$.restAPI.getProjectConfig(name as RepoName).then(config => {
+    this.restApiService.getProjectConfig(name as RepoName).then(config => {
       this._projectConfig = config;
     });
   }
diff --git a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
index ae4adf7..64fc384 100644
--- a/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-message/gr-message_html.ts
@@ -306,5 +306,4 @@
       </span>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
index f8a4af2..42bf1e9 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list.ts
@@ -30,7 +30,6 @@
 import {changeIsOpen} from '../../../utils/change-util';
 import {getPluginEndpoints} from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   ChangeId,
   ChangeInfo,
@@ -43,12 +42,7 @@
   SubmittedTogetherInfo,
 } from '../../../types/common';
 import {ParsedChangeInfo} from '../../shared/gr-rest-api-interface/gr-reviewer-updates-parser';
-
-export interface GrRelatedChangesList {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 function getEmptySubmitTogetherInfo(): SubmittedTogetherInfo {
   return {changes: [], non_visible_changes: 0};
@@ -117,6 +111,8 @@
   @property({type: Array})
   _sameTopic?: ChangeInfo[] = [];
 
+  private readonly restApiService = appContext.restApiService;
+
   clear() {
     this.loading = true;
     this.hidden = true;
@@ -135,7 +131,7 @@
     const change = this.change;
     this.loading = true;
     const promises: Array<Promise<void>> = [
-      this.$.restAPI
+      this.restApiService
         .getRelatedChanges(change._number, this.patchNum)
         .then(response => {
           if (!response) {
@@ -148,13 +144,13 @@
             response.changes
           );
         }),
-      this.$.restAPI
+      this.restApiService
         .getChangesSubmittedTogether(change._number)
         .then(response => {
           this._submittedTogether = response;
           this._fireReloadEvent();
         }),
-      this.$.restAPI
+      this.restApiService
         .getChangeCherryPicks(change.project, change.change_id, change._number)
         .then(response => {
           this._cherryPicks = response || [];
@@ -165,12 +161,14 @@
     // Get conflicts if change is open and is mergeable.
     if (changeIsOpen(change) && this.mergeable) {
       promises.push(
-        this.$.restAPI.getChangeConflicts(change._number).then(response => {
-          // Because the server doesn't always return a response and the
-          // template expects an array, always return an array.
-          this._conflicts = response ? response : [];
-          this._fireReloadEvent();
-        })
+        this.restApiService
+          .getChangeConflicts(change._number)
+          .then(response => {
+            // Because the server doesn't always return a response and the
+            // template expects an array, always return an array.
+            this._conflicts = response ? response : [];
+            this._fireReloadEvent();
+          })
       );
     }
 
@@ -181,7 +179,7 @@
             throw new Error('_getServerConfig returned undefined ');
           }
           if (!config.change.submit_whole_topic) {
-            return this.$.restAPI
+            return this.restApiService
               .getChangesWithSameTopic(change.topic, change._number)
               .then(response => {
                 this._sameTopic = response;
@@ -222,7 +220,7 @@
   }
 
   _getServerConfig() {
-    return this.$.restAPI.getConfig();
+    return this.restApiService.getConfig();
   }
 
   _computeChangeURL(
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_html.ts b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_html.ts
index d4cd0f6..0f42028 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_html.ts
@@ -214,5 +214,4 @@
     </gr-endpoint-decorator>
   </div>
   <div hidden$="[[!loading]]">Loading...</div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js
index 3983c5a..e71df971 100644
--- a/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js
+++ b/polygerrit-ui/app/elements/change/gr-related-changes-list/gr-related-changes-list_test.js
@@ -237,13 +237,13 @@
     };
     element.mergeable = true;
     element.addEventListener('new-section-loaded', loadedStub);
-    sinon.stub(element.$.restAPI, 'getRelatedChanges')
+    sinon.stub(element.restApiService, 'getRelatedChanges')
         .returns(Promise.resolve({changes: []}));
-    sinon.stub(element.$.restAPI, 'getChangesSubmittedTogether')
+    sinon.stub(element.restApiService, 'getChangesSubmittedTogether')
         .returns(Promise.resolve());
-    sinon.stub(element.$.restAPI, 'getChangeCherryPicks')
+    sinon.stub(element.restApiService, 'getChangeCherryPicks')
         .returns(Promise.resolve());
-    sinon.stub(element.$.restAPI, 'getChangeConflicts')
+    sinon.stub(element.restApiService, 'getChangeConflicts')
         .returns(Promise.resolve());
 
     return element.reload().then(() => {
@@ -257,13 +257,13 @@
     setup(() => {
       element = basicFixture.instantiate();
 
-      sinon.stub(element.$.restAPI, 'getRelatedChanges')
+      sinon.stub(element.restApiService, 'getRelatedChanges')
           .returns(Promise.resolve({changes: []}));
-      sinon.stub(element.$.restAPI, 'getChangesSubmittedTogether')
+      sinon.stub(element.restApiService, 'getChangesSubmittedTogether')
           .returns(Promise.resolve());
-      sinon.stub(element.$.restAPI, 'getChangeCherryPicks')
+      sinon.stub(element.restApiService, 'getChangeCherryPicks')
           .returns(Promise.resolve());
-      sinon.stub(element.$.restAPI, 'getChangeConflicts')
+      sinon.stub(element.restApiService, 'getChangeConflicts')
           .returns(Promise.resolve());
     });
 
@@ -286,13 +286,13 @@
     setup(() => {
       element = basicFixture.instantiate();
 
-      sinon.stub(element.$.restAPI, 'getRelatedChanges')
+      sinon.stub(element.restApiService, 'getRelatedChanges')
           .returns(Promise.resolve({changes: []}));
-      sinon.stub(element.$.restAPI, 'getChangesSubmittedTogether')
+      sinon.stub(element.restApiService, 'getChangesSubmittedTogether')
           .returns(Promise.resolve());
-      sinon.stub(element.$.restAPI, 'getChangeCherryPicks')
+      sinon.stub(element.restApiService, 'getChangeCherryPicks')
           .returns(Promise.resolve());
-      conflictsStub = sinon.stub(element.$.restAPI, 'getChangeConflicts')
+      conflictsStub = sinon.stub(element.restApiService, 'getChangeConflicts')
           .returns(Promise.resolve());
     });
 
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index f42adc6..d0d0745 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -51,10 +51,7 @@
 import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announcer';
 import {TargetElement} from '../../plugins/gr-plugin-types';
 import {customElement, observe, property} from '@polymer/decorators';
-import {
-  ErrorCallback,
-  RestApiService,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {FixIronA11yAnnouncer} from '../../../types/types';
 import {
   AccountAddition,
@@ -158,7 +155,6 @@
 
 export interface GrReplyDialog {
   $: {
-    restAPI: RestApiService & Element;
     jsAPI: JsApiService & Element;
     reviewers: GrAccountList;
     ccs: GrAccountList;
@@ -374,6 +370,8 @@
   @property({type: Array, computed: '_computeAllReviewers(_reviewers.*)'})
   _allReviewers: (AccountInfo | GroupInfo)[] = [];
 
+  private readonly restApiService = appContext.restApiService;
+
   get keyBindings() {
     return {
       esc: '_handleEscKey',
@@ -431,7 +429,7 @@
   open(focusTarget?: FocusTarget) {
     if (!this.change) throw new Error('missing required change property');
     this.knownLatestState = LatestPatchState.CHECKING;
-    fetchChangeUpdates(this.change, this.$.restAPI).then(result => {
+    fetchChangeUpdates(this.change, this.restApiService).then(result => {
       this.knownLatestState = result.isLatest
         ? LatestPatchState.LATEST
         : LatestPatchState.NOT_LATEST;
@@ -446,9 +444,9 @@
       // Otherwise, check for an unsaved draft in localstorage.
       this.draft = this._loadStoredDraft();
     }
-    if (this.$.restAPI.hasPendingDiffDrafts()) {
+    if (this.restApiService.hasPendingDiffDrafts()) {
       this._savingComments = true;
-      this.$.restAPI.awaitPendingDiffDrafts().then(() => {
+      this.restApiService.awaitPendingDiffDrafts().then(() => {
         this.dispatchEvent(
           new CustomEvent('comment-refresh', {
             composed: true,
@@ -611,7 +609,7 @@
       return;
     }
 
-    return this.$.restAPI
+    return this.restApiService
       .removeChangeReviewer(this.change._number, accountKey(account))
       .then((response?: Response) => {
         if (!response?.ok || !this.change) return;
@@ -811,7 +809,7 @@
     // Using response.clone() here, because getResponseObject() and
     // potentially the generic error handler will want to call text() on the
     // response object, which can only be done once per object.
-    const jsonPromise = this.$.restAPI.getResponseObject(response.clone());
+    const jsonPromise = this.restApiService.getResponseObject(response.clone());
     return jsonPromise.then((parsed: ParsedJSON) => {
       const result = parsed as ReviewResult;
       // Only perform custom error handling for 400s and a parseable
@@ -1224,7 +1222,7 @@
   }
 
   _getAccount() {
-    return this.$.restAPI.getAccount();
+    return this.restApiService.getAccount();
   }
 
   _cancelTapHandler(e: Event) {
@@ -1291,7 +1289,7 @@
   _saveReview(review: ReviewInput, errFn?: ErrorCallback) {
     if (!this.change) throw new Error('missing required change property');
     if (!this.patchNum) throw new Error('missing required patchNum property');
-    return this.$.restAPI.saveChangeReview(
+    return this.restApiService.saveChangeReview(
       this.change._number,
       this.patchNum,
       review,
@@ -1467,7 +1465,7 @@
 
   _getReviewerSuggestionsProvider(change: ChangeInfo) {
     const provider = GrReviewerSuggestionsProvider.create(
-      this.$.restAPI,
+      this.restApiService,
       change._number,
       SUGGESTIONS_PROVIDERS_USERS_TYPES.REVIEWER
     );
@@ -1477,7 +1475,7 @@
 
   _getCcSuggestionsProvider(change: ChangeInfo) {
     const provider = GrReviewerSuggestionsProvider.create(
-      this.$.restAPI,
+      this.restApiService,
       change._number,
       SUGGESTIONS_PROVIDERS_USERS_TYPES.CC
     );
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
index c56a5c9..45c4799 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_html.ts
@@ -617,6 +617,5 @@
     </div>
   </div>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
index b612a57..a606624 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog_test.js
@@ -131,7 +131,7 @@
           try {
             const result = jsonResponseProducer(review) || {};
             const resultStr =
-            element.$.restAPI.JSON_PREFIX + JSON.stringify(result);
+            element.restApiService.JSON_PREFIX + JSON.stringify(result);
             resolve({
               ok: true,
               text() {
@@ -977,7 +977,7 @@
   });
 
   test('_removeAccount', done => {
-    sinon.stub(element.$.restAPI, 'removeChangeReviewer')
+    sinon.stub(element.restApiService, 'removeChangeReviewer')
         .returns(Promise.resolve({ok: true}));
     const arr = [makeAccount(), makeAccount()];
     element.change.reviewers = {
@@ -1283,7 +1283,7 @@
 
     setup(() => {
       startReviewStub = sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'startReview')
           .callsFake(() => Promise.resolve());
     });
@@ -1371,8 +1371,9 @@
         const refreshHandler = sinon.stub();
 
         element.addEventListener('comment-refresh', refreshHandler);
-        sinon.stub(element.$.restAPI, 'hasPendingDiffDrafts').returns(true);
-        element.$.restAPI._pendingRequests.sendDiffDraft = [promise];
+        sinon.stub(element.restApiService, 'hasPendingDiffDrafts').returns(
+            true);
+        element.restApiService._pendingRequests.sendDiffDraft = [promise];
         element.open();
 
         assert.isFalse(refreshHandler.called);
@@ -1380,14 +1381,15 @@
 
         promise.resolve();
 
-        return element.$.restAPI.awaitPendingDiffDrafts().then(() => {
+        return element.restApiService.awaitPendingDiffDrafts().then(() => {
           assert.isTrue(refreshHandler.called);
           assert.isFalse(element._savingComments);
         });
       });
 
       test('no', () => {
-        sinon.stub(element.$.restAPI, 'hasPendingDiffDrafts').returns(false);
+        sinon.stub(element.restApiService, 'hasPendingDiffDrafts').returns(
+            false);
         element.open();
         assert.notOk(element._savingComments);
       });
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
index 9c3fa42..33ac51f 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list.ts
@@ -39,16 +39,10 @@
 } from '../../../types/common';
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
 import {GrAccountChip} from '../../shared/gr-account-chip/gr-account-chip';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {isRemovableReviewer} from '../../../utils/change-util';
 import {ReviewerState} from '../../../constants/constants';
-
-export interface GrReviewerList {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 @customElement('gr-reviewer-list')
 export class GrReviewerList extends GestureEventListeners(
@@ -94,6 +88,8 @@
   @property({type: Object})
   _xhrPromise?: Promise<Response | undefined>;
 
+  private readonly restApiService = appContext.restApiService;
+
   @computed('ccsOnly')
   get _addLabel() {
     return this.ccsOnly ? 'Add CC' : 'Add reviewer';
@@ -323,6 +319,6 @@
 
   _removeReviewer(id: AccountId | EmailAddress): Promise<Response | undefined> {
     if (!this.change) return Promise.resolve(undefined);
-    return this.$.restAPI.removeChangeReviewer(this.change._number, id);
+    return this.restApiService.removeChangeReviewer(this.change._number, id);
   }
 }
diff --git a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
index 616a7db..dd18d03 100644
--- a/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-reviewer-list/gr-reviewer-list_html.ts
@@ -69,5 +69,4 @@
       >
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
index cab17dd..28327a1 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog.ts
@@ -24,7 +24,7 @@
 import {htmlTemplate} from './gr-upload-help-dialog_html';
 import {customElement, property} from '@polymer/decorators';
 import {RevisionInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 const COMMIT_COMMAND = 'git add . && git commit --amend --no-edit';
 const PUSH_COMMAND_PREFIX = 'git push origin HEAD:refs/for/';
@@ -32,12 +32,6 @@
 // Command names correspond to download plugin definitions.
 const PREFERRED_FETCH_COMMAND_ORDER = ['checkout', 'cherry pick', 'pull'];
 
-export interface GrUploadHelpDialog {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-upload-help-dialog')
 export class GrUploadHelpDialog extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -73,13 +67,17 @@
   @property({type: String, computed: '_computePushCommand(targetBranch)'})
   _pushCommand?: string;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
-    this.$.restAPI
+    this.restApiService
       .getLoggedIn()
       .then(loggedIn =>
-        loggedIn ? this.$.restAPI.getPreferences() : Promise.resolve(undefined)
+        loggedIn
+          ? this.restApiService.getPreferences()
+          : Promise.resolve(undefined)
       )
       .then(prefs => {
         if (prefs) {
diff --git a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts
index 1ee3a3a..d44cbb0 100644
--- a/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts
+++ b/polygerrit-ui/app/elements/change/gr-upload-help-dialog/gr-upload-help-dialog_html.ts
@@ -66,5 +66,4 @@
       </ol>
     </div>
   </gr-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
index ef0ced8..56cb763 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown.ts
@@ -26,7 +26,7 @@
 import {getUserName} from '../../../utils/display-name-util';
 import {customElement, property} from '@polymer/decorators';
 import {AccountInfo, ServerInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 const INTERPOLATE_URL_PATTERN = /\${([\w]+)}/g;
 
@@ -36,12 +36,6 @@
   }
 }
 
-export interface GrAccountDropdown {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-account-dropdown')
 export class GrAccountDropdown extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -71,12 +65,14 @@
   @property({type: String})
   _switchAccountUrl = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
     this._handleLocationChange();
     this.listen(window, 'location-change', '_handleLocationChange');
-    this.$.restAPI.getConfig().then(cfg => {
+    this.restApiService.getConfig().then(cfg => {
       this.config = cfg;
 
       if (cfg && cfg.auth && cfg.auth.switch_account_url) {
diff --git a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_html.ts b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_html.ts
index b67e1e8..0fa2f1e 100644
--- a/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-account-dropdown/gr-account-dropdown_html.ts
@@ -49,5 +49,4 @@
       aria-label="Account avatar"
     ></gr-avatar>
   </gr-dropdown>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
index e4e4056..91a8ebf 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager.ts
@@ -35,7 +35,6 @@
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {GrErrorDialog} from '../gr-error-dialog/gr-error-dialog';
 import {GrAlert} from '../../shared/gr-alert/gr-alert';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {FetchRequest} from '../../shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper';
 import {ErrorType, FixIronA11yAnnouncer} from '../../../types/types';
 import {AccountId} from '../../../types/common';
@@ -72,7 +71,6 @@
     noInteractionOverlay: GrOverlay;
     errorDialog: GrErrorDialog;
     errorOverlay: GrOverlay;
-    restAPI: RestApiService & Element;
   };
 }
 @customElement('gr-error-manager')
@@ -116,11 +114,11 @@
 
   _authErrorHandlerDeregistrationHook?: Function;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
-
     this._authService = appContext.authService;
-
     this.reporting = appContext.reportingService;
     this.eventEmitter = appContext.eventEmitter;
   }
@@ -204,7 +202,7 @@
         // This indicates the auth token may no longer valid.
         // Re-check on auth
         this._authService.clearCache();
-        this.$.restAPI.getLoggedIn();
+        this.restApiService.getLoggedIn();
       } else if (!this._shouldSuppressError(errorText)) {
         const trace =
           response.headers && response.headers.get('X-Gerrit-Trace');
@@ -239,7 +237,7 @@
     url,
     trace,
   }: ErrorMsg) {
-    this.$.restAPI.getLoggedIn().then(isLoggedIn => {
+    this.restApiService.getLoggedIn().then(isLoggedIn => {
       const tip = isLoggedIn
         ? 'You might have not enough privileges.'
         : 'You might have not enough privileges. Sign in and try again.';
@@ -422,10 +420,10 @@
     this._lastCredentialCheck = Date.now();
 
     // force to refetch account info
-    this.$.restAPI.invalidateAccountsCache();
+    this.restApiService.invalidateAccountsCache();
     this._authService.clearCache();
 
-    this.$.restAPI.getLoggedIn().then(isLoggedIn => {
+    this.restApiService.getLoggedIn().then(isLoggedIn => {
       // do nothing if its refreshing
       if (!this._refreshingCredentials) return;
 
@@ -437,7 +435,7 @@
         this._requestCheckLoggedIn();
       } else {
         // check account
-        this.$.restAPI.getAccount().then(account => {
+        this.restApiService.getAccount().then(account => {
           if (this._refreshingCredentials) {
             // If the credentials were refreshed but the account is different
             // then reload the page completely.
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.ts b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.ts
index 1cefb78..c67ed07 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_html.ts
@@ -34,5 +34,4 @@
     no-cancel-on-outside-click=""
   >
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
index f13276f..7fc35c6 100644
--- a/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
+++ b/polygerrit-ui/app/elements/core/gr-error-manager/gr-error-manager_test.js
@@ -67,7 +67,7 @@
               element, '_showAuthErrorAlert'
           );
           const responseText = Promise.resolve('Authentication required\n');
-          sinon.stub(element.$.restAPI, 'getLoggedIn')
+          sinon.stub(element.restApiService, 'getLoggedIn')
               .returns(Promise.resolve(true));
           element.dispatchEvent(
               new CustomEvent('server-error', {
@@ -83,9 +83,9 @@
 
     test('recheck auth for 403 with auth error if authed before', done => {
       // starts with authed state
-      element.$.restAPI.getLoggedIn();
+      element.restApiService.getLoggedIn();
       const responseText = Promise.resolve('Authentication required\n');
-      sinon.stub(element.$.restAPI, 'getLoggedIn')
+      sinon.stub(element.restApiService, 'getLoggedIn')
           .returns(Promise.resolve(true));
       element.dispatchEvent(
           new CustomEvent('server-error', {
@@ -94,7 +94,7 @@
             composed: true, bubbles: true,
           }));
       flush(() => {
-        assert.isTrue(element.$.restAPI.getLoggedIn.calledOnce);
+        assert.isTrue(element.restApiService.getLoggedIn.calledOnce);
         done();
       });
     });
@@ -241,8 +241,9 @@
 
     test('show auth refresh toast', async () => {
       // starts with authed state
-      element.$.restAPI.getLoggedIn();
-      const refreshStub = sinon.stub(element.$.restAPI, 'getAccount').callsFake(
+      element.restApiService.getLoggedIn();
+      const refreshStub = sinon.stub(element.restApiService,
+          'getAccount').callsFake(
           () => Promise.resolve({}));
       const windowOpen = sinon.stub(window, 'open');
       const responseText = Promise.resolve('Authentication required\n');
@@ -313,7 +314,7 @@
 
     test('auth toast should dismiss existing toast', async () => {
       // starts with authed state
-      element.$.restAPI.getLoggedIn();
+      element.restApiService.getLoggedIn();
       const responseText = Promise.resolve('Authentication required\n');
 
       // fake an alert
@@ -353,7 +354,7 @@
 
     test('regular toast should dismiss regular toast', () => {
       // starts with authed state
-      element.$.restAPI.getLoggedIn();
+      element.restApiService.getLoggedIn();
 
       // fake an alert
       element.dispatchEvent(
@@ -379,7 +380,7 @@
 
     test('regular toast should not dismiss auth toast', done => {
       // starts with authed state
-      element.$.restAPI.getLoggedIn();
+      element.restApiService.getLoggedIn();
       const responseText = Promise.resolve('Authentication required\n');
 
       // fake auth
@@ -456,7 +457,7 @@
 
     test('refreshes with same credentials', done => {
       const accountPromise = Promise.resolve({_account_id: 1234});
-      sinon.stub(element.$.restAPI, 'getAccount')
+      sinon.stub(element.restApiService, 'getAccount')
           .returns(accountPromise);
       const requestCheckStub = sinon.stub(element, '_requestCheckLoggedIn');
       const handleRefreshStub = sinon.stub(element,
@@ -513,7 +514,7 @@
 
     test('reloads when refreshed credentials differ', done => {
       const accountPromise = Promise.resolve({_account_id: 1234});
-      sinon.stub(element.$.restAPI, 'getAccount')
+      sinon.stub(element.restApiService, 'getAccount')
           .returns(accountPromise);
       const requestCheckStub = sinon.stub(
           element,
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
index c4ed683..f1b9ea1 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header.ts
@@ -29,7 +29,6 @@
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
 import {getAdminLinks, NavLink} from '../../../utils/admin-nav-util';
 import {customElement, property, observe} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AccountDetailInfo,
   RequireProperties,
@@ -40,6 +39,7 @@
 import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {AuthType} from '../../../constants/constants';
 import {DropdownLink} from '../../shared/gr-dropdown/gr-dropdown';
+import {appContext} from '../../../services/app-context';
 
 type MainHeaderLink = RequireProperties<DropdownLink, 'url' | 'name'>;
 
@@ -105,7 +105,6 @@
 
 export interface GrMainHeader {
   $: {
-    restAPI: RestApiService & Element;
     jsAPI: JsApiService & Element;
   };
 }
@@ -161,6 +160,8 @@
   @property({type: Boolean})
   mobileSearchHidden = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   ready() {
     super.ready();
@@ -274,8 +275,8 @@
     this.loading = true;
 
     return Promise.all([
-      this.$.restAPI.getAccount(),
-      this.$.restAPI.getTopMenus(),
+      this.restApiService.getAccount(),
+      this.restApiService.getTopMenus(),
       getPluginLoader().awaitPluginsLoaded(),
     ]).then(result => {
       const account = result[0];
@@ -287,7 +288,7 @@
       return getAdminLinks(
         account,
         () =>
-          this.$.restAPI.getAccountCapabilities().then(capabilities => {
+          this.restApiService.getAccountCapabilities().then(capabilities => {
             if (!capabilities) {
               throw new Error('getAccountCapabilities returns undefined');
             }
@@ -301,14 +302,14 @@
   }
 
   _loadConfig() {
-    this.$.restAPI
+    this.restApiService
       .getConfig()
       .then(config => {
         if (!config) {
           throw new Error('getConfig returned undefined');
         }
         this._retrieveRegisterURL(config);
-        return getDocsBaseUrl(config, this.$.restAPI);
+        return getDocsBaseUrl(config, this.restApiService);
       })
       .then(docBaseUrl => {
         this._docBaseUrl = docBaseUrl;
@@ -321,7 +322,7 @@
       return;
     }
 
-    this.$.restAPI.getPreferences().then(prefs => {
+    this.restApiService.getPreferences().then(prefs => {
       this._userLinks =
         prefs && prefs.my ? prefs.my.map(this._createHeaderLink) : [];
     });
diff --git a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
index 5778fb8..0cdd0f2 100644
--- a/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-main-header/gr-main-header_html.ts
@@ -239,5 +239,4 @@
     </div>
   </nav>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index 79f029b..d0e1167d 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -63,7 +63,6 @@
   ServerInfo,
   UrlEncodedCommentId,
 } from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AppElement,
   AppElementParams,
@@ -267,12 +266,6 @@
   });
 })();
 
-export interface GrRouter {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 export interface PageContextWithQueryMap extends PageContext {
   queryMap: Map<string, string> | URLSearchParams;
 }
@@ -314,6 +307,8 @@
 
   private readonly reporting = appContext.reportingService;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
   }
@@ -658,7 +653,7 @@
       return Promise.resolve();
     }
 
-    return this.$.restAPI
+    return this.restApiService
       .getFromProjectLookup(params.changeNum)
       .then(project => {
         // Show a 404 and terminate if the lookup request failed. Attempting
@@ -745,7 +740,7 @@
    * (if it resolves).
    */
   _redirectIfNotLoggedIn(data: PageContext) {
-    return this.$.restAPI.getLoggedIn().then(loggedIn => {
+    return this.restApiService.getLoggedIn().then(loggedIn => {
       if (loggedIn) {
         return Promise.resolve();
       } else {
@@ -757,7 +752,7 @@
 
   /**  Page.js middleware that warms the REST API's logged-in cache line. */
   _loadUserMiddleware(_: PageContext, next: PageNextCallback) {
-    this.$.restAPI.getLoggedIn().then(() => {
+    this.restApiService.getLoggedIn().then(() => {
       next();
     });
   }
@@ -1125,7 +1120,7 @@
       this._redirect(newUrl);
       return null;
     }
-    return this.$.restAPI.getLoggedIn().then(loggedIn => {
+    return this.restApiService.getLoggedIn().then(loggedIn => {
       if (loggedIn) {
         this._redirect('/dashboard/self');
       } else {
@@ -1183,7 +1178,7 @@
     // User dashboard. We require viewing user to be logged in, else we
     // redirect to login for self dashboard or simple owner search for
     // other user dashboard.
-    return this.$.restAPI.getLoggedIn().then(loggedIn => {
+    return this.restApiService.getLoggedIn().then(loggedIn => {
       if (!loggedIn) {
         if (data.params[0].toLowerCase() === 'self') {
           this._redirectToLogin(data.canonicalPath);
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_html.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router_html.ts
index 91d8b41..1489006 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_html.ts
@@ -16,6 +16,4 @@
  */
 import {html} from '@polymer/polymer/lib/utils/html-tag';
 
-export const htmlTemplate = html`
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
-`;
+export const htmlTemplate = html``;
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
index 927434b..cdec405 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router_test.js
@@ -229,7 +229,7 @@
   });
 
   test('_redirectIfNotLoggedIn while logged in', () => {
-    sinon.stub(element.$.restAPI, 'getLoggedIn')
+    sinon.stub(element.restApiService, 'getLoggedIn')
         .returns(Promise.resolve(true));
     const data = {canonicalPath: ''};
     const redirectStub = sinon.stub(element, '_redirectToLogin');
@@ -239,7 +239,7 @@
   });
 
   test('_redirectIfNotLoggedIn while logged out', () => {
-    sinon.stub(element.$.restAPI, 'getLoggedIn')
+    sinon.stub(element.restApiService, 'getLoggedIn')
         .returns(Promise.resolve(false));
     const redirectStub = sinon.stub(element, '_redirectToLogin');
     const data = {canonicalPath: ''};
@@ -524,7 +524,7 @@
 
     setup(() => {
       projectLookupStub = sinon
-          .stub(element.$.restAPI, 'getFromProjectLookup');
+          .stub(element.restApiService, 'getFromProjectLookup');
       generateUrlStub = sinon.stub(element, '_generateUrl');
     });
 
@@ -794,7 +794,7 @@
       });
 
       test('redirects to dashboard if logged in', () => {
-        sinon.stub(element.$.restAPI, 'getLoggedIn')
+        sinon.stub(element.restApiService, 'getLoggedIn')
             .returns(Promise.resolve(true));
         const data = {
           canonicalPath: '/', path: '/', querystring: '', hash: '',
@@ -807,7 +807,7 @@
       });
 
       test('redirects to open changes if not logged in', () => {
-        sinon.stub(element.$.restAPI, 'getLoggedIn')
+        sinon.stub(element.restApiService, 'getLoggedIn')
             .returns(Promise.resolve(false));
         const data = {
           canonicalPath: '/', path: '/', querystring: '', hash: '',
@@ -905,7 +905,7 @@
       });
 
       test('own dashboard but signed out redirects to login', () => {
-        sinon.stub(element.$.restAPI, 'getLoggedIn')
+        sinon.stub(element.restApiService, 'getLoggedIn')
             .returns(Promise.resolve(false));
         const data = {canonicalPath: '/dashboard/', params: {0: 'seLF'}};
         return element._handleDashboardRoute(data, '').then(() => {
@@ -916,7 +916,7 @@
       });
 
       test('non-self dashboard but signed out does not redirect', () => {
-        sinon.stub(element.$.restAPI, 'getLoggedIn')
+        sinon.stub(element.restApiService, 'getLoggedIn')
             .returns(Promise.resolve(false));
         const data = {canonicalPath: '/dashboard/', params: {0: 'foo'}};
         return element._handleDashboardRoute(data, '').then(() => {
@@ -928,7 +928,7 @@
       });
 
       test('dashboard while signed in sets params', () => {
-        sinon.stub(element.$.restAPI, 'getLoggedIn')
+        sinon.stub(element.restApiService, 'getLoggedIn')
             .returns(Promise.resolve(true));
         const data = {canonicalPath: '/dashboard/', params: {0: 'foo'}};
         return element._handleDashboardRoute(data, '').then(() => {
@@ -1444,7 +1444,7 @@
         setup(() => {
           normalizeRangeStub = sinon.stub(element,
               '_normalizePatchRangeParams');
-          sinon.stub(element.$.restAPI, 'setInProjectLookup');
+          sinon.stub(element.restApiService, 'setInProjectLookup');
         });
 
         test('needs redirect', () => {
@@ -1498,7 +1498,7 @@
         setup(() => {
           normalizeRangeStub = sinon.stub(element,
               '_normalizePatchRangeParams');
-          sinon.stub(element.$.restAPI, 'setInProjectLookup');
+          sinon.stub(element.restApiService, 'setInProjectLookup');
         });
 
         test('needs redirect', () => {
@@ -1551,7 +1551,7 @@
       test('_handleDiffEditRoute', () => {
         const normalizeRangeSpy =
             sinon.spy(element, '_normalizePatchRangeParams');
-        sinon.stub(element.$.restAPI, 'setInProjectLookup');
+        sinon.stub(element.restApiService, 'setInProjectLookup');
         const ctx = {
           params: [
             'foo/bar', // 0 Project
@@ -1580,7 +1580,7 @@
       test('_handleDiffEditRoute with lineNum', () => {
         const normalizeRangeSpy =
             sinon.spy(element, '_normalizePatchRangeParams');
-        sinon.stub(element.$.restAPI, 'setInProjectLookup');
+        sinon.stub(element.restApiService, 'setInProjectLookup');
         const ctx = {
           params: [
             'foo/bar', // 0 Project
@@ -1610,7 +1610,7 @@
       test('_handleChangeEditRoute', () => {
         const normalizeRangeSpy =
             sinon.spy(element, '_normalizePatchRangeParams');
-        sinon.stub(element.$.restAPI, 'setInProjectLookup');
+        sinon.stub(element.restApiService, 'setInProjectLookup');
         const ctx = {
           params: [
             'foo/bar', // 0 Project
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
index d785a2f..dc9a92f 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar.ts
@@ -28,7 +28,6 @@
 } from '../../../mixins/keyboard-shortcut-mixin/keyboard-shortcut-mixin';
 import {customElement, property} from '@polymer/decorators';
 import {ServerInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AutocompleteQuery,
   AutocompleteSuggestion,
@@ -37,6 +36,7 @@
 import {getDocsBaseUrl} from '../../../utils/url-util';
 import {CustomKeyboardEvent} from '../../../types/events';
 import {MergeabilityComputationBehavior} from '../../../constants/constants';
+import {appContext} from '../../../services/app-context';
 
 // Possible static search options for auto complete, without negations.
 const SEARCH_OPERATORS: ReadonlyArray<string> = [
@@ -136,7 +136,6 @@
 
 export interface GrSearchBar {
   $: {
-    restAPI: RestApiService & Element;
     searchInput: GrAutocomplete;
   };
 }
@@ -187,6 +186,8 @@
   @property({type: String})
   docBaseUrl: string | null = null;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this.query = (input: string) => this._getSearchSuggestions(input);
@@ -194,7 +195,7 @@
 
   attached() {
     super.attached();
-    this.$.restAPI.getConfig().then((serverConfig?: ServerInfo) => {
+    this.restApiService.getConfig().then((serverConfig?: ServerInfo) => {
       const mergeability =
         serverConfig &&
         serverConfig.change &&
@@ -209,7 +210,7 @@
         this._addOperator('is:mergeable');
       }
       if (serverConfig) {
-        getDocsBaseUrl(serverConfig, this.$.restAPI).then(baseUrl => {
+        getDocsBaseUrl(serverConfig, this.restApiService).then(baseUrl => {
           this.docBaseUrl = baseUrl;
         });
       }
diff --git a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_html.ts b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_html.ts
index 2ee0058..a0de7f2 100644
--- a/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-search-bar/gr-search-bar_html.ts
@@ -56,5 +56,4 @@
       </a>
     </gr-autocomplete>
   </form>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
index a818c59..042d4fe 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search.ts
@@ -23,24 +23,18 @@
 import {GerritNav} from '../gr-navigation/gr-navigation';
 import {getUserName} from '../../../utils/display-name-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {AccountInfo, ServerInfo} from '../../../types/common';
 import {
   SearchBarHandleSearchDetail,
   SuggestionProvider,
 } from '../gr-search-bar/gr-search-bar';
 import {AutocompleteSuggestion} from '../../shared/gr-autocomplete/gr-autocomplete';
+import {appContext} from '../../../services/app-context';
 
 const MAX_AUTOCOMPLETE_RESULTS = 10;
 const SELF_EXPRESSION = 'self';
 const ME_EXPRESSION = 'me';
 
-export interface GrSmartSearch {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-smart-search')
 export class GrSmartSearch extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -70,10 +64,12 @@
   @property({type: String})
   label = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
-    this.$.restAPI.getConfig().then(cfg => {
+    this.restApiService.getConfig().then(cfg => {
       this._config = cfg;
     });
   }
@@ -97,7 +93,7 @@
     predicate: string,
     expression: string
   ): Promise<AutocompleteSuggestion[]> {
-    return this.$.restAPI
+    return this.restApiService
       .getSuggestedProjects(expression, MAX_AUTOCOMPLETE_RESULTS)
       .then(projects => {
         if (!projects) {
@@ -125,7 +121,7 @@
     if (expression.length === 0) {
       return Promise.resolve([]);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getSuggestedGroups(expression, MAX_AUTOCOMPLETE_RESULTS)
       .then(groups => {
         if (!groups) {
@@ -153,7 +149,7 @@
     if (expression.length === 0) {
       return Promise.resolve([]);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getSuggestedAccounts(expression, MAX_AUTOCOMPLETE_RESULTS)
       .then(accounts => {
         if (!accounts) {
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_html.ts b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_html.ts
index 7088937..c08df15 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_html.ts
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_html.ts
@@ -27,5 +27,4 @@
     group-suggestions="[[_groupSuggestions]]"
     account-suggestions="[[_accountSuggestions]]"
   ></gr-search-bar>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js
index dc7bf0e..d7e6c27 100644
--- a/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js
+++ b/polygerrit-ui/app/elements/core/gr-smart-search/gr-smart-search_test.js
@@ -28,7 +28,7 @@
   });
 
   test('Autocompletes accounts', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedAccounts').callsFake(() =>
+    sinon.stub(element.restApiService, 'getSuggestedAccounts').callsFake(() =>
       Promise.resolve([
         {
           name: 'fred',
@@ -42,7 +42,7 @@
   });
 
   test('Inserts self as option when valid', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedAccounts').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedAccounts').callsFake( () =>
       Promise.resolve([
         {
           name: 'fred',
@@ -62,7 +62,7 @@
   });
 
   test('Inserts me as option when valid', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedAccounts').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedAccounts').callsFake( () =>
       Promise.resolve([
         {
           name: 'fred',
@@ -82,7 +82,7 @@
   });
 
   test('Autocompletes groups', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedGroups').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedGroups').callsFake( () =>
       Promise.resolve({
         Polygerrit: 0,
         gerrit: 0,
@@ -95,7 +95,7 @@
   });
 
   test('Autocompletes projects', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedProjects').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedProjects').callsFake( () =>
       Promise.resolve({Polygerrit: 0}));
     return element._fetchProjects('project', 'pol').then(s => {
       assert.deepEqual(s[0], {text: 'project:Polygerrit'});
@@ -103,7 +103,7 @@
   });
 
   test('Autocomplete doesnt override exact matches to input', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedGroups').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedGroups').callsFake( () =>
       Promise.resolve({
         Polygerrit: 0,
         gerrit: 0,
@@ -118,7 +118,7 @@
   });
 
   test('Autocompletes accounts with no email', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedAccounts').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedAccounts').callsFake( () =>
       Promise.resolve([{name: 'fred'}]));
     return element._fetchAccounts('owner', 'fr').then(s => {
       assert.deepEqual(s[0], {text: 'owner:"fred"', label: 'fred'});
@@ -126,7 +126,7 @@
   });
 
   test('Autocompletes accounts with email', () => {
-    sinon.stub(element.$.restAPI, 'getSuggestedAccounts').callsFake( () =>
+    sinon.stub(element.restApiService, 'getSuggestedAccounts').callsFake( () =>
       Promise.resolve([{email: 'fred@goog.co'}]));
     return element._fetchAccounts('owner', 'fr').then(s => {
       assert.deepEqual(s[0], {text: 'owner:fred@goog.co', label: ''});
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
index d89bb24..50dede4 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api.ts
@@ -39,7 +39,6 @@
 } from '../../../types/common';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {CommentSide, Side} from '../../../constants/constants';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   Comment,
   CommentMap,
@@ -53,6 +52,7 @@
   createCommentThreads,
 } from '../../../utils/comment-util';
 import {PatchSetFile, PatchNumOnly, isPatchSetFile} from '../../../types/types';
+import {appContext} from '../../../services/app-context';
 
 export type CommentIdToCommentThreadMap = {
   [urlEncodedCommentId: string]: CommentThread;
@@ -552,12 +552,6 @@
 export const _testOnly_findCommentById =
   ChangeComments.prototype.findCommentById;
 
-export interface GrCommentApi {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-comment-api')
 export class GrCommentApi extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -569,6 +563,8 @@
   @property({type: Object})
   _changeComments?: ChangeComments;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   created() {
     super.created();
@@ -583,8 +579,8 @@
   getPortedComments(changeNum: NumericChangeId, revision?: RevisionId) {
     if (!revision) revision = CURRENT;
     return Promise.all([
-      this.$.restAPI.getPortedComments(changeNum, revision),
-      this.$.restAPI.getPortedDrafts(changeNum, revision),
+      this.restApiService.getPortedComments(changeNum, revision),
+      this.restApiService.getPortedDrafts(changeNum, revision),
     ]).then(result => {
       return {
         portedComments: result[0],
@@ -600,9 +596,9 @@
    */
   loadAll(changeNum: NumericChangeId) {
     const promises = [];
-    promises.push(this.$.restAPI.getDiffComments(changeNum));
-    promises.push(this.$.restAPI.getDiffRobotComments(changeNum));
-    promises.push(this.$.restAPI.getDiffDrafts(changeNum));
+    promises.push(this.restApiService.getDiffComments(changeNum));
+    promises.push(this.restApiService.getDiffRobotComments(changeNum));
+    promises.push(this.restApiService.getDiffDrafts(changeNum));
 
     return Promise.all(promises).then(([comments, robotComments, drafts]) => {
       this._changeComments = new ChangeComments(
@@ -627,7 +623,7 @@
       return this.loadAll(changeNum);
     }
     const oldChangeComments = this._changeComments;
-    return this.$.restAPI.getDiffDrafts(changeNum).then(drafts => {
+    return this.restApiService.getDiffDrafts(changeNum).then(drafts => {
       this._changeComments = new ChangeComments(
         oldChangeComments.comments,
         (oldChangeComments.robotComments as unknown) as PathToRobotCommentsInfoMap,
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_html.ts b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_html.ts
index 91d8b41..1489006 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_html.ts
@@ -16,6 +16,4 @@
  */
 import {html} from '@polymer/polymer/lib/utils/html-tag';
 
-export const htmlTemplate = html`
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
-`;
+export const htmlTemplate = html``;
diff --git a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
index c2c1c72..cd73430 100644
--- a/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-comment-api/gr-comment-api_test.js
@@ -34,23 +34,24 @@
   test('loads logged-out', () => {
     const changeNum = 1234;
 
-    sinon.stub(element.$.restAPI, 'getLoggedIn')
+    sinon.stub(element.restApiService, 'getLoggedIn')
         .returns(Promise.resolve(false));
-    sinon.stub(element.$.restAPI, 'getDiffComments')
+    sinon.stub(element.restApiService, 'getDiffComments')
         .returns(Promise.resolve({
           'foo.c': [{id: '123', message: 'foo bar', in_reply_to: '321'}],
         }));
-    sinon.stub(element.$.restAPI, 'getDiffRobotComments')
+    sinon.stub(element.restApiService, 'getDiffRobotComments')
         .returns(Promise.resolve({'foo.c': [{id: '321', message: 'done'}]}));
-    sinon.stub(element.$.restAPI, 'getDiffDrafts')
+    sinon.stub(element.restApiService, 'getDiffDrafts')
         .returns(Promise.resolve({}));
 
     return element.loadAll(changeNum).then(() => {
-      assert.isTrue(element.$.restAPI.getDiffComments.calledWithExactly(
+      assert.isTrue(element.restApiService.getDiffComments.calledWithExactly(
           changeNum));
-      assert.isTrue(element.$.restAPI.getDiffRobotComments.calledWithExactly(
-          changeNum));
-      assert.isTrue(element.$.restAPI.getDiffDrafts.calledWithExactly(
+      assert.isTrue(
+          element.restApiService.getDiffRobotComments.calledWithExactly(
+              changeNum));
+      assert.isTrue(element.restApiService.getDiffDrafts.calledWithExactly(
           changeNum));
       assert.isOk(element._changeComments._comments);
       assert.isOk(element._changeComments._robotComments);
@@ -61,23 +62,24 @@
   test('loads logged-in', () => {
     const changeNum = 1234;
 
-    sinon.stub(element.$.restAPI, 'getLoggedIn')
+    sinon.stub(element.restApiService, 'getLoggedIn')
         .returns(Promise.resolve(true));
-    sinon.stub(element.$.restAPI, 'getDiffComments')
+    sinon.stub(element.restApiService, 'getDiffComments')
         .returns(Promise.resolve({
           'foo.c': [{id: '123', message: 'foo bar', in_reply_to: '321'}],
         }));
-    sinon.stub(element.$.restAPI, 'getDiffRobotComments')
+    sinon.stub(element.restApiService, 'getDiffRobotComments')
         .returns(Promise.resolve({'foo.c': [{id: '321', message: 'done'}]}));
-    sinon.stub(element.$.restAPI, 'getDiffDrafts')
+    sinon.stub(element.restApiService, 'getDiffDrafts')
         .returns(Promise.resolve({'foo.c': [{id: '555', message: 'ack'}]}));
 
     return element.loadAll(changeNum).then(() => {
-      assert.isTrue(element.$.restAPI.getDiffComments.calledWithExactly(
+      assert.isTrue(element.restApiService.getDiffComments.calledWithExactly(
           changeNum));
-      assert.isTrue(element.$.restAPI.getDiffRobotComments.calledWithExactly(
-          changeNum));
-      assert.isTrue(element.$.restAPI.getDiffDrafts.calledWithExactly(
+      assert.isTrue(
+          element.restApiService.getDiffRobotComments.calledWithExactly(
+              changeNum));
+      assert.isTrue(element.restApiService.getDiffDrafts.calledWithExactly(
           changeNum));
       assert.isOk(element._changeComments._comments);
       assert.isOk(element._changeComments._robotComments);
@@ -90,11 +92,11 @@
     let robotCommentStub;
     let draftStub;
     setup(() => {
-      commentStub = sinon.stub(element.$.restAPI, 'getDiffComments')
+      commentStub = sinon.stub(element.restApiService, 'getDiffComments')
           .returns(Promise.resolve({}));
-      robotCommentStub = sinon.stub(element.$.restAPI,
+      robotCommentStub = sinon.stub(element.restApiService,
           'getDiffRobotComments').returns(Promise.resolve({}));
-      draftStub = sinon.stub(element.$.restAPI, 'getDiffDrafts')
+      draftStub = sinon.stub(element.restApiService, 'getDiffDrafts')
           .returns(Promise.resolve({}));
     });
 
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
index 987a7d0..060001e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor_test.js
@@ -22,11 +22,11 @@
 import {html} from '@polymer/polymer/lib/utils/html-tag.js';
 import {listenOnce} from '../../../test/test-utils.js';
 import {getMockDiffResponse} from '../../../test/mocks/diff-response.js';
+import {appContext} from '../../../services/app-context.js';
 
 const basicFixture = fixtureFromTemplate(html`
   <gr-diff></gr-diff>
   <gr-diff-cursor></gr-diff-cursor>
-  <gr-rest-api-interface></gr-rest-api-interface>
 `);
 
 const emptyFixture = fixtureFromElement('div');
@@ -40,7 +40,7 @@
     const fixtureElems = basicFixture.instantiate();
     diffElement = fixtureElems[0];
     cursorElement = fixtureElems[1];
-    const restAPI = fixtureElems[2];
+    const restAPI = appContext.restApiService;
 
     // Register the diff with the cursor.
     cursorElement.push('diffs', diffElement);
@@ -539,7 +539,6 @@
       <gr-diff></gr-diff>
       <gr-diff></gr-diff>
       <gr-diff-cursor></gr-diff-cursor>
-      <gr-rest-api-interface></gr-rest-api-interface>
     `);
 
     let diffElements;
@@ -548,7 +547,7 @@
       const fixtureElems = multiDiffFixture.instantiate();
       diffElements = fixtureElems.slice(0, 3);
       cursorElement = fixtureElems[3];
-      const restAPI = fixtureElems[4];
+      const restAPI = appContext.restApiService;
 
       // Register the diff with the cursor.
       cursorElement.push('diffs', ...diffElements);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
index 2223734..19aed90 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host.ts
@@ -60,7 +60,6 @@
   DiffPreferencesInfo,
   IgnoreWhitespaceType,
 } from '../../../types/diff';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {JsApiService} from '../../shared/gr-js-api-interface/gr-js-api-types';
 import {GrDiff, LineOfInterest} from '../gr-diff/gr-diff';
 import {GrSyntaxLayer} from '../gr-syntax-layer/gr-syntax-layer';
@@ -110,7 +109,6 @@
 
 export interface GrDiffHost {
   $: {
-    restAPI: RestApiService & Element;
     jsAPI: JsApiService & Element;
     syntaxLayer: GrSyntaxLayer & Element;
     diff: GrDiff;
@@ -261,6 +259,8 @@
 
   private readonly flags = appContext.flagsService;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   created() {
     super.created();
@@ -508,7 +508,7 @@
     if (!this.changeNum) throw new Error('Missing required "changeNum" prop.');
     if (!this.patchRange) throw new Error('Missing required "patchRange".');
     if (!this.path) throw new Error('Missing required "path" property.');
-    return this.$.restAPI
+    return this.restApiService
       .getBlame(this.changeNum, this.patchRange.patchNum, this.path, true)
       .then(blame => {
         if (!blame || !blame.length) {
@@ -542,7 +542,7 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _canReload() {
@@ -575,7 +575,7 @@
       if (!this.changeNum) throw new Error('Missing required "changeNum".');
       if (!this.patchRange) throw new Error('Missing required "patchRange".');
       if (!this.path) throw new Error('Missing required "path" property.');
-      this.$.restAPI
+      this.restApiService
         .getDiff(
           this.changeNum,
           this.patchRange.basePatchNum,
@@ -697,7 +697,7 @@
   _getImages(diff: DiffInfo) {
     if (!this.changeNum) throw new Error('Missing required "changeNum" prop.');
     if (!this.patchRange) throw new Error('Missing required "patchRange".');
-    return this.$.restAPI.getImagesForDiff(
+    return this.restApiService.getImagesForDiff(
       this.changeNum,
       diff,
       this.patchRange
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
index 9921dd6..48b82ec 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_html.ts
@@ -50,5 +50,4 @@
     diff="[[diff]]"
   ></gr-syntax-layer>
   <gr-js-api-interface id="jsAPI"></gr-js-api-interface>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
index 402cb52..fe6c7b9 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-host/gr-diff-host_test.js
@@ -133,11 +133,11 @@
           resolve => {
             notifySyntaxProcessed = resolve;
           }));
-      sinon.stub(element.$.restAPI, 'getDiff').returns(
+      sinon.stub(element.restApiService, 'getDiff').returns(
           Promise.resolve({content: []}));
       element.patchRange = {};
       element.change = createChange();
-      element.$.restAPI.getDiffPreferences().then(prefs => {
+      element.restApiService.getDiffPreferences().then(prefs => {
         element.prefs = prefs;
         return element.reload(true);
       });
@@ -154,7 +154,7 @@
     });
 
     test('ends total timer w/ no syntax layer processing', async () => {
-      sinon.stub(element.$.restAPI, 'getDiff').returns(
+      sinon.stub(element.restApiService, 'getDiff').returns(
           Promise.resolve({content: []}));
       element.patchRange = {};
       element.change = createChange();
@@ -176,12 +176,12 @@
           resolve => {
             notifySyntaxProcessed = resolve;
           }));
-      sinon.stub(element.$.restAPI, 'getDiff').returns(
+      sinon.stub(element.restApiService, 'getDiff').returns(
           Promise.resolve({content: []}));
       element.patchRange = {};
       element.change = createChange();
       let reloadComplete = false;
-      element.$.restAPI.getDiffPreferences()
+      element.restApiService.getDiffPreferences()
           .then(prefs => {
             element.prefs = prefs;
             return element.reload();
@@ -230,7 +230,7 @@
     test('reload() loads files weblinks', () => {
       const weblinksStub = sinon.stub(GerritNav, '_generateWeblinks')
           .returns({name: 'stubb', url: '#s'});
-      sinon.stub(element.$.restAPI, 'getDiff').returns(Promise.resolve({
+      sinon.stub(element.restApiService, 'getDiff').returns(Promise.resolve({
         content: [],
       }));
       element.projectName = 'test-project';
@@ -263,7 +263,7 @@
     });
 
     test('prefetch getDiff', done => {
-      const diffRestApiStub = sinon.stub(element.$.restAPI, 'getDiff')
+      const diffRestApiStub = sinon.stub(element.restApiService, 'getDiff')
           .returns(Promise.resolve({content: []}));
       element.changeNum = 123;
       element.patchRange = {basePatchNum: 1, patchNum: 2};
@@ -288,7 +288,7 @@
     test('reload resolves on error', () => {
       const onErrStub = sinon.stub(element, '_handleGetDiffError');
       const error = new Response(null, {ok: false, status: 500});
-      sinon.stub(element.$.restAPI, 'getDiff').callsFake(
+      sinon.stub(element.restApiService, 'getDiff').callsFake(
           (changeNum, basePatchNum, patchNum, path, whitespace, onErr) => {
             onErr(error);
           });
@@ -347,7 +347,7 @@
           'wsAAAAAAAAAAAAA/////w==',
           type: 'image/bmp',
         };
-        sinon.stub(element.$.restAPI,
+        sinon.stub(element.restApiService,
             'getB64FileContents')
             .callsFake(
                 (changeId, patchNum, path, opt_parentIndex) => Promise.resolve(
@@ -380,7 +380,7 @@
           content: [{skip: 66}],
           binary: true,
         };
-        sinon.stub(element.$.restAPI, 'getDiff')
+        sinon.stub(element.restApiService, 'getDiff')
             .returns(Promise.resolve(mockDiff));
 
         const rendered = () => {
@@ -438,7 +438,7 @@
 
         element.addEventListener('render', rendered);
 
-        element.$.restAPI.getDiffPreferences().then(prefs => {
+        element.restApiService.getDiffPreferences().then(prefs => {
           element.prefs = prefs;
           element.reload();
         });
@@ -461,7 +461,7 @@
           content: [{skip: 66}],
           binary: true,
         };
-        sinon.stub(element.$.restAPI, 'getDiff')
+        sinon.stub(element.restApiService, 'getDiff')
             .returns(Promise.resolve(mockDiff));
 
         const rendered = () => {
@@ -521,7 +521,7 @@
 
         element.addEventListener('render', rendered);
 
-        element.$.restAPI.getDiffPreferences().then(prefs => {
+        element.restApiService.getDiffPreferences().then(prefs => {
           element.prefs = prefs;
           element.reload();
         });
@@ -543,7 +543,7 @@
           content: [{skip: 66}],
           binary: true,
         };
-        sinon.stub(element.$.restAPI, 'getDiff')
+        sinon.stub(element.restApiService, 'getDiff')
             .returns(Promise.resolve(mockDiff));
 
         element.addEventListener('render', () => {
@@ -562,7 +562,7 @@
           done();
         });
 
-        element.$.restAPI.getDiffPreferences().then(prefs => {
+        element.restApiService.getDiffPreferences().then(prefs => {
           element.prefs = prefs;
           element.reload();
         });
@@ -584,7 +584,7 @@
           content: [{skip: 66}],
           binary: true,
         };
-        sinon.stub(element.$.restAPI, 'getDiff')
+        sinon.stub(element.restApiService, 'getDiff')
             .returns(Promise.resolve(mockDiff));
 
         element.addEventListener('render', () => {
@@ -603,7 +603,7 @@
           done();
         });
 
-        element.$.restAPI.getDiffPreferences().then(prefs => {
+        element.restApiService.getDiffPreferences().then(prefs => {
           element.prefs = prefs;
           element.reload();
         });
@@ -627,7 +627,7 @@
         };
         mockFile1.type = 'image/jpeg-evil';
 
-        sinon.stub(element.$.restAPI, 'getDiff')
+        sinon.stub(element.restApiService, 'getDiff')
             .returns(Promise.resolve(mockDiff));
 
         element.addEventListener('render', () => {
@@ -641,7 +641,7 @@
           done();
         });
 
-        element.$.restAPI.getDiffPreferences().then(prefs => {
+        element.restApiService.getDiffPreferences().then(prefs => {
           element.prefs = prefs;
           element.reload();
         });
@@ -702,7 +702,7 @@
       const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
       const showAlertStub = sinon.stub();
       element.addEventListener('show-alert', showAlertStub);
-      const getBlameStub = sinon.stub(element.$.restAPI, 'getBlame')
+      const getBlameStub = sinon.stub(element.restApiService, 'getBlame')
           .returns(Promise.resolve(mockBlame));
       element.changeNum = 42;
       element.patchRange = {patchNum: 5, basePatchNum: 4};
@@ -720,7 +720,7 @@
       const mockBlame = [];
       const showAlertStub = sinon.stub();
       element.addEventListener('show-alert', showAlertStub);
-      sinon.stub(element.$.restAPI, 'getBlame')
+      sinon.stub(element.restApiService, 'getBlame')
           .returns(Promise.resolve(mockBlame));
       element.changeNum = 42;
       element.patchRange = {patchNum: 5, basePatchNum: 4};
@@ -1270,7 +1270,7 @@
     test('starts syntax layer processing on render event', async () => {
       sinon.stub(element.$.syntaxLayer, 'process')
           .returns(Promise.resolve());
-      sinon.stub(element.$.restAPI, 'getDiff').returns(
+      sinon.stub(element.restApiService, 'getDiff').returns(
           Promise.resolve({content: []}));
       element.reload();
       await flush();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
index e0333cc..c30feeb 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
@@ -20,7 +20,6 @@
 import '../../shared/gr-button/gr-button';
 import '../../shared/gr-rest-api-interface/gr-rest-api-interface';
 import {DiffViewMode} from '../../../constants/constants';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners';
 import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin';
 import {PolymerElement} from '@polymer/polymer/polymer-element';
@@ -28,12 +27,7 @@
 import {customElement, property} from '@polymer/decorators';
 import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announcer';
 import {FixIronA11yAnnouncer} from '../../../types/types';
-
-export interface GrDiffModeSelector {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 @customElement('gr-diff-mode-selector')
 export class GrDiffModeSelector extends GestureEventListeners(
@@ -53,6 +47,8 @@
   @property({type: Boolean})
   saveOnChange = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   attached() {
     ((IronA11yAnnouncer as unknown) as FixIronA11yAnnouncer).requestAvailability();
   }
@@ -62,7 +58,7 @@
    */
   setMode(newMode: DiffViewMode) {
     if (this.saveOnChange && this.mode && this.mode !== newMode) {
-      this.$.restAPI.savePreferences({diff_view: newMode});
+      this.restApiService.savePreferences({diff_view: newMode});
     }
     this.mode = newMode;
     let annoucement;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
index a5bf269..9943b58 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_html.ts
@@ -52,5 +52,4 @@
   >
     <iron-icon icon="gr-icons:unified"></iron-icon>
   </gr-button>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.js b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.js
index 07a1d16..049f01d 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector_test.js
@@ -40,7 +40,7 @@
   });
 
   test('setMode', () => {
-    const saveStub = sinon.stub(element.$.restAPI, 'savePreferences');
+    const saveStub = sinon.stub(element.restApiService, 'savePreferences');
 
     // Setting the mode initially does not save prefs.
     element.saveOnChange = true;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index 984b05a..82c48fa 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -59,7 +59,6 @@
 } from '../../../utils/path-list-util';
 import {changeBaseURL, changeIsOpen} from '../../../utils/change-util';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrDiffHost} from '../gr-diff-host/gr-diff-host';
 import {
   DropdownItem,
@@ -116,7 +115,6 @@
 
 export interface GrDiffView {
   $: {
-    restAPI: RestApiService & Element;
     commentAPI: GrCommentApi;
     cursor: GrDiffCursor;
     diffHost: GrDiffHost;
@@ -319,6 +317,8 @@
 
   flagsService = appContext.flagsService;
 
+  private readonly restApiService = appContext.restApiService;
+
   _throttledToggleFileReviewed?: EventListener;
 
   _onRenderHandler?: EventListener;
@@ -354,19 +354,19 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   @observe('_change.project')
   _getProjectConfig(project?: RepoName) {
     if (!project) return;
-    return this.$.restAPI.getProjectConfig(project).then(config => {
+    return this.restApiService.getProjectConfig(project).then(config => {
       this._projectConfig = config;
     });
   }
 
   _getChangeDetail(changeNum: NumericChangeId) {
-    return this.$.restAPI.getDiffChangeDetail(changeNum).then(change => {
+    return this.restApiService.getDiffChangeDetail(changeNum).then(change => {
       if (!change) throw new Error('Missing "change" in API response.');
       this._change = change;
       return change;
@@ -375,7 +375,7 @@
 
   _getChangeEdit() {
     if (!this._changeNum) throw new Error('Missing this._changeNum');
-    return this.$.restAPI.getChangeEdit(this._changeNum);
+    return this.restApiService.getChangeEdit(this._changeNum);
   }
 
   _getSortedFileList(files?: Files) {
@@ -413,7 +413,7 @@
     }
 
     const patchRange = patchRangeRecord.base;
-    return this.$.restAPI
+    return this.restApiService
       .getChangeFiles(changeNum, patchRange)
       .then(changeFiles => {
         if (!changeFiles) return;
@@ -428,13 +428,13 @@
   }
 
   _getDiffPreferences() {
-    return this.$.restAPI.getDiffPreferences().then(prefs => {
+    return this.restApiService.getDiffPreferences().then(prefs => {
       this._prefs = prefs;
     });
   }
 
   _getPreferences() {
-    return this.$.restAPI.getPreferences();
+    return this.restApiService.getPreferences();
   }
 
   _getWindowWidth() {
@@ -461,7 +461,7 @@
     if (!this._changeNum) return Promise.resolve(undefined);
     if (!this._patchRange?.patchNum) return Promise.resolve(undefined);
     if (!this._path) return Promise.resolve(undefined);
-    return this.$.restAPI.saveFileReviewed(
+    return this.restApiService.saveFileReviewed(
       this._changeNum,
       this._patchRange?.patchNum,
       this._path,
@@ -843,10 +843,12 @@
     patchNum?: PatchSetNum
   ): Promise<Set<string>> {
     if (!changeNum || !patchNum) return Promise.resolve(new Set<string>());
-    return this.$.restAPI.getReviewedFiles(changeNum, patchNum).then(files => {
-      this._reviewedFiles = new Set(files);
-      return this._reviewedFiles;
-    });
+    return this.restApiService
+      .getReviewedFiles(changeNum, patchNum)
+      .then(files => {
+        this._reviewedFiles = new Set(files);
+        return this._reviewedFiles;
+      });
   }
 
   _getReviewedStatus(
@@ -1031,7 +1033,7 @@
     this._focusLineNum = undefined;
 
     if (value.changeNum && value.project) {
-      this.$.restAPI.setInProjectLookup(value.changeNum, value.project);
+      this.restApiService.setInProjectLookup(value.changeNum, value.project);
     }
 
     this._changeNum = value.changeNum;
@@ -1141,7 +1143,7 @@
   _changeViewStateChanged(changeViewState: Partial<ChangeViewState>) {
     if (changeViewState.diffMode === null) {
       // If screen size is small, always default to unified view.
-      this.$.restAPI.getPreferences().then(prefs => {
+      this.restApiService.getPreferences().then(prefs => {
         if (prefs) {
           this.set('changeViewState.diffMode', prefs.default_diff_view);
         }
@@ -1583,7 +1585,7 @@
   _getDiffDrafts() {
     if (!this._changeNum) throw new Error('Missing this._changeNum');
 
-    return this.$.restAPI.getDiffDrafts(this._changeNum);
+    return this.restApiService.getDiffDrafts(this._changeNum);
   }
 
   _computeCommentSkips(
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
index be2dce5..9ffb7df 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
@@ -425,7 +425,6 @@
     on-reload-diff-preference="_handleReloadingDiffPreference"
   >
   </gr-diff-preferences-dialog>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
   <gr-diff-cursor
     id="cursor"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
index 8e1e5c1..cee6567 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_test.js
@@ -334,8 +334,8 @@
       sinon.stub(element, '_loadBlame');
       sinon.stub(element.$.diffHost, 'reload').returns(Promise.resolve());
       sinon.spy(element, '_paramsChanged');
-      element.$.restAPI.getDiffChangeDetail.restore();
-      sinon.stub(element.$.restAPI, 'getDiffChangeDetail')
+      element.restApiService.getDiffChangeDetail.restore();
+      sinon.stub(element.restApiService, 'getDiffChangeDetail')
           .returns(
               Promise.resolve({
                 ...createChange(),
@@ -1233,7 +1233,7 @@
       const prefsPromise = new Promise(resolve => {
         resolvePrefs = resolve;
       });
-      sinon.stub(element.$.restAPI, 'getPreferences')
+      sinon.stub(element.restApiService, 'getPreferences')
           .callsFake(() => prefsPromise);
 
       // Attach a new gr-diff-view so we can intercept the preferences fetch.
@@ -1622,9 +1622,9 @@
 
     test('_getReviewedStatus', () => {
       const promises = [];
-      element.$.restAPI.getReviewedFiles.restore();
+      element.restApiService.getReviewedFiles.restore();
 
-      sinon.stub(element.$.restAPI, 'getReviewedFiles')
+      sinon.stub(element.restApiService, 'getReviewedFiles')
           .returns(Promise.resolve(['path']));
 
       promises.push(element._getReviewedStatus(true, null, null, 'path')
@@ -1689,7 +1689,7 @@
 
     test('_paramsChanged sets in projectLookup', () => {
       sinon.stub(element, '_initLineOfInterestAndCursor');
-      const setStub = sinon.stub(element.$.restAPI, 'setInProjectLookup');
+      const setStub = sinon.stub(element.restApiService, 'setInProjectLookup');
       element._paramsChanged({
         view: GerritNav.View.DIFF,
         changeNum: 101,
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
index 79c4359..c04e61b 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search.ts
@@ -28,15 +28,10 @@
 } from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {getBaseUrl} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {DocResult} from '../../../types/common';
 import {fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
-export interface GrDocumentationSearch {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-documentation-search')
 export class GrDocumentationSearch extends ListViewMixin(
   GestureEventListeners(LegacyElementMixin(PolymerElement))
@@ -60,6 +55,8 @@
   @property({type: String})
   _filter = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -75,14 +72,16 @@
 
   _getDocumentationSearches(filter: string) {
     this._documentationSearches = [];
-    return this.$.restAPI.getDocumentationSearches(filter).then(searches => {
-      // Late response.
-      if (filter !== this._filter || !searches) {
-        return;
-      }
-      this._documentationSearches = searches;
-      this._loading = false;
-    });
+    return this.restApiService
+      .getDocumentationSearches(filter)
+      .then(searches => {
+        // Late response.
+        if (filter !== this._filter || !searches) {
+          return;
+        }
+        this._documentationSearches = searches;
+        this._loading = false;
+      });
   }
 
   _computeSearchUrl(url?: string) {
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_html.ts b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_html.ts
index 9f5aae3..dd1faeb 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_html.ts
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_html.ts
@@ -54,5 +54,4 @@
       </tbody>
     </table>
   </gr-list-view>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.js b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.js
index ce80f2f..79d40b5 100644
--- a/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.js
+++ b/polygerrit-ui/app/elements/documentation/gr-documentation-search/gr-documentation-search_test.js
@@ -72,14 +72,14 @@
 
     test('_paramsChanged', done => {
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'getDocumentationSearches')
           .callsFake(() => Promise.resolve(documentationSearches));
       const value = {
         filter: 'test',
       };
       element._paramsChanged(value).then(() => {
-        assert.isTrue(element.$.restAPI.getDocumentationSearches.lastCall
+        assert.isTrue(element.restApiService.getDocumentationSearches.lastCall
             .calledWithExactly('test'));
         done();
       });
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
index cf011bb..f05080e 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls.ts
@@ -33,15 +33,14 @@
 import {ChangeInfo, PatchSetNum} from '../../../types/common';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {GrDialog} from '../../shared/gr-dialog/gr-dialog';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AutocompleteQuery,
   AutocompleteSuggestion,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
+import {appContext} from '../../../services/app-context';
 
 export interface GrEditControls {
   $: {
-    restAPI: RestApiService & Element;
     overlay: GrOverlay;
     openDialog: GrDialog;
     deleteDialog: GrDialog;
@@ -79,6 +78,8 @@
   @property({type: Object})
   _query: AutocompleteQuery;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = (input: string) => this._queryFiles(input);
@@ -221,7 +222,7 @@
       this._closeDialog(this.$.openDialog, true);
       return;
     }
-    return this.$.restAPI
+    return this.restApiService
       .saveFileUploadChangeEdit(this.change._number, path, fileData)
       .then(res => {
         if (!res || !res.ok) {
@@ -236,7 +237,7 @@
     // Get the dialog before the api call as the event will change during bubbling
     // which will make Polymer.dom(e).path an empty array in polymer 2
     const dialog = this._getDialogFromEvent(e);
-    this.$.restAPI
+    this.restApiService
       .deleteFileInChangeEdit(this.change._number, this._path)
       .then(res => {
         if (!res || !res.ok) {
@@ -249,7 +250,7 @@
 
   _handleRestoreConfirm(e: Event) {
     const dialog = this._getDialogFromEvent(e);
-    this.$.restAPI
+    this.restApiService
       .restoreFileInChangeEdit(this.change._number, this._path)
       .then(res => {
         if (!res || !res.ok) {
@@ -262,7 +263,7 @@
 
   _handleRenameConfirm(e: Event) {
     const dialog = this._getDialogFromEvent(e);
-    return this.$.restAPI
+    return this.restApiService
       .renameFileInChangeEdit(this.change._number, this._path, this._newPath)
       .then(res => {
         if (!res || !res.ok) {
@@ -274,7 +275,7 @@
   }
 
   _queryFiles(input: string): Promise<AutocompleteSuggestion[]> {
-    return this.$.restAPI
+    return this.restApiService
       .queryChangeFiles(this.change._number, this.patchNum, input)
       .then(res => {
         if (!res) throw new Error('Failed to retrieve files. Reponse not set.');
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_html.ts b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_html.ts
index b67f6cd..eac796e 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_html.ts
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_html.ts
@@ -179,5 +179,4 @@
       </div>
     </gr-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.js b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.js
index 464c13f..e366233 100644
--- a/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.js
+++ b/polygerrit-ui/app/elements/edit/gr-edit-controls/gr-edit-controls_test.js
@@ -35,7 +35,7 @@
     showDialogSpy = sinon.spy(element, '_showDialog');
     closeDialogSpy = sinon.spy(element, '_closeDialog');
     sinon.stub(element, '_hideAllDialogs');
-    queryStub = sinon.stub(element.$.restAPI, 'queryChangeFiles')
+    queryStub = sinon.stub(element.restApiService, 'queryChangeFiles')
         .returns(Promise.resolve([]));
     flush();
   });
@@ -114,7 +114,7 @@
 
     setup(() => {
       navStub = sinon.stub(GerritNav, 'navigateToChange');
-      deleteStub = sinon.stub(element.$.restAPI, 'deleteFileInChangeEdit');
+      deleteStub = sinon.stub(element.restApiService, 'deleteFileInChangeEdit');
       deleteAutocomplete =
           element.$.deleteDialog.querySelector('gr-autocomplete');
     });
@@ -198,7 +198,7 @@
 
     setup(() => {
       navStub = sinon.stub(GerritNav, 'navigateToChange');
-      renameStub = sinon.stub(element.$.restAPI, 'renameFileInChangeEdit');
+      renameStub = sinon.stub(element.restApiService, 'renameFileInChangeEdit');
       renameAutocomplete =
           element.$.renameDialog.querySelector('gr-autocomplete');
     });
@@ -291,7 +291,8 @@
 
     setup(() => {
       navStub = sinon.stub(GerritNav, 'navigateToChange');
-      restoreStub = sinon.stub(element.$.restAPI, 'restoreFileInChangeEdit');
+      restoreStub = sinon.stub(element.restApiService,
+          'restoreFileInChangeEdit');
     });
 
     test('restore hidden by default', () => {
@@ -355,7 +356,7 @@
 
     setup(() => {
       navStub = sinon.stub(GerritNav, 'navigateToChange');
-      fileStub = sinon.stub(element.$.restAPI, 'saveFileUploadChangeEdit');
+      fileStub = sinon.stub(element.restApiService, 'saveFileUploadChangeEdit');
     });
 
     test('_handleUploadConfirm', () => {
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index 60944d0..83840a5f 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -34,10 +34,7 @@
 import {SPECIAL_PATCH_SET_NUM} from '../../../utils/patch-set-util';
 import {computeTruncatedPath} from '../../../utils/path-list-util';
 import {customElement, property} from '@polymer/decorators';
-import {
-  RestApiService,
-  ErrorCallback,
-} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {ErrorCallback} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   ChangeInfo,
   PatchSetNum,
@@ -48,6 +45,7 @@
 import {GrStorage} from '../../shared/gr-storage/gr-storage';
 import {HttpMethod, NotifyType} from '../../../constants/constants';
 import {fireAlert, fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const RESTORED_MESSAGE = 'Content restored from a previous edit.';
 const SAVING_MESSAGE = 'Saving changes...';
@@ -60,7 +58,6 @@
 
 export interface GrEditorView {
   $: {
-    restAPI: RestApiService & Element;
     storage: GrStorage;
   };
 }
@@ -126,6 +123,8 @@
   @property({type: Number})
   _lineNum?: number;
 
+  private readonly restApiService = appContext.restApiService;
+
   get keyBindings() {
     return {
       'ctrl+s meta+s': '_handleSaveShortcut',
@@ -153,11 +152,11 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _getEditPrefs() {
-    return this.$.restAPI.getEditPreferences();
+    return this.restApiService.getEditPreferences();
   }
 
   _paramsChanged(value: GenerateUrlEditViewParameters) {
@@ -190,7 +189,7 @@
   }
 
   _getChangeDetail(changeNum: NumericChangeId) {
-    return this.$.restAPI.getDiffChangeDetail(changeNum).then(change => {
+    return this.restApiService.getDiffChangeDetail(changeNum).then(change => {
       this._change = change;
     });
   }
@@ -204,7 +203,7 @@
     if (path === this._path) {
       return Promise.resolve();
     }
-    return this.$.restAPI
+    return this.restApiService
       .renameFileInChangeEdit(this._changeNum, this._path, path)
       .then(res => {
         if (!res || !res.ok) {
@@ -241,7 +240,7 @@
       this.storageKey
     );
 
-    return this.$.restAPI
+    return this.restApiService
       .getFileContent(changeNum, path, patchNum)
       .then(res => {
         const content = (res && (res as Base64FileContent).content) || '';
@@ -278,7 +277,7 @@
     this.$.storage.eraseEditableContentItem(this.storageKey);
     if (!this._newContent)
       return Promise.reject(new Error('new content undefined'));
-    return this.$.restAPI
+    return this.restApiService
       .saveChangeEdit(this._changeNum, this._path, this._newContent)
       .then(res => {
         this._saving = false;
@@ -336,7 +335,7 @@
 
       this._showAlert(PUBLISHING_EDIT_MSG);
 
-      this.$.restAPI
+      this.restApiService
         .executeChangeAction(
           changeNum,
           HttpMethod.POST,
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_html.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_html.ts
index 1e05232..0b03856 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_html.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_html.ts
@@ -133,6 +133,5 @@
       ></gr-default-editor>
     </gr-endpoint-decorator>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
 `;
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
index b04277e..419e63e 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view_test.js
@@ -43,9 +43,10 @@
     });
 
     element = basicFixture.instantiate();
-    savePathStub = sinon.stub(element.$.restAPI, 'renameFileInChangeEdit');
-    saveFileStub = sinon.stub(element.$.restAPI, 'saveChangeEdit');
-    changeDetailStub = sinon.stub(element.$.restAPI, 'getDiffChangeDetail');
+    savePathStub = sinon.stub(element.restApiService, 'renameFileInChangeEdit');
+    saveFileStub = sinon.stub(element.restApiService, 'saveChangeEdit');
+    changeDetailStub = sinon.stub(element.restApiService,
+        'getDiffChangeDetail');
     navigateStub = sinon.stub(element, '_viewEditInChangeView');
   });
 
@@ -199,7 +200,7 @@
       const saveSpy = sinon.spy(element, '_saveEdit');
       const alertStub = sinon.stub(element, '_showAlert');
       const changeActionsStub =
-        sinon.stub(element.$.restAPI, 'executeChangeAction');
+        sinon.stub(element.restApiService, 'executeChangeAction');
       saveFileStub.returns(Promise.resolve({ok: true}));
       element._newContent = newText;
       flush();
@@ -255,7 +256,7 @@
     });
 
     test('res.ok', () => {
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({
             ok: true,
             type: 'text/javascript',
@@ -271,7 +272,7 @@
     });
 
     test('!res.ok', () => {
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({}));
 
       // Ensure no data is set with a bad response.
@@ -283,7 +284,7 @@
     });
 
     test('content is undefined', () => {
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({
             ok: true,
             type: 'text/javascript',
@@ -297,7 +298,7 @@
     });
 
     test('content and type is undefined', () => {
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({
             ok: true,
           }));
@@ -382,7 +383,7 @@
     test('local edit exists', () => {
       sinon.stub(element.$.storage, 'getEditableContentItem')
           .returns({message: 'pending edit'});
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({
             ok: true,
             type: 'text/javascript',
@@ -405,7 +406,7 @@
     test('local edit exists, is same as remote edit', () => {
       sinon.stub(element.$.storage, 'getEditableContentItem')
           .returns({message: 'pending edit'});
-      sinon.stub(element.$.restAPI, 'getFileContent')
+      sinon.stub(element.restApiService, 'getFileContent')
           .returns(Promise.resolve({
             ok: true,
             type: 'text/javascript',
diff --git a/polygerrit-ui/app/elements/gr-app-element.ts b/polygerrit-ui/app/elements/gr-app-element.ts
index 6df7cad..4cc0389 100644
--- a/polygerrit-ui/app/elements/gr-app-element.ts
+++ b/polygerrit-ui/app/elements/gr-app-element.ts
@@ -53,7 +53,6 @@
 import {appContext} from '../services/app-context';
 import {flush} from '@polymer/polymer/lib/utils/flush';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../services/services/gr-rest-api/gr-rest-api';
 import {GrRouter} from './core/gr-router/gr-router';
 import {
   AccountDetailInfo,
@@ -89,7 +88,6 @@
 
 export interface GrAppElement {
   $: {
-    restAPI: RestApiService & Element;
     router: GrRouter;
     errorManager: GrErrorManager;
     errorView: HTMLDivElement;
@@ -195,6 +193,8 @@
 
   private reporting = appContext.reportingService;
 
+  private restApiService = appContext.restApiService;
+
   keyboardShortcuts() {
     return {
       [Shortcut.OPEN_SHORTCUT_HELP_DIALOG]: '_showKeyboardShortcuts',
@@ -238,19 +238,19 @@
     this.reporting.appStarted();
     this.$.router.start();
 
-    this.$.restAPI.getAccount().then(account => {
+    this.restApiService.getAccount().then(account => {
       this._account = account;
       const role = account ? 'user' : 'guest';
       this.reporting.reportLifeCycle(`Started as ${role}`);
     });
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this._serverConfig = config;
 
       if (config && config.gerrit && config.gerrit.report_bug_url) {
         this._feedbackUrl = config.gerrit.report_bug_url;
       }
     });
-    this.$.restAPI.getVersion().then(version => {
+    this.restApiService.getVersion().then(version => {
       this._version = version;
       this._logWelcome();
     });
@@ -440,9 +440,9 @@
     if (!account) return;
 
     // Preferences are cached when a user is logged in; warm them.
-    this.$.restAPI.getPreferences();
-    this.$.restAPI.getDiffPreferences();
-    this.$.restAPI.getEditPreferences();
+    this.restApiService.getPreferences();
+    this.restApiService.getDiffPreferences();
+    this.restApiService.getEditPreferences();
     this.$.errorManager.knownAccountId =
       (this._account && this._account._account_id) || null;
   }
diff --git a/polygerrit-ui/app/elements/gr-app-element_html.ts b/polygerrit-ui/app/elements/gr-app-element_html.ts
index 88cd7f5..b978ed8 100644
--- a/polygerrit-ui/app/elements/gr-app-element_html.ts
+++ b/polygerrit-ui/app/elements/gr-app-element_html.ts
@@ -218,7 +218,6 @@
     id="errorManager"
     login-url="[[_loginUrl]]"
   ></gr-error-manager>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-router id="router"></gr-router>
   <gr-plugin-host id="plugins" config="[[_serverConfig]]"> </gr-plugin-host>
   <gr-lib-loader id="libLoader"></gr-lib-loader>
diff --git a/polygerrit-ui/app/elements/gr-app_test.js b/polygerrit-ui/app/elements/gr-app_test.js
index 4c5e965..013d9387 100644
--- a/polygerrit-ui/app/elements/gr-app_test.js
+++ b/polygerrit-ui/app/elements/gr-app_test.js
@@ -70,7 +70,7 @@
   });
 
   test('passes config to gr-plugin-host', () => {
-    const config = appElement().$.restAPI.getConfig;
+    const config = appElement().restApiService.getConfig;
     return config.lastCall.returnValue.then(config => {
       assert.deepEqual(appElement().$.plugins.config, config);
     });
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
index 9c781c8..a7b6a6c 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
@@ -26,14 +26,9 @@
 import {htmlTemplate} from './gr-account-info_html';
 import {customElement, property, observe} from '@polymer/decorators';
 import {AccountInfo, ServerInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {EditableAccountField} from '../../../constants/constants';
+import {appContext} from '../../../services/app-context';
 
-export interface GrAccountInfo {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-account-info')
 export class GrAccountInfo extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -101,19 +96,21 @@
   @property({type: String})
   _avatarChangeUrl = '';
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
     const promises = [];
 
     this._loading = true;
 
     promises.push(
-      this.$.restAPI.getConfig().then(config => {
+      this.restApiService.getConfig().then(config => {
         this._serverConfig = config;
       })
     );
 
     promises.push(
-      this.$.restAPI.getAccount().then(account => {
+      this.restApiService.getAccount().then(account => {
         if (!account) return;
         this._hasNameChange = false;
         this._hasUsernameChange = false;
@@ -128,7 +125,7 @@
     );
 
     promises.push(
-      this.$.restAPI.getAvatarChangeUrl().then(url => {
+      this.restApiService.getAvatarChangeUrl().then(url => {
         this._avatarChangeUrl = url || '';
       })
     );
@@ -168,7 +165,7 @@
     // Note that we are intentionally not acting on this._account.name being the
     // empty string (which is falsy).
     return this._hasNameChange && this.nameMutable && this._account?.name
-      ? this.$.restAPI.setAccountName(this._account.name)
+      ? this.restApiService.setAccountName(this._account.name)
       : Promise.resolve();
   }
 
@@ -176,20 +173,20 @@
     // Note that we are intentionally not acting on this._username being the
     // empty string (which is falsy).
     return this._hasUsernameChange && this.usernameMutable && this._username
-      ? this.$.restAPI.setAccountUsername(this._username)
+      ? this.restApiService.setAccountUsername(this._username)
       : Promise.resolve();
   }
 
   _maybeSetDisplayName() {
     return this._hasDisplayNameChange &&
       this._account?.display_name !== undefined
-      ? this.$.restAPI.setAccountDisplayName(this._account.display_name)
+      ? this.restApiService.setAccountDisplayName(this._account.display_name)
       : Promise.resolve();
   }
 
   _maybeSetStatus() {
     return this._hasStatusChange && this._account?.status !== undefined
-      ? this.$.restAPI.setAccountStatus(this._account.status)
+      ? this.restApiService.setAccountStatus(this._account.status)
       : Promise.resolve();
   }
 
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
index d69a279..f207876 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_html.ts
@@ -128,5 +128,4 @@
       </span>
     </section>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js
index d359ad2..a92c023 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info_test.js
@@ -133,11 +133,12 @@
       element.set('_serverConfig',
           {auth: {editable_account_fields: ['FULL_NAME', 'USER_NAME']}});
 
-      nameStub = sinon.stub(element.$.restAPI, 'setAccountName').callsFake(
+      nameStub = sinon.stub(element.restApiService, 'setAccountName').callsFake(
           name => Promise.resolve());
-      usernameStub = sinon.stub(element.$.restAPI, 'setAccountUsername')
+      usernameStub = sinon.stub(element.restApiService, 'setAccountUsername')
           .callsFake(username => Promise.resolve());
-      statusStub = sinon.stub(element.$.restAPI, 'setAccountStatus').callsFake(
+      statusStub = sinon.stub(element.restApiService,
+          'setAccountStatus').callsFake(
           status => Promise.resolve());
     });
 
@@ -217,11 +218,12 @@
       element.set('_serverConfig',
           {auth: {editable_account_fields: ['FULL_NAME']}});
 
-      nameStub = sinon.stub(element.$.restAPI, 'setAccountName').callsFake(
+      nameStub = sinon.stub(element.restApiService, 'setAccountName').callsFake(
           name => Promise.resolve());
-      statusStub = sinon.stub(element.$.restAPI, 'setAccountStatus').callsFake(
+      statusStub = sinon.stub(element.restApiService,
+          'setAccountStatus').callsFake(
           status => Promise.resolve());
-      sinon.stub(element.$.restAPI, 'setAccountUsername').callsFake(
+      sinon.stub(element.restApiService, 'setAccountUsername').callsFake(
           username => Promise.resolve());
     });
 
@@ -261,7 +263,8 @@
       element.set('_serverConfig',
           {auth: {editable_account_fields: []}});
 
-      statusStub = sinon.stub(element.$.restAPI, 'setAccountStatus').callsFake(
+      statusStub = sinon.stub(element.restApiService,
+          'setAccountStatus').callsFake(
           status => Promise.resolve());
     });
 
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
index 5523be1..243a40d 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list.ts
@@ -24,14 +24,9 @@
 import {htmlTemplate} from './gr-agreements-list_html';
 import {getBaseUrl} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {ContributorAgreementInfo} from '../../../types/common';
+import {appContext} from '../../../services/app-context';
 
-export interface GrAgreementsList {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-agreements-list')
 export class GrAgreementsList extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -43,6 +38,8 @@
   @property({type: Array})
   _agreements?: ContributorAgreementInfo[];
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -50,7 +47,7 @@
   }
 
   loadData() {
-    return this.$.restAPI.getAccountAgreements().then(agreements => {
+    return this.restApiService.getAccountAgreements().then(agreements => {
       this._agreements = agreements;
     });
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_html.ts b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_html.ts
index 194ca2b..1afac0d 100644
--- a/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-agreements-list/gr-agreements-list_html.ts
@@ -52,5 +52,4 @@
     </table>
     <a href$="[[getUrl()]]">New Contributor Agreement</a>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
index 891fdf6..2e4cb8c 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view.ts
@@ -25,7 +25,6 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-cla-view_html';
 import {getBaseUrl} from '../../../utils/url-util';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {customElement, property} from '@polymer/decorators';
 import {
   ServerInfo,
@@ -33,12 +32,7 @@
   ContributorAgreementInfo,
 } from '../../../types/common';
 import {fireAlert, fireTitleChange} from '../../../utils/event-util';
-
-export interface GrClaView {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -75,6 +69,8 @@
   @property({type: String})
   _agreementsUrl?: string;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -86,13 +82,13 @@
   loadData() {
     const promises = [];
     promises.push(
-      this.$.restAPI.getConfig(true).then(config => {
+      this.restApiService.getConfig(true).then(config => {
         this._serverConfig = config;
       })
     );
 
     promises.push(
-      this.$.restAPI.getAccountGroups().then(groups => {
+      this.restApiService.getAccountGroups().then(groups => {
         if (!groups) return;
         this._groups = groups.sort((a, b) =>
           (a.name || '').localeCompare(b.name || '')
@@ -101,7 +97,7 @@
     );
 
     promises.push(
-      this.$.restAPI
+      this.restApiService
         .getAccountAgreements()
         .then((agreements: ContributorAgreementInfo[] | undefined) => {
           this._signedAgreements = agreements || [];
@@ -138,7 +134,7 @@
     this._createToast('Agreement saving...');
 
     const name = this._agreementName;
-    return this.$.restAPI.saveAccountAgreement({name}).then(res => {
+    return this.restApiService.saveAccountAgreement({name}).then(res => {
       let message = 'Agreement failed to be submitted, please try again';
       if (res.status === 200) {
         message = 'Agreement has been successfully submitted.';
diff --git a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
index c461718..91ca402 100644
--- a/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-cla-view/gr-cla-view_html.ts
@@ -122,5 +122,4 @@
       </div>
     </div>
   </main>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
index d49cb5a..da99583 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences.ts
@@ -24,12 +24,11 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-edit-preferences_html';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {EditPreferencesInfo} from '../../../types/common';
+import {appContext} from '../../../services/app-context';
 
 export interface GrEditPreferences {
   $: {
-    restAPI: RestApiService & Element;
     editSyntaxHighlighting: HTMLInputElement;
     showAutoCloseBrackets: HTMLInputElement;
     showIndentWithTabs: HTMLInputElement;
@@ -52,8 +51,10 @@
   @property({type: Object})
   editPrefs?: EditPreferencesInfo;
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getEditPreferences().then(prefs => {
+    return this.restApiService.getEditPreferences().then(prefs => {
       this.editPrefs = prefs;
     });
   }
@@ -101,7 +102,7 @@
   save() {
     if (!this.editPrefs)
       return Promise.reject(new Error('Missing edit preferences'));
-    return this.$.restAPI.saveEditPreferences(this.editPrefs).then(() => {
+    return this.restApiService.saveEditPreferences(this.editPrefs).then(() => {
       this.hasUnsavedChanges = false;
     });
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_html.ts b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_html.ts
index 47e4592..bcff4df 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_html.ts
@@ -160,5 +160,4 @@
       </span>
     </section>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
index b1b8b61..01c6861 100644
--- a/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-edit-preferences/gr-edit-preferences_test.js
@@ -92,7 +92,7 @@
   });
 
   test('save changes', () => {
-    sinon.stub(element.$.restAPI, 'saveEditPreferences')
+    sinon.stub(element.restApiService, 'saveEditPreferences')
         .returns(Promise.resolve());
     const showTabsCheckbox = valueOf('Show tabs', 'editPreferences')
         .firstElementChild;
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
index fd10a16..9db3e4d 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
@@ -24,14 +24,8 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-email-editor_html';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {EmailInfo} from '../../../types/common';
-
-export interface GrEmailEditor {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 @customElement('gr-email-editor')
 export class GrEmailEditor extends GestureEventListeners(
@@ -53,8 +47,10 @@
   @property({type: String})
   _newPreferred: string | null = null;
 
+  readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getAccountEmails().then(emails => {
+    return this.restApiService.getAccountEmails().then(emails => {
       this._emails = emails ?? [];
     });
   }
@@ -63,12 +59,12 @@
     const promises: Promise<unknown>[] = [];
 
     for (const emailObj of this._emailsToRemove) {
-      promises.push(this.$.restAPI.deleteAccountEmail(emailObj.email));
+      promises.push(this.restApiService.deleteAccountEmail(emailObj.email));
     }
 
     if (this._newPreferred) {
       promises.push(
-        this.$.restAPI.setPreferredAccountEmail(this._newPreferred)
+        this.restApiService.setPreferredAccountEmail(this._newPreferred)
       );
     }
 
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_html.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_html.ts
index 525fca6..0591e4b 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_html.ts
@@ -95,5 +95,4 @@
       </tbody>
     </table>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
index 18ff95c..143d49c 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor_test.ts
@@ -114,9 +114,12 @@
   });
 
   test('save changes', done => {
-    const deleteEmailStub = sinon.stub(element.$.restAPI, 'deleteAccountEmail');
+    const deleteEmailStub = sinon.stub(
+      element.restApiService,
+      'deleteAccountEmail'
+    );
     const setPreferredStub = sinon.stub(
-      element.$.restAPI,
+      element.restApiService,
       'setPreferredAccountEmail'
     );
 
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
index 21e414b..087fe7c 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
@@ -31,11 +31,10 @@
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 export interface GrGpgEditor {
   $: {
-    restAPI: RestApiService & Element;
     viewKeyOverlay: GrOverlay;
     addButton: GrButton;
     newKey: IronAutogrowTextareaElement;
@@ -70,9 +69,11 @@
   @property({type: Array})
   _keysToRemove: GpgKeyInfo[] = [];
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
     this._keys = [];
-    return this.$.restAPI.getAccountGPGKeys().then(keys => {
+    return this.restApiService.getAccountGPGKeys().then(keys => {
       if (!keys) {
         return;
       }
@@ -86,7 +87,7 @@
 
   save() {
     const promises = this._keysToRemove.map(key =>
-      this.$.restAPI.deleteAccountGPGKey(key.id!)
+      this.restApiService.deleteAccountGPGKey(key.id!)
     );
 
     return Promise.all(promises).then(() => {
@@ -117,7 +118,7 @@
   _handleAddKey() {
     this.$.addButton.disabled = true;
     this.$.newKey.disabled = true;
-    return this.$.restAPI
+    return this.restApiService
       .addAccountGPGKey({add: [this._newKey.trim()]})
       .then(() => {
         this.$.newKey.disabled = false;
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_html.ts b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_html.ts
index 432bc4f..69ac702 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_html.ts
@@ -133,5 +133,4 @@
       >
     </fieldset>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
index 2792176..1a84aeb4 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor_test.js
@@ -74,7 +74,7 @@
   test('remove key', done => {
     const lastKey = keys[Object.keys(keys)[1]];
 
-    const saveStub = sinon.stub(element.$.restAPI, 'deleteAccountGPGKey')
+    const saveStub = sinon.stub(element.restApiService, 'deleteAccountGPGKey')
         .callsFake(() => Promise.resolve());
 
     assert.equal(element._keysToRemove.length, 0);
@@ -130,7 +130,8 @@
       },
     };
 
-    const addStub = sinon.stub(element.$.restAPI, 'addAccountGPGKey').callsFake(
+    const addStub = sinon.stub(element.restApiService,
+        'addAccountGPGKey').callsFake(
         () => Promise.resolve(newKeyObject));
 
     element._newKey = newKeyString;
@@ -155,7 +156,8 @@
   test('add invalid key', done => {
     const newKeyString = 'not even close to valid';
 
-    const addStub = sinon.stub(element.$.restAPI, 'addAccountGPGKey').callsFake(
+    const addStub = sinon.stub(element.restApiService,
+        'addAccountGPGKey').callsFake(
         () => Promise.reject(new Error('error')));
 
     element._newKey = newKeyString;
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
index d631c53..30146bc 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list.ts
@@ -22,15 +22,9 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-group-list_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {customElement, property} from '@polymer/decorators';
 import {GroupInfo, GroupId} from '../../../types/common';
-
-export interface GrGroupList {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -48,8 +42,10 @@
   @property({type: Array})
   _groups: GroupInfo[] = [];
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getAccountGroups().then(groups => {
+    return this.restApiService.getAccountGroups().then(groups => {
       if (!groups) return;
       this._groups = groups.sort((a, b) =>
         (a.name || '').localeCompare(b.name || '')
diff --git a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
index e52583d..0ae3490 100644
--- a/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-group-list/gr-group-list_html.ts
@@ -57,5 +57,4 @@
       </tbody>
     </table>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
index 02683e3..424e30e 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password.ts
@@ -26,7 +26,7 @@
 import {htmlTemplate} from './gr-http-password_html';
 import {property, customElement} from '@polymer/decorators';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -36,7 +36,6 @@
 
 export interface GrHttpPassword {
   $: {
-    restAPI: RestApiService & Element;
     generatedPasswordOverlay: GrOverlay;
   };
 }
@@ -58,6 +57,8 @@
   @property({type: String})
   _passwordUrl: string | null = null;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -68,7 +69,7 @@
     const promises = [];
 
     promises.push(
-      this.$.restAPI.getAccount().then(account => {
+      this.restApiService.getAccount().then(account => {
         if (account) {
           this._username = account.username;
         }
@@ -76,7 +77,7 @@
     );
 
     promises.push(
-      this.$.restAPI.getConfig().then(info => {
+      this.restApiService.getConfig().then(info => {
         if (info) {
           this._passwordUrl = info.auth.http_password_url || null;
         } else {
@@ -91,7 +92,7 @@
   _handleGenerateTap() {
     this._generatedPassword = 'Generating...';
     this.$.generatedPasswordOverlay.open();
-    this.$.restAPI.generateAccountHttpPassword().then(newPassword => {
+    this.restApiService.generateAccountHttpPassword().then(newPassword => {
       this._generatedPassword = newPassword;
     });
   }
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_html.ts b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_html.ts
index 41084b5..549fc93 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_html.ts
@@ -94,5 +94,4 @@
       >
     </div>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.js b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.js
index 920ad48..6f47952 100644
--- a/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-http-password/gr-http-password_test.js
@@ -42,7 +42,7 @@
     const button = element.$.generateButton;
     const nextPassword = 'the new password';
     let generateResolve;
-    const generateStub = sinon.stub(element.$.restAPI,
+    const generateStub = sinon.stub(element.restApiService,
         'generateAccountHttpPassword')
         .callsFake(() => new Promise(resolve => {
           generateResolve = resolve;
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
index 5f2b6a5..4222b03 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
@@ -26,16 +26,15 @@
 import {htmlTemplate} from './gr-identities_html';
 import {getBaseUrl} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {AccountExternalIdInfo, ServerInfo} from '../../../types/common';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {PolymerDomRepeatEvent} from '../../../types/types';
+import {appContext} from '../../../services/app-context';
 
 const AUTH = ['OPENID', 'OAUTH'];
 
 export interface GrIdentities {
   $: {
-    restAPI: RestApiService & Element;
     overlay: GrOverlay;
   };
 }
@@ -63,8 +62,10 @@
   })
   _showLinkAnotherIdentity?: boolean;
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getExternalIds().then(id => {
+    return this.restApiService.getExternalIds().then(id => {
       this._identities = id ?? [];
     });
   }
@@ -79,9 +80,11 @@
 
   _handleDeleteItemConfirm() {
     this.$.overlay.close();
-    return this.$.restAPI.deleteAccountIdentity([this._idName!]).then(() => {
-      this.loadData();
-    });
+    return this.restApiService
+      .deleteAccountIdentity([this._idName!])
+      .then(() => {
+        this.loadData();
+      });
   }
 
   _handleConfirmDialogCancel() {
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
index 1472103..34af7eb 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities_html.ts
@@ -103,5 +103,4 @@
       item-type="id"
     ></gr-confirm-delete-item-dialog>
   </gr-overlay>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
index 0e73062..793900b 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
@@ -25,12 +25,11 @@
 import {htmlTemplate} from './gr-registration-dialog_html';
 import {customElement, property, observe} from '@polymer/decorators';
 import {ServerInfo, AccountDetailInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {EditableAccountField} from '../../../constants/constants';
+import {appContext} from '../../../services/app-context';
 
 export interface GrRegistrationDialog {
   $: {
-    restAPI: RestApiService & Element;
     name: HTMLInputElement;
     username: HTMLInputElement;
     email: HTMLSelectElement;
@@ -83,6 +82,8 @@
   })
   _usernameMutable = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   ready() {
     super.ready();
@@ -107,11 +108,11 @@
   loadData() {
     this._loading = true;
 
-    const loadAccount = this.$.restAPI.getAccount().then(account => {
+    const loadAccount = this.restApiService.getAccount().then(account => {
       this._account = {...this._account, ...account};
     });
 
-    const loadConfig = this.$.restAPI.getConfig().then(config => {
+    const loadConfig = this.restApiService.getConfig().then(config => {
       this._serverConfig = config;
     });
 
@@ -123,12 +124,14 @@
   _save() {
     this._saving = true;
     const promises = [
-      this.$.restAPI.setAccountName(this.$.name.value),
-      this.$.restAPI.setPreferredAccountEmail(this.$.email.value || ''),
+      this.restApiService.setAccountName(this.$.name.value),
+      this.restApiService.setPreferredAccountEmail(this.$.email.value || ''),
     ];
 
     if (this._usernameMutable) {
-      promises.push(this.$.restAPI.setAccountUsername(this.$.username.value));
+      promises.push(
+        this.restApiService.setAccountUsername(this.$.username.value)
+      );
     }
 
     return Promise.all(promises).then(() => {
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
index 11fbbc9..a1d6a5c 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog_html.ts
@@ -129,5 +129,4 @@
       >
     </footer>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 4293a83..bf739c7 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -57,7 +57,6 @@
 import {GrIdentities} from '../gr-identities/gr-identities';
 import {GrEditPreferences} from '../gr-edit-preferences/gr-edit-preferences';
 import {GrDiffPreferences} from '../../shared/gr-diff-preferences/gr-diff-preferences';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   PreferencesInput,
   ServerInfo,
@@ -69,6 +68,7 @@
 import {GrEmailEditor} from '../gr-email-editor/gr-email-editor';
 import {CustomKeyboardEvent} from '../../../types/events';
 import {fireAlert, fireTitleChange} from '../../../utils/event-util';
+import {appContext} from '../../../services/app-context';
 
 const PREFS_SECTION_FIELDS: Array<keyof PreferencesInput> = [
   'changes_per_page',
@@ -102,7 +102,6 @@
 
 export interface GrSettingsView {
   $: {
-    restAPI: RestApiService & Element;
     accountInfo: GrAccountInfo;
     watchedProjectsEditor: GrWatchedProjectsEditor;
     groupList: GrGroupList;
@@ -214,6 +213,8 @@
 
   public _testOnly_loadingPromise?: Promise<void>;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -234,7 +235,7 @@
     ];
 
     promises.push(
-      this.$.restAPI.getPreferences().then(prefs => {
+      this.restApiService.getPreferences().then(prefs => {
         if (!prefs) {
           throw new Error('getPreferences returned undefined');
         }
@@ -247,7 +248,7 @@
     );
 
     promises.push(
-      this.$.restAPI.getConfig().then(config => {
+      this.restApiService.getConfig().then(config => {
         this._serverConfig = config;
         const configPromises: Array<Promise<void>> = [];
 
@@ -264,7 +265,7 @@
         }
 
         configPromises.push(
-          getDocsBaseUrl(config, this.$.restAPI).then(baseUrl => {
+          getDocsBaseUrl(config, this.restApiService).then(baseUrl => {
             this._docsBaseUrl = baseUrl;
           })
         );
@@ -279,12 +280,14 @@
       this.params.emailToken
     ) {
       promises.push(
-        this.$.restAPI.confirmEmail(this.params.emailToken).then(message => {
-          if (message) {
-            fireAlert(this, message);
-          }
-          this.$.emailEditor.loadData();
-        })
+        this.restApiService
+          .confirmEmail(this.params.emailToken)
+          .then(message => {
+            if (message) {
+              fireAlert(this, message);
+            }
+            this.$.emailEditor.loadData();
+          })
       );
     } else {
       promises.push(this.$.emailEditor.loadData());
@@ -427,7 +430,7 @@
   _handleSavePreferences() {
     this._copyPrefs(CopyPrefsDirection.LocalPrefsToPrefs);
 
-    return this.$.restAPI.savePreferences(this.prefs).then(() => {
+    return this.restApiService.savePreferences(this.prefs).then(() => {
       this._prefsChanged = false;
     });
   }
@@ -436,7 +439,7 @@
     this.set('prefs.change_table', this._localChangeTableColumns);
     this.set('prefs.legacycid_in_change_table', this._showNumber);
     this._cloneChangeTableColumns(this._localChangeTableColumns);
-    return this.$.restAPI.savePreferences(this.prefs).then(() => {
+    return this.restApiService.savePreferences(this.prefs).then(() => {
       this._changeTableChanged = false;
     });
   }
@@ -452,13 +455,13 @@
   _handleSaveMenu() {
     this.set('prefs.my', this._localMenu);
     this._cloneMenu(this._localMenu);
-    return this.$.restAPI.savePreferences(this.prefs).then(() => {
+    return this.restApiService.savePreferences(this.prefs).then(() => {
       this._menuChanged = false;
     });
   }
 
   _handleResetMenuButton() {
-    return this.$.restAPI.getDefaultPreferences().then(data => {
+    return this.restApiService.getDefaultPreferences().then(data => {
       if (data?.my) {
         this._cloneMenu(data.my);
       }
@@ -497,7 +500,7 @@
     if (!this._isNewEmailValid(this._newEmail)) return;
 
     this._addingEmail = true;
-    this.$.restAPI.addAccountEmail(this._newEmail).then(response => {
+    this.restApiService.addAccountEmail(this._newEmail).then(response => {
       this._addingEmail = false;
 
       // If it was unsuccessful.
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
index 78f84b1..d1d412f 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_html.ts
@@ -552,5 +552,4 @@
       <gr-endpoint-decorator name="settings-screen"> </gr-endpoint-decorator>
     </main>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
index 0535e15..a01edac 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view_test.js
@@ -51,7 +51,7 @@
   }
 
   function stubAddAccountEmail(statusCode) {
-    return sinon.stub(element.$.restAPI, 'addAccountEmail').callsFake(
+    return sinon.stub(element.restApiService, 'addAccountEmail').callsFake(
         () => Promise.resolve({status: statusCode}));
   }
 
@@ -481,7 +481,7 @@
     setup(() => {
       sinon.stub(element.$.emailEditor, 'loadData');
       sinon.stub(
-          element.$.restAPI,
+          element.restApiService,
           'confirmEmail')
           .callsFake(
               () => new Promise(
@@ -491,8 +491,8 @@
     });
 
     test('it is used to confirm email via rest API', () => {
-      assert.isTrue(element.$.restAPI.confirmEmail.calledOnce);
-      assert.isTrue(element.$.restAPI.confirmEmail.calledWith('foo'));
+      assert.isTrue(element.restApiService.confirmEmail.calledOnce);
+      assert.isTrue(element.restApiService.confirmEmail.calledWith('foo'));
     });
 
     test('emails are not loaded initially', () => {
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
index 507caef..d4de208 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor.ts
@@ -31,11 +31,10 @@
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {IronAutogrowTextareaElement} from '@polymer/iron-autogrow-textarea/iron-autogrow-textarea';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 export interface GrSshEditor {
   $: {
-    restAPI: RestApiService & Element;
     addButton: GrButton;
     newKey: IronAutogrowTextareaElement;
     viewKeyOverlay: GrOverlay;
@@ -70,8 +69,10 @@
   @property({type: Array})
   _keysToRemove: SshKeyInfo[] = [];
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getAccountSSHKeys().then(keys => {
+    return this.restApiService.getAccountSSHKeys().then(keys => {
       if (!keys) return;
       this._keys = keys;
     });
@@ -79,7 +80,7 @@
 
   save() {
     const promises = this._keysToRemove.map(key =>
-      this.$.restAPI.deleteAccountSSHKey(`${key.seq}`)
+      this.restApiService.deleteAccountSSHKey(`${key.seq}`)
     );
     return Promise.all(promises).then(() => {
       this._keysToRemove = [];
@@ -113,7 +114,7 @@
   _handleAddKey() {
     this.$.addButton.disabled = true;
     this.$.newKey.disabled = true;
-    return this.$.restAPI
+    return this.restApiService
       .addAccountSSHKey(this._newKey.trim())
       .then(key => {
         this.$.newKey.disabled = false;
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_html.ts b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_html.ts
index 96f770a..0bee1d3 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_html.ts
@@ -139,5 +139,4 @@
       >
     </fieldset>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
index 29ba692..73e707f 100644
--- a/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
+++ b/polygerrit-ui/app/elements/settings/gr-ssh-editor/gr-ssh-editor_test.js
@@ -65,7 +65,7 @@
   test('remove key', done => {
     const lastKey = keys[1];
 
-    const saveStub = sinon.stub(element.$.restAPI, 'deleteAccountSSHKey')
+    const saveStub = sinon.stub(element.restApiService, 'deleteAccountSSHKey')
         .callsFake(() => Promise.resolve());
 
     assert.equal(element._keysToRemove.length, 0);
@@ -116,7 +116,8 @@
       valid: true,
     };
 
-    const addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey').callsFake(
+    const addStub = sinon.stub(element.restApiService,
+        'addAccountSSHKey').callsFake(
         () => Promise.resolve(newKeyObject));
 
     element._newKey = newKeyString;
@@ -141,7 +142,8 @@
   test('add invalid key', done => {
     const newKeyString = 'not even close to valid';
 
-    const addStub = sinon.stub(element.$.restAPI, 'addAccountSSHKey').callsFake(
+    const addStub = sinon.stub(element.restApiService,
+        'addAccountSSHKey').callsFake(
         () => Promise.reject(new Error('error')));
 
     element._newKey = newKeyString;
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
index 15f9c6b..58be0f7 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor.ts
@@ -31,9 +31,9 @@
   GrAutocomplete,
   AutocompleteSuggestion,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {ProjectWatchInfo} from '../../../types/common';
+import {appContext} from '../../../services/app-context';
 
 const NOTIFICATION_TYPES = [
   {name: 'Changes', key: 'notify_new_changes'},
@@ -45,7 +45,6 @@
 
 export interface GrWatchedProjectsEditor {
   $: {
-    restAPI: RestApiService & Element;
     newFilter: HTMLInputElement;
     newProject: GrAutocomplete;
   };
@@ -70,13 +69,15 @@
   @property({type: Object})
   _query?: AutocompleteQuery;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = input => this._getProjectSuggestions(input);
   }
 
   loadData() {
-    return this.$.restAPI.getWatchedProjects().then(projs => {
+    return this.restApiService.getWatchedProjects().then(projs => {
       this._projects = projs;
     });
   }
@@ -84,7 +85,7 @@
   save() {
     let deletePromise;
     if (this._projectsToRemove.length) {
-      deletePromise = this.$.restAPI.deleteWatchedProjects(
+      deletePromise = this.restApiService.deleteWatchedProjects(
         this._projectsToRemove
       );
     } else {
@@ -94,7 +95,7 @@
     return deletePromise
       .then(() => {
         if (this._projects) {
-          return this.$.restAPI.saveWatchedProjects(this._projects);
+          return this.restApiService.saveWatchedProjects(this._projects);
         } else {
           return Promise.resolve(undefined);
         }
@@ -119,7 +120,7 @@
   }
 
   _getProjectSuggestions(input: string) {
-    return this.$.restAPI.getSuggestedProjects(input).then(response => {
+    return this.restApiService.getSuggestedProjects(input).then(response => {
       const projects: AutocompleteSuggestion[] = [];
       for (const key in response) {
         if (!hasOwnProperty(response, key)) {
diff --git a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_html.ts b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_html.ts
index e3a90a2..edc8fb2 100644
--- a/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_html.ts
+++ b/polygerrit-ui/app/elements/settings/gr-watched-projects-editor/gr-watched-projects-editor_html.ts
@@ -120,5 +120,4 @@
       </tfoot>
     </table>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
index 9623442..65bf55d3d 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip.ts
@@ -25,13 +25,8 @@
 import {htmlTemplate} from './gr-account-chip_html';
 import {customElement, property} from '@polymer/decorators';
 import {AccountInfo, ChangeInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
-export interface GrAccountChip {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-account-chip')
 export class GrAccountChip extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -94,6 +89,8 @@
   @property({type: Boolean})
   transparentBackground = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   ready() {
     super.ready();
@@ -118,7 +115,7 @@
   }
 
   _getHasAvatars() {
-    return this.$.restAPI
+    return this.restApiService
       .getConfig()
       .then(cfg =>
         Promise.resolve(!!(cfg && cfg.plugin && cfg.plugin.has_avatars))
diff --git a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
index 991104f..3bb1458 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-chip/gr-account-chip_html.ts
@@ -109,5 +109,4 @@
       <iron-icon icon="gr-icons:close"></iron-icon>
     </gr-button>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
index be23cb3..b37645e 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label.ts
@@ -27,16 +27,10 @@
 import {getDisplayName} from '../../../utils/display-name-util';
 import {isServiceUser} from '../../../utils/account-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
 import {ChangeInfo, AccountInfo, ServerInfo} from '../../../types/common';
 import {hasOwnProperty} from '../../../utils/common-util';
 
-export interface GrAccountLabel {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-account-label')
 export class GrAccountLabel extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -106,6 +100,8 @@
 
   reporting: ReportingService;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this.reporting = appContext.reportingService;
@@ -114,10 +110,10 @@
   /** @override */
   ready() {
     super.ready();
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this._config = config;
     });
-    this.$.restAPI.getAccount().then(account => {
+    this.restApiService.getAccount().then(account => {
       this._selfAccount = account;
     });
     this.addEventListener('attention-set-updated', () => {
@@ -232,7 +228,7 @@
       'attention-icon-remove',
       this._reportingDetails()
     );
-    this.$.restAPI
+    this.restApiService
       .removeFromAttentionSet(
         this.change._number,
         this.account._account_id,
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
index 1d8b13e..b62df9e 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_html.ts
@@ -132,5 +132,4 @@
       </template>
     </span>
   </span>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
index 2e54db2..42b1dd7 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-account-label/gr-account-label_test.js
@@ -99,7 +99,8 @@
     });
 
     test('tap attention button', () => {
-      const apiStub = sinon.stub(element.$.restAPI, 'removeFromAttentionSet')
+      const apiStub = sinon.stub(element.restApiService,
+          'removeFromAttentionSet')
           .callsFake(() => Promise.resolve());
       const button = element.shadowRoot.querySelector('#attentionButton');
       assert.ok(button);
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
index 45bac9f..f8042a5 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar.ts
@@ -25,13 +25,8 @@
 import {getPluginLoader} from '../gr-js-api-interface/gr-plugin-loader';
 import {customElement, property} from '@polymer/decorators';
 import {AccountInfo} from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
-export interface GrAvatar {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-avatar')
 export class GrAvatar extends GestureEventListeners(
   LegacyElementMixin(PolymerElement)
@@ -49,6 +44,8 @@
   @property({type: Boolean})
   _hasAvatars = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -63,7 +60,7 @@
   }
 
   _getConfig() {
-    return this.$.restAPI.getConfig();
+    return this.restApiService.getConfig();
   }
 
   _accountChanged() {
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
index 0d8e78f..d105c5d 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_html.ts
@@ -25,5 +25,4 @@
       background-color: var(--avatar-background-color, #f1f2f3);
     }
   </style>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
index 261d59c..baec672 100644
--- a/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-avatar/gr-avatar_test.js
@@ -104,7 +104,7 @@
       getPluginLoader().loadPlugins([]);
 
       return Promise.all([
-        element.$.restAPI.getConfig(),
+        element.restApiService.getConfig(),
         getPluginLoader().awaitPluginsLoaded(),
       ]).then(() => {
         assert.isFalse(element.hasAttribute('hidden'));
@@ -134,7 +134,7 @@
       getPluginLoader().loadPlugins([]);
 
       return Promise.all([
-        element.$.restAPI.getConfig(),
+        element.restApiService.getConfig(),
         getPluginLoader().awaitPluginsLoaded(),
       ]).then(() => {
         assert.isTrue(element.hasAttribute('hidden'));
@@ -167,7 +167,7 @@
       getPluginLoader().loadPlugins([]);
 
       return Promise.all([
-        element.$.restAPI.getConfig(),
+        element.restApiService.getConfig(),
         getPluginLoader().awaitPluginsLoaded(),
       ]).then(() => {
         assert.isTrue(element.hasAttribute('hidden'));
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
index f0c5012..d25b22c 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread.ts
@@ -37,7 +37,6 @@
 import {CommentSide, Side, SpecialFilePath} from '../../../constants/constants';
 import {computeDisplayPath} from '../../../utils/path-list-util';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   CommentRange,
   ConfigInfo,
@@ -58,7 +57,6 @@
 
 export interface GrCommentThread {
   $: {
-    restAPI: RestApiService & Element;
     storage: GrStorage;
     replyBtn: GrButton;
     quoteBtn: GrButton;
@@ -187,6 +185,8 @@
 
   flagsService = appContext.flagsService;
 
+  readonly restApiService = appContext.restApiService;
+
   /** @override */
   created() {
     super.created();
@@ -310,7 +310,7 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   @observe('comments.*')
@@ -639,7 +639,7 @@
     if (!name) {
       return;
     }
-    this.$.restAPI.getProjectConfig(name).then(config => {
+    this.restApiService.getProjectConfig(name).then(config => {
       this._projectConfig = config;
     });
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
index 4c15383..ee3e5d0 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_html.ts
@@ -164,6 +164,5 @@
       </div>
     </div>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
index 8ce220c..86311dd 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment-thread/gr-comment-thread_test.ts
@@ -231,7 +231,7 @@
     test('setting project name loads the project config', done => {
       const projectName = 'foo/bar/baz' as RepoName;
       const getProjectStub = sinon
-        .stub(element.$.restAPI, 'getProjectConfig')
+        .stub(element.restApiService, 'getProjectConfig')
         .returns(Promise.resolve({} as ConfigInfo));
       element.projectName = projectName;
       flush(() => {
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
index b4d4c5b..e7cfd25 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment.ts
@@ -39,7 +39,6 @@
 import {getRootElement} from '../../../scripts/rootElement';
 import {appContext} from '../../../services/app-context';
 import {customElement, observe, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrTextarea} from '../gr-textarea/gr-textarea';
 import {GrStorage, StorageLocation} from '../gr-storage/gr-storage';
 import {GrOverlay} from '../gr-overlay/gr-overlay';
@@ -98,7 +97,6 @@
 
 export interface GrComment {
   $: {
-    restAPI: RestApiService & Element;
     storage: GrStorage;
     container: HTMLDivElement;
     resolvedCheckbox: HTMLInputElement;
@@ -270,12 +268,14 @@
     };
   }
 
+  private readonly restApiService = appContext.restApiService;
+
   reporting = appContext.reportingService;
 
   /** @override */
   attached() {
     super.attached();
-    this.$.restAPI.getAccount().then(account => {
+    this.restApiService.getAccount().then(account => {
       this._selfAccount = account;
     });
     if (this.editing) {
@@ -405,7 +405,7 @@
   }
 
   _getIsAdmin() {
-    return this.$.restAPI.getIsAdmin();
+    return this.restApiService.getIsAdmin();
   }
 
   _computeDraftTooltip(unableToSave: boolean) {
@@ -441,7 +441,7 @@
         }
 
         this._eraseDraftComment();
-        return this.$.restAPI.getResponseObject(response).then(obj => {
+        return this.restApiService.getResponseObject(response).then(obj => {
           const resComment = (obj as unknown) as UIDraft;
           if (!isDraft(this.comment)) throw new Error('Can only save drafts.');
           resComment.__draft = true;
@@ -869,7 +869,7 @@
       throw new Error('undefined draft or changeNum or patchNum');
     }
     this._showStartRequest();
-    return this.$.restAPI
+    return this.restApiService
       .saveDiffDraft(this.changeNum, this.patchNum, draft)
       .then(result => {
         if (result.ok) {
@@ -894,7 +894,7 @@
     }
     this._showStartRequest();
     if (!draft.id) throw new Error('Missing id in comment draft.');
-    return this.$.restAPI
+    return this.restApiService
       .deleteDiffDraft(this.changeNum, this.patchNum, {id: draft.id})
       .then(result => {
         if (result.ok) {
@@ -1020,7 +1020,7 @@
     ) {
       throw new Error('undefined comment or id or changeNum or patchNum');
     }
-    this.$.restAPI
+    this.restApiService
       .deleteComment(
         this.changeNum,
         this.patchNum,
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
index c3125c1..64f0be1 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_html.ts
@@ -478,6 +478,5 @@
       </gr-dialog>
     </gr-overlay>
   </template>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
   <gr-storage id="storage"></gr-storage>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
index e8d74f0..d7a581c 100644
--- a/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-comment/gr-comment_test.js
@@ -276,7 +276,7 @@
 
     test('delete comment', done => {
       sinon.stub(
-          element.$.restAPI, 'deleteComment').returns(Promise.resolve({}));
+          element.restApiService, 'deleteComment').returns(Promise.resolve({}));
       sinon.spy(element.confirmDeleteOverlay, 'open');
       element.changeNum = 42;
       element.patchNum = 0xDEADBEEF;
@@ -293,7 +293,7 @@
                   .querySelector('#confirmDeleteComment');
           dialog.message = 'removal reason';
           element._handleConfirmDeleteComment();
-          assert.isTrue(element.$.restAPI.deleteComment.calledWith(
+          assert.isTrue(element.restApiService.deleteComment.calledWith(
               42, 0xDEADBEEF, 'baf0414d_60047215', 'removal reason'));
           done();
         });
@@ -375,7 +375,7 @@
       element.patchNum = 1;
       const updateRequestStub = sinon.stub(element, '_updateRequestToast');
       const diffDraftStub =
-        sinon.stub(element.$.restAPI, 'saveDiffDraft').returns(
+        sinon.stub(element.restApiService, 'saveDiffDraft').returns(
             Promise.resolve({ok: false}));
       element._saveDraft({id: 'abc_123'});
       flush(() => {
@@ -411,7 +411,7 @@
       element.patchNum = 1;
       const updateRequestStub = sinon.stub(element, '_updateRequestToast');
       const diffDraftStub =
-        sinon.stub(element.$.restAPI, 'saveDiffDraft').returns(
+        sinon.stub(element.restApiService, 'saveDiffDraft').returns(
             Promise.reject(new Error()));
       element._saveDraft({id: 'abc_123'});
       flush(() => {
@@ -803,7 +803,7 @@
     test('storage is cleared only after save success', () => {
       element._messageText = 'test';
       const eraseStub = sinon.stub(element, '_eraseDraftComment');
-      sinon.stub(element.$.restAPI, 'getResponseObject')
+      sinon.stub(element.restApiService, 'getResponseObject')
           .returns(Promise.resolve({}));
 
       sinon.stub(element, '_saveDraft').returns(Promise.resolve({ok: false}));
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
index 05e9a73..a4e2a39 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter.ts
@@ -34,8 +34,8 @@
 } from '../../../utils/date-util';
 import {TimeFormat, DateFormat} from '../../../constants/constants';
 import {assertNever} from '../../../utils/common-util';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {Timestamp} from '../../../types/common';
+import {appContext} from '../../../services/app-context';
 
 const TimeFormats = {
   TIME_12: 'h:mm A', // 2:14 PM
@@ -78,12 +78,6 @@
   }
 }
 
-export interface GrDateFormatter {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
-
 @customElement('gr-date-formatter')
 export class GrDateFormatter extends TooltipMixin(
   GestureEventListeners(LegacyElementMixin(PolymerElement))
@@ -134,6 +128,8 @@
   @property({type: Boolean})
   relativeOptionNoAgo = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
   }
@@ -214,11 +210,11 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   _getPreferences() {
-    return this.$.restAPI.getPreferences();
+    return this.restApiService.getPreferences();
   }
 
   _computeDateStr(
diff --git a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
index a08a77d..97bbf68 100644
--- a/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-date-formatter/gr-date-formatter_html.ts
@@ -27,5 +27,4 @@
     [[_computeDateStr(dateStr, _timeFormat, _dateFormat, _relative,
     showDateAndTime, showYesterday)]]
   </span>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
index e781820c..9ede8cc 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences.ts
@@ -24,13 +24,12 @@
 import {PolymerElement} from '@polymer/polymer/polymer-element';
 import {htmlTemplate} from './gr-diff-preferences_html';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {DiffPreferencesInfo} from '../../../types/diff';
 import {GrSelect} from '../gr-select/gr-select';
+import {appContext} from '../../../services/app-context';
 
 export interface GrDiffPreferences {
   $: {
-    restAPI: RestApiService & Element;
     lineWrappingInput: HTMLInputElement;
     showTabsInput: HTMLInputElement;
     showTrailingWhitespaceInput: HTMLInputElement;
@@ -55,8 +54,10 @@
   @property({type: Object})
   diffPrefs?: DiffPreferencesInfo;
 
+  private readonly restApiService = appContext.restApiService;
+
   loadData() {
-    return this.$.restAPI.getDiffPreferences().then(prefs => {
+    return this.restApiService.getDiffPreferences().then(prefs => {
       this.diffPrefs = prefs;
     });
   }
@@ -99,7 +100,7 @@
   save() {
     if (!this.diffPrefs)
       return Promise.reject(new Error('Missing diff preferences'));
-    return this.$.restAPI.saveDiffPreferences(this.diffPrefs).then(_ => {
+    return this.restApiService.saveDiffPreferences(this.diffPrefs).then(_ => {
       this.hasUnsavedChanges = false;
     });
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
index 54022ba..d30aadf 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_html.ts
@@ -191,5 +191,4 @@
       </div>
     </section>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.js b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.js
index ced8c6c..6afb299 100644
--- a/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-diff-preferences/gr-diff-preferences_test.js
@@ -89,7 +89,7 @@
   });
 
   test('save changes', () => {
-    sinon.stub(element.$.restAPI, 'saveDiffPreferences')
+    sinon.stub(element.restApiService, 'saveDiffPreferences')
         .returns(Promise.resolve());
     const showTrailingWhitespaceCheckbox =
         valueOf('Show trailing whitespace', 'diffPreferences')
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
index 97747a0..34595cc 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands.ts
@@ -24,7 +24,7 @@
 import {htmlTemplate} from './gr-download-commands_html';
 import {customElement, property, observe} from '@polymer/decorators';
 import {PaperTabsElement} from '@polymer/paper-tabs/paper-tabs';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -35,7 +35,6 @@
 export interface GrDownloadCommands {
   $: {
     downloadTabs: PaperTabsElement;
-    restAPI: RestApiService & Element;
   };
 }
 
@@ -65,6 +64,8 @@
   @property({type: String, notify: true})
   selectedScheme?: string;
 
+  private readonly restApiService = appContext.restApiService;
+
   /** @override */
   attached() {
     super.attached();
@@ -79,7 +80,7 @@
   }
 
   _getLoggedIn() {
-    return this.$.restAPI.getLoggedIn();
+    return this.restApiService.getLoggedIn();
   }
 
   @observe('_loggedIn')
@@ -87,7 +88,7 @@
     if (!loggedIn) {
       return;
     }
-    return this.$.restAPI.getPreferences().then(prefs => {
+    return this.restApiService.getPreferences().then(prefs => {
       if (prefs?.download_scheme) {
         // Note (issue 5180): normalize the download scheme with lower-case.
         this.selectedScheme = prefs.download_scheme.toLowerCase();
@@ -100,7 +101,9 @@
     if (scheme && scheme !== this.selectedScheme) {
       this.set('selectedScheme', scheme);
       if (this._loggedIn) {
-        this.$.restAPI.savePreferences({download_scheme: this.selectedScheme});
+        this.restApiService.savePreferences({
+          download_scheme: this.selectedScheme,
+        });
       }
     }
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_html.ts b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_html.ts
index 35385fa..5c15b29 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_html.ts
@@ -72,5 +72,4 @@
       ></gr-shell-command>
     </template>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.js b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.js
index 5429506..105cc2c 100644
--- a/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-download-commands/gr-download-commands_test.js
@@ -94,10 +94,11 @@
         },
       });
       element._loggedIn = true;
-      assert.isTrue(element.$.restAPI.getPreferences.called);
-      return element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
-        assert.equal(element.selectedScheme, 'repo');
-      });
+      assert.isTrue(element.restApiService.getPreferences.called);
+      return element.restApiService.getPreferences.lastCall.returnValue.then(
+          () => {
+            assert.equal(element.selectedScheme, 'repo');
+          });
     });
 
     test('normalize scheme from preferences', () => {
@@ -107,14 +108,16 @@
         },
       });
       element._loggedIn = true;
-      return element.$.restAPI.getPreferences.lastCall.returnValue.then(() => {
-        assert.equal(element.selectedScheme, 'repo');
-      });
+      return element.restApiService.getPreferences.lastCall.returnValue.then(
+          () => {
+            assert.equal(element.selectedScheme, 'repo');
+          });
     });
 
     test('saves scheme to preferences', () => {
       element._loggedIn = true;
-      const savePrefsStub = sinon.stub(element.$.restAPI, 'savePreferences')
+      const savePrefsStub = sinon.stub(element.restApiService,
+          'savePreferences')
           .callsFake(() => Promise.resolve());
 
       flush();
diff --git a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
index 8ea0d21..c767edd 100644
--- a/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-dropdown/gr-dropdown_html.ts
@@ -165,5 +165,4 @@
     focus-on-move=""
     stops="[[_listElements]]"
   ></gr-cursor-manager>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
index 0b4e577..9764c59 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account.ts
@@ -29,7 +29,6 @@
 import {accountKey} from '../../../utils/account-util';
 import {getDisplayName} from '../../../utils/display-name-util';
 import {customElement, property} from '@polymer/decorators';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {
   AccountInfo,
   ChangeInfo,
@@ -48,11 +47,6 @@
 import {isRemovableReviewer} from '../../../utils/change-util';
 import {CURRENT} from '../../../utils/patch-set-util';
 
-export interface GrHovercardAccount {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
 @customElement('gr-hovercard-account')
 export class GrHovercardAccount extends GestureEventListeners(
   hovercardBehaviorMixin(LegacyElementMixin(PolymerElement))
@@ -95,6 +89,8 @@
 
   reporting: ReportingService;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this.reporting = appContext.reportingService;
@@ -102,10 +98,10 @@
 
   attached() {
     super.attached();
-    this.$.restAPI.getConfig().then(config => {
+    this.restApiService.getConfig().then(config => {
       this._config = config;
     });
-    this.$.restAPI.getAccount().then(account => {
+    this.restApiService.getAccount().then(account => {
       this._selfAccount = account;
     });
   }
@@ -186,7 +182,7 @@
       },
     ];
 
-    this.$.restAPI
+    this.restApiService
       .saveChangeReview(this.change._number, CURRENT, reviewInput)
       .then(response => {
         if (!response || !response.ok) {
@@ -205,7 +201,7 @@
     this.dispatchEventThroughTarget('show-alert', {
       message: 'Reloading page...',
     });
-    this.$.restAPI
+    this.restApiService
       .removeChangeReviewer(
         this.change._number,
         (this.account?._account_id || this.account?.email)!
@@ -257,7 +253,7 @@
       'attention-hovercard-add',
       this._reportingDetails()
     );
-    this.$.restAPI
+    this.restApiService
       .addToAttentionSet(this.change._number, this.account._account_id, reason)
       .then(() => {
         this.dispatchEventThroughTarget('hide-alert');
@@ -284,7 +280,7 @@
       'attention-hovercard-remove',
       this._reportingDetails()
     );
-    this.$.restAPI
+    this.restApiService
       .removeFromAttentionSet(
         this.change._number,
         this.account._account_id,
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
index 1d437fb..99d3d6c 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_html.ts
@@ -196,5 +196,4 @@
       </template>
     </template>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
index b09f0ce..c8b4b42 100644
--- a/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-hovercard-account/gr-hovercard-account_test.js
@@ -36,7 +36,7 @@
 
   setup(() => {
     element = basicFixture.instantiate();
-    sinon.stub(element.$.restAPI, 'getAccount').returns(
+    sinon.stub(element.restApiService, 'getAccount').returns(
         new Promise(resolve => { '2'; })
     );
 
@@ -110,7 +110,7 @@
         [ReviewerState.REVIEWER]: [ACCOUNT],
       },
     };
-    sinon.stub(element.$.restAPI, 'removeChangeReviewer').returns(
+    sinon.stub(element.restApiService, 'removeChangeReviewer').returns(
         Promise.resolve({ok: true}));
     const reloadListener = sinon.spy();
     element._target.addEventListener('reload', reloadListener);
@@ -130,10 +130,10 @@
         [ReviewerState.REVIEWER]: [ACCOUNT],
       },
     };
-    const saveReviewStub = sinon.stub(element.$.restAPI,
+    const saveReviewStub = sinon.stub(element.restApiService,
         'saveChangeReview').returns(
         Promise.resolve({ok: true}));
-    sinon.stub(element.$.restAPI, 'removeChangeReviewer').returns(
+    sinon.stub(element.restApiService, 'removeChangeReviewer').returns(
         Promise.resolve({ok: true}));
     const reloadListener = sinon.spy();
     element._target.addEventListener('reload', reloadListener);
@@ -157,10 +157,10 @@
         [ReviewerState.REVIEWER]: [],
       },
     };
-    const saveReviewStub = sinon.stub(element.$.restAPI,
+    const saveReviewStub = sinon.stub(element.restApiService,
         'saveChangeReview').returns(
         Promise.resolve({ok: true}));
-    sinon.stub(element.$.restAPI, 'removeChangeReviewer').returns(
+    sinon.stub(element.restApiService, 'removeChangeReviewer').returns(
         Promise.resolve({ok: true}));
     const reloadListener = sinon.spy();
     element._target.addEventListener('reload', reloadListener);
@@ -184,7 +184,7 @@
         [ReviewerState.REVIEWER]: [],
       },
     };
-    sinon.stub(element.$.restAPI, 'removeChangeReviewer').returns(
+    sinon.stub(element.restApiService, 'removeChangeReviewer').returns(
         Promise.resolve({ok: true}));
     const reloadListener = sinon.spy();
     element._target.addEventListener('reload', reloadListener);
@@ -206,7 +206,7 @@
     const apiPromise = new Promise(r => {
       apiResolve = r;
     });
-    sinon.stub(element.$.restAPI, 'addToAttentionSet')
+    sinon.stub(element.restApiService, 'addToAttentionSet')
         .callsFake(() => apiPromise);
     element.highlightAttention = true;
     element._target = document.createElement('div');
@@ -239,7 +239,7 @@
     const apiPromise = new Promise(r => {
       apiResolve = r;
     });
-    sinon.stub(element.$.restAPI, 'removeFromAttentionSet')
+    sinon.stub(element.restApiService, 'removeFromAttentionSet')
         .callsFake(() => apiPromise);
     element.highlightAttention = true;
     element.change = {attention_set: {31415926535: {}}};
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
index 1dac371..332aa51 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info.ts
@@ -38,15 +38,9 @@
   isQuickLabelInfo,
   isDetailedLabelInfo,
 } from '../../../types/common';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
 import {GrButton} from '../gr-button/gr-button';
 import {getVotingRangeOrDefault} from '../../../utils/label-util';
-
-export interface GrLabelInfo {
-  $: {
-    restAPI: RestApiService & Element;
-  };
-}
+import {appContext} from '../../../services/app-context';
 
 declare global {
   interface HTMLElementTagNameMap {
@@ -90,6 +84,8 @@
   @property({type: Boolean})
   mutable = false;
 
+  private readonly restApiService = appContext.restApiService;
+
   // TODO(TS): not used, remove later
   _xhrPromise?: Promise<void>;
 
@@ -206,7 +202,7 @@
     const accountID = Number(
       `${target.getAttribute('data-account-id')}`
     ) as AccountId;
-    this._xhrPromise = this.$.restAPI
+    this._xhrPromise = this.restApiService
       .deleteVote(this.change._number, accountID, this.label)
       .then(response => {
         target.disabled = false;
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
index 3955cd4..46b8be1 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_html.ts
@@ -118,5 +118,4 @@
       </tr>
     </template>
   </table>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
index 3a2cc39..aa71bfc 100644
--- a/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-label-info/gr-label-info_test.js
@@ -73,7 +73,7 @@
     test('deletes votes', () => {
       const deleteResponse = Promise.resolve({ok: true});
       const deleteStub = sinon.stub(
-          element.$.restAPI, 'deleteVote').returns(deleteResponse);
+          element.restApiService, 'deleteVote').returns(deleteResponse);
 
       element.change.removable_reviewers = [element.account];
       element.change.labels.test.recommended = {_account_id: 1};
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
index 01eada8..48c2253 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker.ts
@@ -33,7 +33,7 @@
   BranchInfo,
 } from '../../../types/common';
 import {GrLabeledAutocomplete} from '../gr-labeled-autocomplete/gr-labeled-autocomplete';
-import {RestApiService} from '../../../services/services/gr-rest-api/gr-rest-api';
+import {appContext} from '../../../services/app-context';
 
 const SUGGESTIONS_LIMIT = 15;
 const REF_PREFIX = 'refs/heads/';
@@ -42,7 +42,6 @@
   $: {
     repoInput: GrLabeledAutocomplete;
     branchInput: GrLabeledAutocomplete;
-    restAPI: RestApiService & Element;
   };
 }
 @customElement('gr-repo-branch-picker')
@@ -68,6 +67,8 @@
   @property({type: Object})
   _repoQuery?: AutocompleteQuery;
 
+  private readonly restApiService = appContext.restApiService;
+
   constructor() {
     super();
     this._query = input => this._getRepoBranchesSuggestions(input);
@@ -95,13 +96,13 @@
     if (input.startsWith(REF_PREFIX)) {
       input = input.substring(REF_PREFIX.length);
     }
-    return this.$.restAPI
+    return this.restApiService
       .getRepoBranches(input, this.repo, SUGGESTIONS_LIMIT)
       .then(res => this._branchResponseToSuggestions(res));
   }
 
   _getRepoSuggestions(input: string) {
-    return this.$.restAPI
+    return this.restApiService
       .getRepos(input, SUGGESTIONS_LIMIT)
       .then(res => this._repoResponseToSuggestions(res));
   }
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_html.ts b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_html.ts
index 934b3cb..3e551b6 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_html.ts
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_html.ts
@@ -49,5 +49,4 @@
     >
     </gr-labeled-autocomplete>
   </div>
-  <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
 `;
diff --git a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.js b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.js
index 1d8ae98..8fbc639 100644
--- a/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-repo-branch-picker/gr-repo-branch-picker_test.js
@@ -29,7 +29,7 @@
 
   suite('_getRepoSuggestions', () => {
     setup(() => {
-      sinon.stub(element.$.restAPI, 'getRepos')
+      sinon.stub(element.restApiService, 'getRepos')
           .returns(Promise.resolve([
             {
               id: 'plugins%2Favatars-external',
@@ -50,7 +50,7 @@
     test('converts to suggestion objects', () => {
       const input = 'plugins/avatars';
       return element._getRepoSuggestions(input).then(suggestions => {
-        assert.isTrue(element.$.restAPI.getRepos.calledWith(input));
+        assert.isTrue(element.restApiService.getRepos.calledWith(input));
         const unencodedNames = [
           'plugins/avatars-external',
           'plugins/avatars-gravatar',
@@ -65,7 +65,7 @@
 
   suite('_getRepoBranchesSuggestions', () => {
     setup(() => {
-      sinon.stub(element.$.restAPI, 'getRepoBranches')
+      sinon.stub(element.restApiService, 'getRepoBranches')
           .returns(Promise.resolve([
             {ref: 'refs/heads/stable-2.10'},
             {ref: 'refs/heads/stable-2.11'},
@@ -82,7 +82,7 @@
       element.repo = repo;
       return element._getRepoBranchesSuggestions(branchInput)
           .then(suggestions => {
-            assert.isTrue(element.$.restAPI.getRepoBranches.calledWith(
+            assert.isTrue(element.restApiService.getRepoBranches.calledWith(
                 branchInput, repo, 15));
             const refNames = [
               'stable-2.10',
@@ -103,7 +103,7 @@
       element.repo = repo;
       return element._getRepoBranchesSuggestions(branchInput)
           .then(suggestions => {
-            assert.isTrue(element.$.restAPI.getRepoBranches.calledWith(
+            assert.isTrue(element.restApiService.getRepoBranches.calledWith(
                 'stable-2.1', repo, 15));
           });
     });
@@ -111,12 +111,12 @@
     test('does not query when repo is unset', () => element
         ._getRepoBranchesSuggestions('')
         .then(() => {
-          assert.isFalse(element.$.restAPI.getRepoBranches.called);
+          assert.isFalse(element.restApiService.getRepoBranches.called);
           element.repo = 'gerrit';
           return element._getRepoBranchesSuggestions('');
         })
         .then(() => {
-          assert.isTrue(element.$.restAPI.getRepoBranches.called);
+          assert.isTrue(element.restApiService.getRepoBranches.called);
         }));
   });
 });
diff --git a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
index 7c40b7a..ac48ea0 100644
--- a/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-email-suggestions-provider/gr-email-suggestions-provider_test.js
@@ -18,11 +18,7 @@
 import '../../test/common-test-setup-karma.js';
 import '../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.js';
 import {GrEmailSuggestionsProvider} from './gr-email-suggestions-provider.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
-<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
-`);
+import {appContext} from '../../services/app-context.js';
 
 suite('GrEmailSuggestionsProvider tests', () => {
   let restAPI;
@@ -40,7 +36,7 @@
     stub('gr-rest-api-interface', {
       getConfig() { return Promise.resolve({}); },
     });
-    restAPI = basicFixture.instantiate();
+    restAPI = appContext.restApiService;
     provider = new GrEmailSuggestionsProvider(restAPI);
   });
 
diff --git a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
index 0939f76..f03195d 100644
--- a/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-group-suggestions-provider/gr-group-suggestions-provider_test.js
@@ -18,11 +18,7 @@
 import '../../test/common-test-setup-karma.js';
 import '../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.js';
 import {GrGroupSuggestionsProvider} from './gr-group-suggestions-provider.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
-<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
-`);
+import {appContext} from '../../services/app-context.js';
 
 suite('GrGroupSuggestionsProvider tests', () => {
   let restAPI;
@@ -41,7 +37,7 @@
     stub('gr-rest-api-interface', {
       getConfig() { return Promise.resolve({}); },
     });
-    restAPI = basicFixture.instantiate();
+    restAPI = appContext.restApiService;
     provider = new GrGroupSuggestionsProvider(restAPI);
   });
 
diff --git a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
index fe13c1c..2aea699 100644
--- a/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
+++ b/polygerrit-ui/app/scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider_test.js
@@ -18,11 +18,7 @@
 import '../../test/common-test-setup-karma.js';
 import '../../elements/shared/gr-rest-api-interface/gr-rest-api-interface.js';
 import {GrReviewerSuggestionsProvider, SUGGESTIONS_PROVIDERS_USERS_TYPES} from './gr-reviewer-suggestions-provider.js';
-import {html} from '@polymer/polymer/lib/utils/html-tag.js';
-
-const basicFixture = fixtureFromTemplate(html`
-<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
-`);
+import {appContext} from '../../services/app-context.js';
 
 suite('GrReviewerSuggestionsProvider tests', () => {
   let _nextAccountId = 0;
@@ -77,7 +73,7 @@
       getConfig() { return Promise.resolve({}); },
     });
 
-    restAPI = basicFixture.instantiate();
+    restAPI = appContext.restApiService;
     change = {
       _number: 42,
       owner,