diff --git a/README.md b/README.md
index 15049061b7..eac92c690e 100644
--- a/README.md
+++ b/README.md
@@ -70,6 +70,7 @@ Some useful commands include:
* [`@esri/arcgis-rest-geocoder`](./packages/arcgis-rest-geocoder) - Geocoding wrapper for `@esri/arcgis-rest-js`
* [`@esri/arcgis-rest-items`](./packages/arcgis-rest-items) - Methods for working with ArcGIS Online/Enterprise content.
* [`@esri/arcgis-rest-groups`](./packages/arcgis-rest-groups) - Methods for working with ArcGIS Online/Enterprise groups.
+* [`@esri/arcgis-rest-feature-service`](./packages/arcgis-rest-feature-service) - Functions for working with feature services
* [`@esri/arcgis-rest-common-types`](./packages/arcgis-rest-common-types) - Stores objects common across the ArcGIS API.
### Frequently Asked Questions
diff --git a/packages/arcgis-rest-common-types/src/index.ts b/packages/arcgis-rest-common-types/src/index.ts
index 08950cec95..38195451d8 100644
--- a/packages/arcgis-rest-common-types/src/index.ts
+++ b/packages/arcgis-rest-common-types/src/index.ts
@@ -45,7 +45,7 @@ export type ElipticArc = IArc;
*/
export interface IFeature {
geometry?: IGeometry;
- attributes?: any;
+ attributes: { [key: string]: any };
}
/**
diff --git a/packages/arcgis-rest-feature-service/README.md b/packages/arcgis-rest-feature-service/README.md
new file mode 100644
index 0000000000..68d46516a9
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/README.md
@@ -0,0 +1,67 @@
+[![npm version][npm-img]][npm-url]
+[![build status][travis-img]][travis-url]
+[![apache licensed](https://img.shields.io/badge/license-Apache-green.svg?style=flat-square)](https://raw.githubusercontent.com/Esri/arcgis-rest-js/master/LICENSE)
+
+[npm-img]: https://img.shields.io/npm/v/@esri/arcgis-rest-feature-service.svg?style=flat-square
+[npm-url]: https://www.npmjs.com/package/@esri/arcgis-rest-feature-service
+[travis-img]: https://img.shields.io/travis/Esri/arcgis-rest-js/master.svg?style=flat-square
+[travis-url]: https://travis-ci.org/Esri/arcgis-rest-js
+
+# @esri/arcgis-rest-feature-service
+
+> A module for working with ArcGIS feature services that runs in Node.js and modern browsers.
+
+### Example
+
+```bash
+npm install @esri/arcgis-rest-feature-service
+```
+
+```js
+import { getFeature } from '@esri/arcgis-rest-feature-service';
+
+const params = {
+ url:
+ "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0",
+ id: 42
+};
+
+getFeature(params)
+ .then(feature => {
+ console.log(feature.attributes.FID); // 42
+ });
+```
+
+### Issues
+
+If something isn't working the way you expected, please take a look at [previously logged issues](https://github.com/Esri/arcgis-rest-js/issues) first. Have you found a new bug? Want to request a new feature? We'd [**love**](https://github.com/Esri/arcgis-rest-js/issues/new) to hear from you.
+
+If you're looking for help you can also post issues on [GIS Stackexchange](http://gis.stackexchange.com/questions/ask?tags=esri-oss).
+
+### Versioning
+
+For transparency into the release cycle and in striving to maintain backward compatibility, @esri/arcgis-rest-js is maintained under Semantic Versioning guidelines and will adhere to these rules whenever possible.
+
+For more information on SemVer, please visit .
+
+### Contributing
+
+Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](CONTRIBUTING.md).
+
+### License
+
+Copyright 2018 Esri
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+> http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+A copy of the license is available in the repository's [LICENSE](./LICENSE) file.
diff --git a/packages/arcgis-rest-feature-service/package-lock.json b/packages/arcgis-rest-feature-service/package-lock.json
new file mode 100644
index 0000000000..ffb34e1f41
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/package-lock.json
@@ -0,0 +1,11 @@
+{
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "tslib": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.0.tgz",
+ "integrity": "sha512-ymKWWZJST0/CkgduC2qkzjMOWr4bouhuURNXCn/inEX0L57BnRG6FhX76o7FOnsjHazCjfU2LKeSrlS2sIKQJg=="
+ }
+ }
+}
diff --git a/packages/arcgis-rest-feature-service/package.json b/packages/arcgis-rest-feature-service/package.json
new file mode 100644
index 0000000000..9d81027e0f
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/package.json
@@ -0,0 +1,47 @@
+{
+ "name": "@esri/arcgis-rest-feature-service",
+ "version": "1.0.2",
+ "description": "Feature service helpers for @esri/arcgis-rest-request",
+ "main": "dist/node/index.js",
+ "browser": "dist/umd/arcgis-rest-feature-service.umd.js",
+ "module": "dist/esm/index.js",
+ "js:next": "dist/esm/index.js",
+ "types": "dist/esm/index.d.ts",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "tslib": "^1.7.1"
+ },
+ "peerDependencies": {
+ "@esri/arcgis-rest-common-types": "^1.0.3",
+ "@esri/arcgis-rest-request": "^1.0.3"
+ },
+ "devDependencies": {
+ "@esri/arcgis-rest-common-types": "^1.0.3",
+ "@esri/arcgis-rest-request": "^1.0.3"
+ },
+ "scripts": {
+ "prepare": "npm run build",
+ "build": "npm run build:node && npm run build:umd && npm run build:esm",
+ "build:esm": "tsc -p ./tsconfig.json --module es2015 --outDir ./dist/esm --declaration",
+ "build:umd": "rollup -c ../../rollup.config.umd.js",
+ "build:node": "tsc -p ./tsconfig.json --module commonjs --outDir ./dist/node"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/Esri/arcgis-rest-js.git"
+ },
+ "contributors": [
+ {
+ "name": "Tom Wayson",
+ "email": "twayson@esri.com",
+ "url": "http://tomwayson.com/"
+ }
+ ],
+ "bugs": {
+ "url": "https://github.com/Esri/arcgis-rest-js/issues"
+ },
+ "homepage": "https://github.com/Esri/arcgis-rest-js#readme"
+}
diff --git a/packages/arcgis-rest-feature-service/src/features.ts b/packages/arcgis-rest-feature-service/src/features.ts
new file mode 100644
index 0000000000..b3c170cb65
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/src/features.ts
@@ -0,0 +1,34 @@
+/* Copyright (c) 2017 Environmental Systems Research Institute, Inc.
+ * Apache-2.0 */
+import { IFeature } from "@esri/arcgis-rest-common-types";
+import { request, IRequestOptions } from "@esri/arcgis-rest-request";
+
+/**
+ * parameters required to get a feature by id
+ *
+ * @param url - layer service url
+ * @param id - feature id
+ */
+export interface IFeatureRequestOptions extends IRequestOptions {
+ url: string;
+ id: number;
+}
+
+/**
+ * Get an feature by id
+ *
+ * @param requestOptions - Options for the request
+ * @returns A Promise that will resolve with the feature.
+ */
+export function getFeature(
+ requestOptions: IFeatureRequestOptions
+): Promise {
+ const url = `${requestOptions.url}/${requestOptions.id}`;
+
+ // default to a GET request
+ const options: IFeatureRequestOptions = {
+ ...{ httpMethod: "GET" },
+ ...requestOptions
+ };
+ return request(url, options).then((response: any) => response.feature);
+}
diff --git a/packages/arcgis-rest-feature-service/src/index.ts b/packages/arcgis-rest-feature-service/src/index.ts
new file mode 100644
index 0000000000..0e849261ac
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/src/index.ts
@@ -0,0 +1 @@
+export * from "./features";
diff --git a/packages/arcgis-rest-feature-service/test/features.test.ts b/packages/arcgis-rest-feature-service/test/features.test.ts
new file mode 100644
index 0000000000..1a231e5de5
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/test/features.test.ts
@@ -0,0 +1,26 @@
+import { getFeature } from "../src/index";
+
+import * as fetchMock from "fetch-mock";
+
+import { featureResponse } from "./mocks/feature";
+
+describe("feature", () => {
+ afterEach(fetchMock.restore);
+
+ it("should return a feature by id", done => {
+ const params = {
+ url:
+ "https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/Landscape_Trees/FeatureServer/0",
+ id: 42
+ };
+ fetchMock.once("*", featureResponse);
+ getFeature(params).then(response => {
+ expect(fetchMock.called()).toBeTruthy();
+ const [url, options]: [string, RequestInit] = fetchMock.lastCall("*");
+ expect(url).toEqual(`${params.url}/42?f=json`);
+ expect(options.method).toBe("GET");
+ expect(response.attributes.FID).toEqual(42);
+ done();
+ });
+ });
+});
diff --git a/packages/arcgis-rest-feature-service/test/mocks/feature.ts b/packages/arcgis-rest-feature-service/test/mocks/feature.ts
new file mode 100644
index 0000000000..3bdfb43266
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/test/mocks/feature.ts
@@ -0,0 +1,13 @@
+import { IFeature } from "@esri/arcgis-rest-common-types";
+
+export const featureResponse = {
+ feature: {
+ attributes: {
+ FID: 42
+ },
+ geometry: {
+ x: -9177311.62541634,
+ y: 4247151.205222242
+ }
+ }
+};
diff --git a/packages/arcgis-rest-feature-service/tsconfig.json b/packages/arcgis-rest-feature-service/tsconfig.json
new file mode 100644
index 0000000000..400168ea91
--- /dev/null
+++ b/packages/arcgis-rest-feature-service/tsconfig.json
@@ -0,0 +1,6 @@
+{
+ "extends": "../../tsconfig.json",
+ "include": [
+ "src/**/*.ts"
+ ]
+}
\ No newline at end of file