From a8a52084c93d73743f540422e82dc3b317191614 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Mon, 10 Sep 2018 20:33:26 -0700 Subject: [PATCH 1/8] Added addToFeatureService function --- .../src/index.ts | 1 + .../src/update.ts | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 packages/arcgis-rest-feature-service-admin/src/update.ts diff --git a/packages/arcgis-rest-feature-service-admin/src/index.ts b/packages/arcgis-rest-feature-service-admin/src/index.ts index c6262006e3..b034c901aa 100644 --- a/packages/arcgis-rest-feature-service-admin/src/index.ts +++ b/packages/arcgis-rest-feature-service-admin/src/index.ts @@ -1 +1,2 @@ export * from "./create"; +export * from "./update"; diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/update.ts new file mode 100644 index 0000000000..63644d3a3c --- /dev/null +++ b/packages/arcgis-rest-feature-service-admin/src/update.ts @@ -0,0 +1,83 @@ +/* Copyright (c) 2018 Environmental Systems Research Institute, Inc. + * Apache-2.0 */ + +import { request } from "@esri/arcgis-rest-request"; +import { IUserRequestOptions } from "@esri/arcgis-rest-auth"; +import { ILayer, ITable } from "@esri/arcgis-rest-common-types"; + +export interface IAddToFeatureServiceRequestOptions + extends IUserRequestOptions { + /** + * Feature service URL + */ + url: string; + /** + * Layers to add + */ + layers?: ILayer[]; + /** + * Tables to add + */ + tables?: ITable[]; +} + +export interface IAddToFeatureServiceItemSummary { + name: string; + id: number; +} + +export interface IAddToFeatureServiceSuccessResult { + layers?: IAddToFeatureServiceItemSummary[]; + tables?: IAddToFeatureServiceItemSummary[]; + success: boolean; +} + +export interface IAddToFeatureServiceFailureResult { + error: { + code: number; + message: string; + details: string[]; + }; +} + +/** + * Add layer(s) and/or table(s) to a hosted feature service. + * + * ```js + * import { addLayerToFeatureService } from '@esri/arcgis-rest-items'; + * + * addLayerToFeatureService({ + * authentication: userSession, + * url: serviceurl, + * layers: [], + * tables: [] + * }); + * ``` + * + * @param requestOptions - Options for the request + * @returns A Promise that resolves with service details once the service has been created + */ +export function addToFeatureService( + requestOptions: IAddToFeatureServiceRequestOptions +): Promise< + IAddToFeatureServiceSuccessResult | IAddToFeatureServiceFailureResult +> { + const url = + requestOptions.url.replace("/rest/services", "/rest/admin/services") + + "/addToDefinition"; + + requestOptions.params = { + addToDefinition: {}, + ...requestOptions.params + }; + + if (requestOptions.layers && requestOptions.layers.length > 0) { + requestOptions.params.addToDefinition.layers = requestOptions.layers; + } + + if (requestOptions.tables && requestOptions.tables.length > 0) { + requestOptions.params.addToDefinition.tables = requestOptions.tables; + } + + return request(url, requestOptions); +} From d03aeb9f68f8add4db464e302feb16aae34fbba9 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Tue, 11 Sep 2018 09:14:57 -0700 Subject: [PATCH 2/8] Added `name` parameter to ITable and ILayer --- packages/arcgis-rest-common-types/src/webmap.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/arcgis-rest-common-types/src/webmap.ts b/packages/arcgis-rest-common-types/src/webmap.ts index 8a191abb42..79fa49d0d1 100644 --- a/packages/arcgis-rest-common-types/src/webmap.ts +++ b/packages/arcgis-rest-common-types/src/webmap.ts @@ -326,6 +326,8 @@ export interface IPresentation { * Root element in the web map specifying an array of table objects. */ export interface ITable { + /** Table name */ + name?: string; /** A comma-separated string listing which editing operations are allowed on an editable feature service. Available operations include: 'Create', 'Delete', 'Query', 'Update', and 'Editing'. */ capabilities?: string; /** Object indicating the definitionEditor used as a layer's interactive filter. */ @@ -555,6 +557,8 @@ export interface IBaseMap { export interface ILayer { /** A unique identifying string for the layer. */ id: any; + /** Layer name */ + name?: string; /** Optional string containing the item ID of the service if it's registered on ArcGIS Online or your organization's portal. */ itemId?: string; /** Indicates the layer type */ From a0111caee09e2d516652288b4d3edf877ca17db3 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Tue, 11 Sep 2018 11:28:26 -0700 Subject: [PATCH 3/8] Minor label change --- packages/arcgis-rest-feature-service-admin/test/create.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/arcgis-rest-feature-service-admin/test/create.test.ts b/packages/arcgis-rest-feature-service-admin/test/create.test.ts index 1f7c79f739..cee15c1a67 100644 --- a/packages/arcgis-rest-feature-service-admin/test/create.test.ts +++ b/packages/arcgis-rest-feature-service-admin/test/create.test.ts @@ -18,7 +18,7 @@ import { UserSession } from "@esri/arcgis-rest-auth"; import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils"; import { encodeParam } from "@esri/arcgis-rest-request"; -describe("search", () => { +describe("create feature service", () => { afterEach(fetchMock.restore); describe("Authenticated methods", () => { From 83b7e22f28b0743e5146bbc144683e2227af0140 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Tue, 11 Sep 2018 11:31:17 -0700 Subject: [PATCH 4/8] Added unit tests --- .../src/update.ts | 14 +- .../test/mocks/service.ts | 53 +++ .../test/update.test.ts | 368 ++++++++++++++++++ 3 files changed, 433 insertions(+), 2 deletions(-) create mode 100644 packages/arcgis-rest-feature-service-admin/test/update.test.ts diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/update.ts index 63644d3a3c..1fc28e8d45 100644 --- a/packages/arcgis-rest-feature-service-admin/src/update.ts +++ b/packages/arcgis-rest-feature-service-admin/src/update.ts @@ -23,7 +23,7 @@ export interface IAddToFeatureServiceRequestOptions export interface IAddToFeatureServiceItemSummary { name: string; - id: number; + id: any; } export interface IAddToFeatureServiceSuccessResult { @@ -79,5 +79,15 @@ export function addToFeatureService( requestOptions.params.addToDefinition.tables = requestOptions.tables; } - return request(url, requestOptions); + return new Promise(resolve => { + request(url, requestOptions).then( + response => { + resolve(response); + }, + response => { + // We're not interested in the full ArcGISRequestError response, nor having an exception thrown + resolve(response.response); + } + ); + }); } diff --git a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts index c508b6fed3..d33e1e9ff2 100644 --- a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts +++ b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts @@ -2,6 +2,10 @@ * Apache-2.0 */ import { ICreateServiceResult } from "../../src/create"; +import { + IAddToFeatureServiceSuccessResult, + IAddToFeatureServiceFailureResult +} from "../../src/update"; export const FeatureServiceSuccessResponse: ICreateServiceResult = { encodedServiceURL: @@ -19,3 +23,52 @@ export const FeatureServiceSuccessResponse: ICreateServiceResult = { export const FeatureServiceFailResponse: any = { success: false }; + +export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToFeatureServiceSuccessResult = { + layers: [ + { + name: "Fred", + id: "1899" + }, + { + name: "Ginger", + id: "1911" + } + ], + success: true +}; +export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToFeatureServiceSuccessResult = { + tables: [ + { + name: "Fayard", + id: "1914" + }, + { + name: "Harold", + id: "1921" + } + ], + success: true +}; +export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToFeatureServiceSuccessResult = { + layers: [ + { + name: "Cyd", + id: "1922" + } + ], + tables: [ + { + name: "Gene", + id: "1912" + } + ], + success: true +}; +export const AddToFeatureServiceFailResponse: IAddToFeatureServiceFailureResult = { + error: { + code: 400, + message: "Unable to add feature service definition.", + details: ["Object reference not set to an instance of an object."] + } +}; diff --git a/packages/arcgis-rest-feature-service-admin/test/update.test.ts b/packages/arcgis-rest-feature-service-admin/test/update.test.ts new file mode 100644 index 0000000000..9e5abd9d2c --- /dev/null +++ b/packages/arcgis-rest-feature-service-admin/test/update.test.ts @@ -0,0 +1,368 @@ +/* Copyright (c) 2018 Environmental Systems Research Institute, Inc. + * Apache-2.0 */ + +import * as fetchMock from "fetch-mock"; + +import { addToFeatureService } from "../src/update"; + +import { + AddToFeatureServiceSuccessResponseFredAndGinger, + AddToFeatureServiceSuccessResponseFayardAndHarold, + AddToFeatureServiceSuccessResponseCydAndGene, + AddToFeatureServiceFailResponse +} from "./mocks/service"; + +import { UserSession } from "@esri/arcgis-rest-auth"; +import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils"; +import { encodeParam } from "@esri/arcgis-rest-request"; +import { ILayer, ITable } from "@esri/arcgis-rest-common-types"; + +describe("add to feature service", () => { + afterEach(fetchMock.restore); + + describe("Authenticated methods", () => { + // setup a UserSession to use in all these tests + const MOCK_USER_SESSION = new UserSession({ + clientId: "clientId", + redirectUri: "https://example-app.com/redirect-uri", + token: "fake-token", + tokenExpires: TOMORROW, + refreshToken: "refreshToken", + refreshTokenExpires: TOMORROW, + refreshTokenTTL: 1440, + username: "casey", + password: "123456", + portal: "https://myorg.maps.arcgis.com/sharing/rest" + }); + + const MOCK_USER_REQOPTS = { + authentication: MOCK_USER_SESSION + }; + + const layerDescriptionFred: ILayer = { + name: "Fred", + id: "1899", + layerType: "Feature Layer" + }; + + const layerDescriptionGinger: ILayer = { + name: "Ginger", + id: "1911", + layerType: "Feature Layer" + }; + + const layerDescriptionCyd: ILayer = { + name: "Cyd", + id: "1922", + layerType: "Feature Layer" + }; + + const layerDescriptionFail: ILayer = { + name: "", + id: "", + layerType: "Feature Layer" + }; + + const tableDescriptionFayard: ITable = { + name: "Fayard", + id: "1914" + }; + + const tableDescriptionHarold: ITable = { + name: "Harold", + id: "1921" + }; + + const tableDescriptionGene: ITable = { + name: "Gene", + id: "1912" + }; + + const tableDescriptionFail: ITable = { + name: "", + id: "" + }; + + it("should add a pair of layers", done => { + fetchMock.once("*", AddToFeatureServiceSuccessResponseFredAndGinger); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + layers: [layerDescriptionFred, layerDescriptionGinger], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ + layers: [layerDescriptionFred, layerDescriptionGinger] + }) + ) + ); + + // Check response + expect(response).toEqual( + AddToFeatureServiceSuccessResponseFredAndGinger + ); + + done(); + }, + () => { + fail(); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + + it("should add a pair of tables", done => { + fetchMock.once("*", AddToFeatureServiceSuccessResponseFayardAndHarold); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + tables: [tableDescriptionFayard, tableDescriptionHarold], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ + tables: [tableDescriptionFayard, tableDescriptionHarold] + }) + ) + ); + + // Check response + expect(response).toEqual( + AddToFeatureServiceSuccessResponseFayardAndHarold + ); + + done(); + }, + () => { + fail(); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + + it("should add a layer and a table", done => { + fetchMock.once("*", AddToFeatureServiceSuccessResponseCydAndGene); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + layers: [layerDescriptionCyd], + tables: [tableDescriptionGene], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ + layers: [layerDescriptionCyd], + tables: [tableDescriptionGene] + }) + ) + ); + + // Check response + expect(response).toEqual( + AddToFeatureServiceSuccessResponseCydAndGene + ); + + done(); + }, + () => { + fail(); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + + it("should fail to add a bad layer", done => { + fetchMock.once("*", AddToFeatureServiceFailResponse); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + layers: [layerDescriptionFail], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ layers: [layerDescriptionFail] }) + ) + ); + + // Check response + expect(response).toEqual(AddToFeatureServiceFailResponse); + + done(); + }, + e => { + fail(e); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + + it("should fail to add a bad table", done => { + fetchMock.once("*", AddToFeatureServiceFailResponse); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + tables: [tableDescriptionFail], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ tables: [tableDescriptionFail] }) + ) + ); + + // Check response + expect(response).toEqual(AddToFeatureServiceFailResponse); + + done(); + }, + e => { + fail(e); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + + it("should fail to add a bad layer and a bad table", done => { + fetchMock.once("*", AddToFeatureServiceFailResponse); + + addToFeatureService({ + url: + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + layers: [layerDescriptionFail], + tables: [tableDescriptionFail], + ...MOCK_USER_REQOPTS + }) + .then( + response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall( + "*" + ); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ + layers: [layerDescriptionFail], + tables: [tableDescriptionFail] + }) + ) + ); + + // Check response + expect(response).toEqual(AddToFeatureServiceFailResponse); + + done(); + }, + e => { + fail(e); // call is supposed to succeed + } + ) + .catch(e => { + fail(e); + }); + }); + }); // auth requests +}); From be078d4c92d81dba3bee7ad813b78a24f8aa8463 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Wed, 12 Sep 2018 13:36:16 -0700 Subject: [PATCH 5/8] Renamed add to feature service to match #46 https://github.com/Esri/arcgis-rest-js/pull/317#discussion_r216847531 --- .../src/update.ts | 36 ++++---- .../test/mocks/service.ts | 12 +-- .../test/update.test.ts | 84 ++++++++++--------- 3 files changed, 67 insertions(+), 65 deletions(-) diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/update.ts index 1fc28e8d45..afa1399bd0 100644 --- a/packages/arcgis-rest-feature-service-admin/src/update.ts +++ b/packages/arcgis-rest-feature-service-admin/src/update.ts @@ -5,12 +5,8 @@ import { request } from "@esri/arcgis-rest-request"; import { IUserRequestOptions } from "@esri/arcgis-rest-auth"; import { ILayer, ITable } from "@esri/arcgis-rest-common-types"; -export interface IAddToFeatureServiceRequestOptions +export interface IAddToServiceDefinitionRequestOptions extends IUserRequestOptions { - /** - * Feature service URL - */ - url: string; /** * Layers to add */ @@ -21,18 +17,18 @@ export interface IAddToFeatureServiceRequestOptions tables?: ITable[]; } -export interface IAddToFeatureServiceItemSummary { +export interface IAddToServiceDefinitionItemSummary { name: string; id: any; } -export interface IAddToFeatureServiceSuccessResult { - layers?: IAddToFeatureServiceItemSummary[]; - tables?: IAddToFeatureServiceItemSummary[]; +export interface IAddToServiceDefinitionSuccessResult { + layers?: IAddToServiceDefinitionItemSummary[]; + tables?: IAddToServiceDefinitionItemSummary[]; success: boolean; } -export interface IAddToFeatureServiceFailureResult { +export interface IAddToServiceDefinitionFailureResult { error: { code: number; message: string; @@ -44,27 +40,27 @@ export interface IAddToFeatureServiceFailureResult { * Add layer(s) and/or table(s) to a hosted feature service. * * ```js - * import { addLayerToFeatureService } from '@esri/arcgis-rest-items'; + * import { addToServiceDefinition } from '@esri/arcgis-rest-feature-service-admin'; * - * addLayerToFeatureService({ + * addToServiceDefinition(serviceurl, { * authentication: userSession, - * url: serviceurl, * layers: [], * tables: [] * }); * ``` * + * @param url - URL of feature service * @param requestOptions - Options for the request * @returns A Promise that resolves with service details once the service has been created */ -export function addToFeatureService( - requestOptions: IAddToFeatureServiceRequestOptions +export function addToServiceDefinition( + url: string, + requestOptions: IAddToServiceDefinitionRequestOptions ): Promise< - IAddToFeatureServiceSuccessResult | IAddToFeatureServiceFailureResult + IAddToServiceDefinitionSuccessResult | IAddToServiceDefinitionFailureResult > { - const url = - requestOptions.url.replace("/rest/services", "/rest/admin/services") + - "/addToDefinition"; + const adminUrl = + url.replace("/rest/services", "/rest/admin/services") + "/addToDefinition"; requestOptions.params = { addToDefinition: {}, @@ -80,7 +76,7 @@ export function addToFeatureService( } return new Promise(resolve => { - request(url, requestOptions).then( + request(adminUrl, requestOptions).then( response => { resolve(response); }, diff --git a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts index d33e1e9ff2..ea18066cdc 100644 --- a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts +++ b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts @@ -3,8 +3,8 @@ import { ICreateServiceResult } from "../../src/create"; import { - IAddToFeatureServiceSuccessResult, - IAddToFeatureServiceFailureResult + IAddToServiceDefinitionSuccessResult, + IAddToServiceDefinitionFailureResult } from "../../src/update"; export const FeatureServiceSuccessResponse: ICreateServiceResult = { @@ -24,7 +24,7 @@ export const FeatureServiceFailResponse: any = { success: false }; -export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToFeatureServiceSuccessResult = { +export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToServiceDefinitionSuccessResult = { layers: [ { name: "Fred", @@ -37,7 +37,7 @@ export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToFeatureServi ], success: true }; -export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToFeatureServiceSuccessResult = { +export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToServiceDefinitionSuccessResult = { tables: [ { name: "Fayard", @@ -50,7 +50,7 @@ export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToFeatureSer ], success: true }; -export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToFeatureServiceSuccessResult = { +export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToServiceDefinitionSuccessResult = { layers: [ { name: "Cyd", @@ -65,7 +65,7 @@ export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToFeatureServiceS ], success: true }; -export const AddToFeatureServiceFailResponse: IAddToFeatureServiceFailureResult = { +export const AddToFeatureServiceFailResponse: IAddToServiceDefinitionFailureResult = { error: { code: 400, message: "Unable to add feature service definition.", diff --git a/packages/arcgis-rest-feature-service-admin/test/update.test.ts b/packages/arcgis-rest-feature-service-admin/test/update.test.ts index 9e5abd9d2c..5c0fe20b2b 100644 --- a/packages/arcgis-rest-feature-service-admin/test/update.test.ts +++ b/packages/arcgis-rest-feature-service-admin/test/update.test.ts @@ -3,7 +3,7 @@ import * as fetchMock from "fetch-mock"; -import { addToFeatureService } from "../src/update"; +import { addToServiceDefinition } from "../src/update"; import { AddToFeatureServiceSuccessResponseFredAndGinger, @@ -86,12 +86,13 @@ describe("add to feature service", () => { it("should add a pair of layers", done => { fetchMock.once("*", AddToFeatureServiceSuccessResponseFredAndGinger); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - layers: [layerDescriptionFred, layerDescriptionGinger], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + layers: [layerDescriptionFred, layerDescriptionGinger], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call @@ -134,12 +135,13 @@ describe("add to feature service", () => { it("should add a pair of tables", done => { fetchMock.once("*", AddToFeatureServiceSuccessResponseFayardAndHarold); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - tables: [tableDescriptionFayard, tableDescriptionHarold], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + tables: [tableDescriptionFayard, tableDescriptionHarold], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call @@ -182,13 +184,14 @@ describe("add to feature service", () => { it("should add a layer and a table", done => { fetchMock.once("*", AddToFeatureServiceSuccessResponseCydAndGene); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - layers: [layerDescriptionCyd], - tables: [tableDescriptionGene], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + layers: [layerDescriptionCyd], + tables: [tableDescriptionGene], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call @@ -232,12 +235,13 @@ describe("add to feature service", () => { it("should fail to add a bad layer", done => { fetchMock.once("*", AddToFeatureServiceFailResponse); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - layers: [layerDescriptionFail], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + layers: [layerDescriptionFail], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call @@ -276,12 +280,13 @@ describe("add to feature service", () => { it("should fail to add a bad table", done => { fetchMock.once("*", AddToFeatureServiceFailResponse); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - tables: [tableDescriptionFail], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + tables: [tableDescriptionFail], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call @@ -320,13 +325,14 @@ describe("add to feature service", () => { it("should fail to add a bad layer and a bad table", done => { fetchMock.once("*", AddToFeatureServiceFailResponse); - addToFeatureService({ - url: - "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", - layers: [layerDescriptionFail], - tables: [tableDescriptionFail], - ...MOCK_USER_REQOPTS - }) + addToServiceDefinition( + "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", + { + layers: [layerDescriptionFail], + tables: [tableDescriptionFail], + ...MOCK_USER_REQOPTS + } + ) .then( response => { // Check service call From 49f090235c87a6784b2f3ee0021357273f60a404 Mon Sep 17 00:00:00 2001 From: Mike Tschudi Date: Wed, 12 Sep 2018 15:22:18 -0700 Subject: [PATCH 6/8] Reworked function args for https://github.com/Esri/arcgis-rest-js/pull/317#discussion_r216850450 --- .../src/update.ts | 9 +++++---- .../test/update.test.ts | 18 +++++++++--------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/update.ts index afa1399bd0..ad72c46e57 100644 --- a/packages/arcgis-rest-feature-service-admin/src/update.ts +++ b/packages/arcgis-rest-feature-service-admin/src/update.ts @@ -51,7 +51,8 @@ export interface IAddToServiceDefinitionFailureResult { * * @param url - URL of feature service * @param requestOptions - Options for the request - * @returns A Promise that resolves with service details once the service has been created + * @returns A Promise that resolves with service layer and/or table details once the definition + * has been updated */ export function addToServiceDefinition( url: string, @@ -75,14 +76,14 @@ export function addToServiceDefinition( requestOptions.params.addToDefinition.tables = requestOptions.tables; } - return new Promise(resolve => { + return new Promise((resolve, reject) => { request(adminUrl, requestOptions).then( response => { resolve(response); }, response => { - // We're not interested in the full ArcGISRequestError response, nor having an exception thrown - resolve(response.response); + // We're not interested in the full ArcGISRequestError response + reject(response.response); } ); }); diff --git a/packages/arcgis-rest-feature-service-admin/test/update.test.ts b/packages/arcgis-rest-feature-service-admin/test/update.test.ts index 5c0fe20b2b..c1b78ce7d6 100644 --- a/packages/arcgis-rest-feature-service-admin/test/update.test.ts +++ b/packages/arcgis-rest-feature-service-admin/test/update.test.ts @@ -243,6 +243,9 @@ describe("add to feature service", () => { } ) .then( + e => { + fail(e); // call is supposed to fail + }, response => { // Check service call expect(fetchMock.called()).toEqual(true); @@ -267,9 +270,6 @@ describe("add to feature service", () => { expect(response).toEqual(AddToFeatureServiceFailResponse); done(); - }, - e => { - fail(e); // call is supposed to succeed } ) .catch(e => { @@ -288,6 +288,9 @@ describe("add to feature service", () => { } ) .then( + e => { + fail(e); // call is supposed to fail + }, response => { // Check service call expect(fetchMock.called()).toEqual(true); @@ -312,9 +315,6 @@ describe("add to feature service", () => { expect(response).toEqual(AddToFeatureServiceFailResponse); done(); - }, - e => { - fail(e); // call is supposed to succeed } ) .catch(e => { @@ -334,6 +334,9 @@ describe("add to feature service", () => { } ) .then( + e => { + fail(e); // call is supposed to fail + }, response => { // Check service call expect(fetchMock.called()).toEqual(true); @@ -361,9 +364,6 @@ describe("add to feature service", () => { expect(response).toEqual(AddToFeatureServiceFailResponse); done(); - }, - e => { - fail(e); // call is supposed to succeed } ) .catch(e => { From 31e56db63fb7755d23deef729cfbac5b0df042a4 Mon Sep 17 00:00:00 2001 From: john gravois Date: Thu, 13 Sep 2018 09:22:06 -0700 Subject: [PATCH 7/8] just let request throw its own error --- .../src/update.ts | 26 +-- .../test/mocks/service.ts | 14 +- .../test/update.test.ts | 220 +++++++----------- 3 files changed, 87 insertions(+), 173 deletions(-) diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/update.ts index ad72c46e57..4f92fd3fd8 100644 --- a/packages/arcgis-rest-feature-service-admin/src/update.ts +++ b/packages/arcgis-rest-feature-service-admin/src/update.ts @@ -22,20 +22,12 @@ export interface IAddToServiceDefinitionItemSummary { id: any; } -export interface IAddToServiceDefinitionSuccessResult { +export interface IAddToServiceDefinitionResult { layers?: IAddToServiceDefinitionItemSummary[]; tables?: IAddToServiceDefinitionItemSummary[]; success: boolean; } -export interface IAddToServiceDefinitionFailureResult { - error: { - code: number; - message: string; - details: string[]; - }; -} - /** * Add layer(s) and/or table(s) to a hosted feature service. * @@ -57,9 +49,7 @@ export interface IAddToServiceDefinitionFailureResult { export function addToServiceDefinition( url: string, requestOptions: IAddToServiceDefinitionRequestOptions -): Promise< - IAddToServiceDefinitionSuccessResult | IAddToServiceDefinitionFailureResult -> { +): Promise { const adminUrl = url.replace("/rest/services", "/rest/admin/services") + "/addToDefinition"; @@ -76,15 +66,5 @@ export function addToServiceDefinition( requestOptions.params.addToDefinition.tables = requestOptions.tables; } - return new Promise((resolve, reject) => { - request(adminUrl, requestOptions).then( - response => { - resolve(response); - }, - response => { - // We're not interested in the full ArcGISRequestError response - reject(response.response); - } - ); - }); + return request(adminUrl, requestOptions); } diff --git a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts index ea18066cdc..8d5e3577e4 100644 --- a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts +++ b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts @@ -2,10 +2,7 @@ * Apache-2.0 */ import { ICreateServiceResult } from "../../src/create"; -import { - IAddToServiceDefinitionSuccessResult, - IAddToServiceDefinitionFailureResult -} from "../../src/update"; +import { IAddToServiceDefinitionResult } from "../../src/update"; export const FeatureServiceSuccessResponse: ICreateServiceResult = { encodedServiceURL: @@ -24,7 +21,7 @@ export const FeatureServiceFailResponse: any = { success: false }; -export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToServiceDefinitionSuccessResult = { +export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToServiceDefinitionResult = { layers: [ { name: "Fred", @@ -37,7 +34,7 @@ export const AddToFeatureServiceSuccessResponseFredAndGinger: IAddToServiceDefin ], success: true }; -export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToServiceDefinitionSuccessResult = { +export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToServiceDefinitionResult = { tables: [ { name: "Fayard", @@ -50,7 +47,7 @@ export const AddToFeatureServiceSuccessResponseFayardAndHarold: IAddToServiceDef ], success: true }; -export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToServiceDefinitionSuccessResult = { +export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToServiceDefinitionResult = { layers: [ { name: "Cyd", @@ -65,7 +62,8 @@ export const AddToFeatureServiceSuccessResponseCydAndGene: IAddToServiceDefiniti ], success: true }; -export const AddToFeatureServiceFailResponse: IAddToServiceDefinitionFailureResult = { + +export const AddToFeatureServiceError: any = { error: { code: 400, message: "Unable to add feature service definition.", diff --git a/packages/arcgis-rest-feature-service-admin/test/update.test.ts b/packages/arcgis-rest-feature-service-admin/test/update.test.ts index c1b78ce7d6..17b3f929fe 100644 --- a/packages/arcgis-rest-feature-service-admin/test/update.test.ts +++ b/packages/arcgis-rest-feature-service-admin/test/update.test.ts @@ -9,12 +9,12 @@ import { AddToFeatureServiceSuccessResponseFredAndGinger, AddToFeatureServiceSuccessResponseFayardAndHarold, AddToFeatureServiceSuccessResponseCydAndGene, - AddToFeatureServiceFailResponse + AddToFeatureServiceError } from "./mocks/service"; import { UserSession } from "@esri/arcgis-rest-auth"; import { TOMORROW } from "@esri/arcgis-rest-auth/test/utils"; -import { encodeParam } from "@esri/arcgis-rest-request"; +import { encodeParam, ErrorTypes } from "@esri/arcgis-rest-request"; import { ILayer, ITable } from "@esri/arcgis-rest-common-types"; describe("add to feature service", () => { @@ -192,48 +192,40 @@ describe("add to feature service", () => { ...MOCK_USER_REQOPTS } ) - .then( - response => { - // Check service call - expect(fetchMock.called()).toEqual(true); - const [url, options]: [string, RequestInit] = fetchMock.lastCall( - "*" - ); - - expect(url).toEqual( - "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" - ); - expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain( - encodeParam( - "addToDefinition", - JSON.stringify({ - layers: [layerDescriptionCyd], - tables: [tableDescriptionGene] - }) - ) - ); - - // Check response - expect(response).toEqual( - AddToFeatureServiceSuccessResponseCydAndGene - ); - - done(); - }, - () => { - fail(); // call is supposed to succeed - } - ) + .then(response => { + // Check service call + expect(fetchMock.called()).toEqual(true); + const [url, options]: [string, RequestInit] = fetchMock.lastCall("*"); + + expect(url).toEqual( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + expect(options.method).toBe("POST"); + expect(options.body).toContain("f=json"); + expect(options.body).toContain(encodeParam("token", "fake-token")); + expect(options.body).toContain( + encodeParam( + "addToDefinition", + JSON.stringify({ + layers: [layerDescriptionCyd], + tables: [tableDescriptionGene] + }) + ) + ); + + // Check response + expect(response).toEqual( + AddToFeatureServiceSuccessResponseCydAndGene + ); + done(); + }) .catch(e => { fail(e); }); }); it("should fail to add a bad layer", done => { - fetchMock.once("*", AddToFeatureServiceFailResponse); + fetchMock.once("*", AddToFeatureServiceError); addToServiceDefinition( "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", @@ -241,44 +233,26 @@ describe("add to feature service", () => { layers: [layerDescriptionFail], ...MOCK_USER_REQOPTS } - ) - .then( - e => { - fail(e); // call is supposed to fail - }, - response => { - // Check service call - expect(fetchMock.called()).toEqual(true); - const [url, options]: [string, RequestInit] = fetchMock.lastCall( - "*" - ); - - expect(url).toEqual( - "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" - ); - expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain( - encodeParam( - "addToDefinition", - JSON.stringify({ layers: [layerDescriptionFail] }) - ) - ); - - // Check response - expect(response).toEqual(AddToFeatureServiceFailResponse); - - done(); - } - ) - .catch(e => { - fail(e); + ).catch(error => { + expect(error.name).toBe(ErrorTypes.ArcGISRequestError); + expect(error.message).toBe( + "400: Unable to add feature service definition." + ); + expect(error instanceof Error).toBeTruthy(); + expect(error.url).toBe( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + // params added internally aren't surfaced in the error + expect(error.options.params.addToDefinition).toEqual({ + layers: [layerDescriptionFail] }); + expect(error.options.httpMethod).toEqual("POST"); + done(); + }); }); it("should fail to add a bad table", done => { - fetchMock.once("*", AddToFeatureServiceFailResponse); + fetchMock.once("*", AddToFeatureServiceError); addToServiceDefinition( "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", @@ -286,44 +260,26 @@ describe("add to feature service", () => { tables: [tableDescriptionFail], ...MOCK_USER_REQOPTS } - ) - .then( - e => { - fail(e); // call is supposed to fail - }, - response => { - // Check service call - expect(fetchMock.called()).toEqual(true); - const [url, options]: [string, RequestInit] = fetchMock.lastCall( - "*" - ); - - expect(url).toEqual( - "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" - ); - expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain( - encodeParam( - "addToDefinition", - JSON.stringify({ tables: [tableDescriptionFail] }) - ) - ); - - // Check response - expect(response).toEqual(AddToFeatureServiceFailResponse); - - done(); - } - ) - .catch(e => { - fail(e); + ).catch(error => { + expect(error.name).toBe(ErrorTypes.ArcGISRequestError); + expect(error.message).toBe( + "400: Unable to add feature service definition." + ); + expect(error instanceof Error).toBeTruthy(); + expect(error.url).toBe( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + // params added internally aren't surfaced in the error + expect(error.options.params.addToDefinition).toEqual({ + tables: [tableDescriptionFail] }); + expect(error.options.httpMethod).toEqual("POST"); + done(); + }); }); it("should fail to add a bad layer and a bad table", done => { - fetchMock.once("*", AddToFeatureServiceFailResponse); + fetchMock.once("*", AddToFeatureServiceError); addToServiceDefinition( "https://services1.arcgis.com/ORG/arcgis/rest/services/FEATURE_SERVICE/FeatureServer", @@ -332,43 +288,23 @@ describe("add to feature service", () => { tables: [tableDescriptionFail], ...MOCK_USER_REQOPTS } - ) - .then( - e => { - fail(e); // call is supposed to fail - }, - response => { - // Check service call - expect(fetchMock.called()).toEqual(true); - const [url, options]: [string, RequestInit] = fetchMock.lastCall( - "*" - ); - - expect(url).toEqual( - "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" - ); - expect(options.method).toBe("POST"); - expect(options.body).toContain("f=json"); - expect(options.body).toContain(encodeParam("token", "fake-token")); - expect(options.body).toContain( - encodeParam( - "addToDefinition", - JSON.stringify({ - layers: [layerDescriptionFail], - tables: [tableDescriptionFail] - }) - ) - ); - - // Check response - expect(response).toEqual(AddToFeatureServiceFailResponse); - - done(); - } - ) - .catch(e => { - fail(e); + ).catch(error => { + expect(error.name).toBe(ErrorTypes.ArcGISRequestError); + expect(error.message).toBe( + "400: Unable to add feature service definition." + ); + expect(error instanceof Error).toBeTruthy(); + expect(error.url).toBe( + "https://services1.arcgis.com/ORG/arcgis/rest/admin/services/FEATURE_SERVICE/FeatureServer/addToDefinition" + ); + // params added internally aren't surfaced in the error + expect(error.options.params.addToDefinition).toEqual({ + tables: [tableDescriptionFail], + layers: [layerDescriptionFail] }); + expect(error.options.httpMethod).toEqual("POST"); + done(); + }); }); }); // auth requests }); From 61522f459f38f7e8cd66d711ffd8ee15a423ee1c Mon Sep 17 00:00:00 2001 From: john gravois Date: Thu, 13 Sep 2018 09:23:36 -0700 Subject: [PATCH 8/8] rename files to match new method name --- .../src/{update.ts => addTo.ts} | 0 packages/arcgis-rest-feature-service-admin/src/index.ts | 2 +- .../test/{update.test.ts => addTo.test.ts} | 2 +- .../arcgis-rest-feature-service-admin/test/mocks/service.ts | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename packages/arcgis-rest-feature-service-admin/src/{update.ts => addTo.ts} (100%) rename packages/arcgis-rest-feature-service-admin/test/{update.test.ts => addTo.test.ts} (99%) diff --git a/packages/arcgis-rest-feature-service-admin/src/update.ts b/packages/arcgis-rest-feature-service-admin/src/addTo.ts similarity index 100% rename from packages/arcgis-rest-feature-service-admin/src/update.ts rename to packages/arcgis-rest-feature-service-admin/src/addTo.ts diff --git a/packages/arcgis-rest-feature-service-admin/src/index.ts b/packages/arcgis-rest-feature-service-admin/src/index.ts index b034c901aa..1e283a24cf 100644 --- a/packages/arcgis-rest-feature-service-admin/src/index.ts +++ b/packages/arcgis-rest-feature-service-admin/src/index.ts @@ -1,2 +1,2 @@ export * from "./create"; -export * from "./update"; +export * from "./addTo"; diff --git a/packages/arcgis-rest-feature-service-admin/test/update.test.ts b/packages/arcgis-rest-feature-service-admin/test/addTo.test.ts similarity index 99% rename from packages/arcgis-rest-feature-service-admin/test/update.test.ts rename to packages/arcgis-rest-feature-service-admin/test/addTo.test.ts index 17b3f929fe..da0b518e2d 100644 --- a/packages/arcgis-rest-feature-service-admin/test/update.test.ts +++ b/packages/arcgis-rest-feature-service-admin/test/addTo.test.ts @@ -3,7 +3,7 @@ import * as fetchMock from "fetch-mock"; -import { addToServiceDefinition } from "../src/update"; +import { addToServiceDefinition } from "../src/addTo"; import { AddToFeatureServiceSuccessResponseFredAndGinger, diff --git a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts index 8d5e3577e4..ec2414be65 100644 --- a/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts +++ b/packages/arcgis-rest-feature-service-admin/test/mocks/service.ts @@ -2,7 +2,7 @@ * Apache-2.0 */ import { ICreateServiceResult } from "../../src/create"; -import { IAddToServiceDefinitionResult } from "../../src/update"; +import { IAddToServiceDefinitionResult } from "../../src/addTo"; export const FeatureServiceSuccessResponse: ICreateServiceResult = { encodedServiceURL: