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
14 changes: 14 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"env": {
"commonjs": true,
"es2021": true,
"node": true,
"jest": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": "latest"
},
"rules": {
}
}
130 changes: 130 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json

# 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
*.lcov

# nyc test coverage
.nyc_output

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

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

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

# Dependency directories
node_modules/
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
web_modules/

# TypeScript cache
*.tsbuildinfo

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional stylelint cache
.stylelintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next
out

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public

# vuepress build output
.vuepress/dist

# vuepress v2.x temp and cache directory
.temp
.cache

# Docusaurus cache and generated files
.docusaurus

# Serverless directories
.serverless/

# FuseBox cache
.fusebox/

# DynamoDB Local files
.dynamodb/

# TernJS port file
.tern-port

# Stores VSCode versions used for testing VSCode extensions
.vscode-test

# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ For this project you will create a RESTful API using Node and Express, containin

Here is a checklist of tasks to help you put your project together:

- Generate a `.gitignore` file.
- Install express, [email protected], sqlite3 as plain dependencies.
- Alternatively install express, knex, @vscode/sqlite3 as plain dependencies.
- Install jest, eslint, nodemon, supertest, cross-env as dev-dependencies.
- Configure jest and eslint using `npx <libname> --init`.
- Create a `knexfile.js` with "development" and "testing" configurations.
- Create a `db-config.js` file that selects the correct configuration using the value of `process.env.NODE_ENV`.
- Create migration and seed files.
- Put together "start", "server", "rollback", "migrate" and "seed" scripts in your `package.json`.
- Create a "test" script in your `package.json` using cross-env to inject a `NODE_ENV` of "testing".
- Create a basic express application with a few database access functions and a few endpoints.
- Test your endpoints manually using Postman, HTTPie or similar.
- Test your endpoints with supertest.
X Generate a `.gitignore` file.
X Install express, [email protected], sqlite3 as plain dependencies.
X Alternatively install express, knex, @vscode/sqlite3 as plain dependencies.
X Install jest, eslint, nodemon, supertest, cross-env as dev-dependencies.
X Configure jest and eslint using `npx <libname> --init`.
X Create a `knexfile.js` with "development" and "testing" configurations.
X Create a `db-config.js` file that selects the correct configuration using the value of `process.env.NODE_ENV`.
X Create migration and seed files.
X Put together "start", "server", "rollback", "migrate" and "seed" scripts in your `package.json`.
X Create a "test" script in your `package.json` using cross-env to inject a `NODE_ENV` of "testing".
X Create a basic express application with a few database access functions and a few endpoints.
X Test your endpoints manually using Postman, HTTPie or similar.
X Test your endpoints with supertest.
27 changes: 27 additions & 0 deletions api/pets/pets-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const db = require('../../data/dbConfig')

module.exports = {
insert,
update,
getAll,
getById
}

async function insert(pet) {
const [id] = await db('pets').insert(pet)
return db('pets').where({id}).first()
}


async function update(id, changes) {
await db('pets').where({id}).update(changes)
return db('pets').where({id}).first();
}

function getAll(){
return db('pets')
}

function getById(id){
return db('pets').where({id}).first()
}
47 changes: 47 additions & 0 deletions api/pets/pets-model.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const Pets = require('./pets-model')
//const db = require('../../data/dbConfig')
const knex = require('knex')
const knexConfig = require('../../knexfile')

const testDb = knex(knexConfig.testing)

beforeAll(async () => {
await testDb.migrate.rollback(); // so any changes to migration files are picked up
await testDb.migrate.latest();
})
beforeEach(async () => {
await testDb('pets').truncate();
await testDb.seed.run()
})
afterAll(async () => {
await testDb.destroy();
})

describe('pets model', () => {
describe('insert', () => {
it('inserts new pet into db', async () => {
await Pets.insert({ name: 'Fluffy' })
const pets = await Pets.getAll()
console.log(pets)
expect(pets).toHaveLength(4)
})
it('resolves to the inserted pet', async () => {
let pet = await Pets.insert({ name: 'Fluffy' })
expect(pet).toMatchObject({ id: 4, name: 'Fluffy'})
})
})

describe('getAll()', () => {
it('gets a list of all pets in the db', async () => {
let result = await Pets.getAll()
expect(result).toHaveLength(3)
})
})

describe('getById()', () => {
it('can find a pet by id', async () => {
const cooper = await Pets.getById(1)
expect(cooper).toMatchObject({ id:1, name:'Cooper' })
})
})
})
40 changes: 40 additions & 0 deletions api/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const express = require('express');
const Pets = require('./pets/pets-model')
const server = express();

server.use(express.json())

server.get('/', async (req,res) => {
res.status(200).json({api: 'up'})
})

server.get('/pets', (req,res) => {
Pets.getAll()
.then(pets => {
res.status(200).json(pets)
})
.catch(error => {
res.status(500).json(error)
})
})

server.get('/pets/:id', async (req,res) => {
const pet = await Pets.getById(req.params.id)
if(!pet){
res.status(404).end()
} else {
res.json(pet)
}
})

server.post('/pets', async (req,res) => {
const newPet = await Pets.insert(req.body)
res.json(newPet)
})

server.delete('/pets/:id', async (req,res) => {
await Pets.remove(req.params.id)
res.status(200).json({message: `pet with id ${req.params.id} removed from database`})
})

module.exports = server;
79 changes: 79 additions & 0 deletions api/server.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const request = require('supertest')
const db = require('../data/dbConfig')
const server = require('./server')

const knex = require('knex')
const knexConfig = require('../knexfile')

const testDb = knex(knexConfig.testing)

beforeAll(async () => {
await testDb.migrate.rollback(); // so any changes to migration files are picked up
await testDb.migrate.latest();
})
beforeEach(async () => {
await testDb('pets').truncate();
await testDb.seed.run()
})
afterAll(async () => {
await testDb.destroy();
})

describe('server.js', () => {
it('should set testing environment', () => {
expect(process.env.NODE_ENV).toBe('testing')
})

describe('[GET] /', () => {
it('should return 200 OK', () => {
return request(server)
.get('/')
.then(res => {
expect(res.status).toBe(200)
})
})
it('should return JSON', async () => {
const res = await request(server).get('/')
expect(res.type).toBe('application/json')
})
it('should return { api : "up" }', async () => {
const res = await request(server).get('/')
expect(res.body).toEqual({ api: 'up'})
})
})

describe('[GET] /pets', () => {
it('responds with 200 ok', async () => {
const res = await request(server).get('/pets')
expect(res.status).toBe(200)
})
it('responds with pets if there are pets', async () => {
const res = await request(server).get('/pets')
expect(res.body).toHaveLength(3)
})
})

describe('[GET] /pets/:id', () => {
it('resolves to the pet with the given id', async () => {
let res = await request(server).get('/pets/1')
expect(res.body).toMatchObject({ id: 1, name: 'Cooper' })
})

it('responds with 404 if not in db', async () => {
let res = await request(server).get('/pets/5')
expect(res.status).toBe(404)
})
})

describe('[POST] /pets', () => {
it('returns the newly created pet', async () => {
const res = await request(server).post('/pets').send({ name: 'Fluffy' })
expect(res.body).toMatchObject({ id: 4, name: 'Fluffy'})
})
it('after inserting a new pet, GET resolves to the updated array of pets', async () => {
await request(server).post('/pets').send({ name: 'Fluffy' })
const res = await request(server).get('/pets')
expect(res.body).toHaveLength(4)
})
})
})
6 changes: 6 additions & 0 deletions data/dbConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const knex = require('knex');
const config = require('../knexfile.js');

const dbEnv = process.env.NODE_ENV || 'development';

module.exports = knex(config[dbEnv]);
11 changes: 11 additions & 0 deletions data/migrations/20240107223716_first-migration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

exports.up = function(knex) {
return knex.schema.createTable('pets', tbl => {
tbl.increments();
tbl.string('name').notNullable()
})
};

exports.down = function(knex) {
return knex.schema.dropTableIfExists('pets')
};
Binary file added data/pets.db3
Binary file not shown.
Loading