Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"rules": {
"no-console": "off",
"indent": [ "error", 2 ],
"quotes": [ "error", "single" ],
"semi": ["error", "always"],
"linebreak-style": [ "error", "unix" ]
},
"env": {
"es6": true,
"node": true,
"mocha": true,
"jasmine": true
},
"ecmaFeatures": {
"modules": true,
"experimentalObjectRestSpread": true,
"impliedStrict": true
},
"extends": "eslint:recommended"
}
123 changes: 123 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@

# Created by https://www.gitignore.io/api/node,macos,windows,linux

### Node ###
# Logs
logs
*.log
npm-debug.log*
node_modules
coverage

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules
jspm_packages

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity



### macOS ###
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk


### Windows ###
# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# Windows Installer files
*.cab
*.msi
*.msm
*.msp

# Windows shortcuts
*.lnk


### Linux ###
*~

# temporary files which can be created if a process still has a handle open of a deleted file
.fuse_hidden*

# KDE directory preferences
.directory

# Linux trash folder which might appear on any partition or disk
.Trash-*

# .nfs files are created when an open file is removed but is still being accessed
.nfs*


# exclude everything
data/*

# exception to the rule
!data/.gitkeep
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Single Resource Express API

This project creates a single resource REST API using [Express.js](http://expressjs.com/) and allows users send POST, GET and DELETE requests related
to dogs through the terminal.
When sending requests, use filepath `/api/dog` with a query and a response will return with appropriate message/content.
You will need to [HTTPie](https://httpie.org/) to send requets through the terminal.

## How to run

Install any Dependencies from the `package.json` file into the project root
directory. Using [Node.js](https://nodejs.org/), to create a `package.json` file, enter command `npm init` in the project root.
You can run the command `npm i` to install all depenenedcies. Make sure to have a `data` folder in the root directory.
This is where POST requests will write to.

## Running server

Run the `server.js` file using command `node server.js` or `npm start`. In terminal, you should see `Server up: 8000` or
port that is set in your environmental variable in terminal.

## Sending POST GET DELETE Request

>POST Request

In an new terminal window, send a `POST` request by using the command
`http POST localhost:8000/api/dog name=<name> breed=<breed> color=<color>`.
Example: `http POST localhost:8000/api/dog name='Buddy' breed='Golden Retriever' color='brown`
The POST request must include `name` `breed` and `color` parameters.
The successful response should return a JSON object with values you entered along with a unique `id` and
a status code of `200`. This will also create a new `.json` file into the `data` folder with the `id`
as the file name.

![POST request screenshot](/assets/post-response-screenshot.png)

>GET Request

In an new terminal window, send a `GET` request by using the command `http localhost:8000/api/dog?id=<id>`.
Example: `http localhost:8000/api/dog?id=00000000-c303-11e6-a4a3-73422de980bc`
The successful reponse should return a JSON object with a status of `200`.

![GET request screenshot](/assets/get-response-screenshot.png)

>DELETE Request

In an new terminal window, send a `DELETE` request by using the command
`http DELETE localhost:8000/api/dog?id=<id>`.
Example: `http DELETE localhost:8000/api/dog?id=00000000-c303-11e6-a4a3-73422de980bc`
The a successful response should return a `204` status code with no content.

![DELETE request screenshot](/assets/delete-response-screenshot.png)

## Closing server

In server terminal, enter ```control``` + ```c```.
Binary file added assets/delete-response-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/get-response-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/post-response-screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added data/.gitkeep
Empty file.
37 changes: 37 additions & 0 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';

const gulp = require('gulp');
const eslint = require('gulp-eslint');
const mocha = require('gulp-mocha');
const cache = require('gulp-cache');
const istanbul = require('gulp-istanbul');

gulp.task('pre-test', function() {
return gulp.src(['./lib/*.js', './model/*.js', '!node_modules/**'])
.pipe(istanbul())
.pipe(istanbul.hookRequire());
});

gulp.task('test', ['pre-test'], function() {
gulp.src('./test/*-test.js', { read: false})
.pipe(mocha({ report: 'spec'}))
.pipe(istanbul.writeReports())
.pipe(istanbul.enforceThresholds({thresholds: {global: 90}}));
});

gulp.task('lint', function() {
return gulp.src(['**/*.js', '!node_modules/**'])
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});

gulp.task('dev', function() {
gulp.watch(['**/*.js', '!node_modules/**'], ['lint', 'test']);
});

gulp.task('default', ['dev']);

gulp.task('clear', function (done) {
return cache.clearAll(done);
});
49 changes: 49 additions & 0 deletions lib/storage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

const Promise = require('bluebird');
const fs = Promise.promisifyAll(require('fs'), {suffix: 'Prom'});
const createError = require('http-errors');
const debug = require('debug')('dogs:storage');

module.exports = exports = {};

exports.createItem = function(schemaName, item) {
debug('createItem');

if(!schemaName) return Promise.reject(createError(400, 'expected schema name'));
if(!item) return Promise.reject(createError(400, 'expected item'));

let json = JSON.stringify(item);
return fs.writeFileProm(`${__dirname}/../data/${schemaName}/${item.id}.json`, json)
.then( () => item)
.catch( err => Promise.reject(createError(500, err.message)));
};

exports.fetchItem = function(schemaName, id) {
debug('fetchItem');

if(!schemaName) return Promise.reject(createError(400, 'expected schema name'));
if(!id) return Promise.reject(createError(400, 'expected id'));

return fs.readFileProm(`${__dirname}/../data/${schemaName}/${id}.json`)
.then( data => {
try {
let item = JSON.parse(data.toString());
return item;
} catch (err) {
return Promise.reject(createError(500, err.message));
}
})
.catch( err => Promise.reject(createError(404, err.message)));
};

exports.deleteItem = function(schemaName, id) {
debug('deleteItem');

if(!schemaName) return Promise.reject(createError(400, 'expected schema name'));
if(!id) return Promise.reject(createError(400, 'expected id'));

return fs.unlinkProm(`${__dirname}/../data/${schemaName}/${id}.json`)

.catch(err => Promise.reject(createError(404, err.message)));
};
43 changes: 43 additions & 0 deletions model/dogs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use strict';

const uuid = require('node-uuid');
const createError = require('http-errors');
const debug = require('debug')('dogs:dogs');
const storage = require('../lib/storage.js');

const Dog = module.exports = function(name, breed, color) {
debug('dog constructor');

if(!name) throw createError(400, 'expected name');
if(!breed) throw createError(400, 'expected breed');
if(!color) throw createError(400, 'expected color');

this.id = uuid.v1();
this.name = name;
this.breed = breed;
this.color = color;

};

Dog.createDog = function(_dog) {
debug('createDog');

try {
let dog = new Dog(_dog.name, _dog.breed, _dog.color);
return storage.createItem('dog', dog);
} catch (err) {
return Promise.reject(err);
}
};

Dog.fetchDog = function(id) {
debug('fetchDog');

return storage.fetchItem('dog', id);
};

Dog.deleteDog = function(id) {
debug('deleteDog');

return storage.deleteItem('dog', id);
};
40 changes: 40 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "11-express_single_resource_api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "DEBUG='dog*' node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/peterkim2/11-express_single_resource_api.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/peterkim2/11-express_single_resource_api/issues"
},
"homepage": "https://github.com/peterkim2/11-express_single_resource_api#readme",
"devDependencies": {
"chai": "^3.5.0",
"gulp": "^3.9.1",
"gulp-cache": "^0.4.5",
"gulp-eslint": "^3.0.1",
"gulp-istanbul": "^1.1.1",
"gulp-mocha": "^3.0.1",
"mocha": "^3.2.0"
},
"dependencies": {
"bluebird": "^3.4.6",
"body-parser": "^1.15.2",
"debug": "^2.4.5",
"express": "^4.14.0",
"http-errors": "^1.5.1",
"morgan": "^1.7.0",
"node-uuid": "^1.4.7",
"superagent": "^3.3.1"
}
}
Loading