├── .gitignore ├── .babelrc ├── clients.db ├── package.json ├── clients.sql ├── db.txt ├── server.js └── README.markdown /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | build/ -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { "presets": ["@babel/preset-env"] } -------------------------------------------------------------------------------- /clients.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/insidesherpa/shiptivitas-2/HEAD/clients.db -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shiptivity-api", 3 | "version": "1.0.0", 4 | "description": "The Backend of Shiptivity", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "babel server.js --out-dir build", 9 | "start": "babel-watch server.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/insidesherpa/shiptivity-2.git" 14 | }, 15 | "keywords": [ 16 | "shiptivity" 17 | ], 18 | "author": "juliusarden", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/insidesherpa/shiptivity-2/issues" 22 | }, 23 | "homepage": "https://github.com/insidesherpa/shiptivity-2#readme", 24 | "dependencies": { 25 | "better-sqlite3": "^5.4.0", 26 | "express": "^4.16.4" 27 | }, 28 | "devDependencies": { 29 | "@babel/core": "^7.2.2", 30 | "@babel/preset-env": "^7.3.1", 31 | "babel": "^6.23.0", 32 | "babel-cli": "^6.26.0", 33 | "babel-preset-env": "^1.7.0", 34 | "babel-watch": "^7.0.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /clients.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE clients; 2 | CREATE TABLE IF NOT EXISTS clients ( 3 | id INTEGER PRIMARY KEY, 4 | name TEXT NOT NULL, 5 | description TEXT, 6 | status TEXT, 7 | priority INTEGER 8 | ); 9 | 10 | insert into clients values(1,"Stark, White and Abbott", "Cloned Optimal Architecture", "in-progress", 1); 11 | insert into clients values(2,"Wiza LLC", "Exclusive Bandwidth-Monitored Implementation", "complete", 1); 12 | insert into clients values(3,"Nolan LLC", "Vision-Oriented 4Thgeneration Graphicaluserinterface", "backlog", 1); 13 | insert into clients values(4,"Thompson PLC", "Streamlined Regional Knowledgeuser", "in-progress", 2); 14 | insert into clients values(5,"Walker-Williamson", "Team-Oriented 6Thgeneration Matrix", "in-progress", 3); 15 | insert into clients values(6,"Boehm and Sons", "Automated Systematic Paradigm", "backlog", 2); 16 | insert into clients values(7,"Runolfsson, Hegmann and Block", "Integrated Transitional Strategy", "backlog", 3); 17 | insert into clients values(8,"Schumm-Labadie", "Operative Heuristic Challenge", "backlog", 4); 18 | insert into clients values(9,"Kohler Group", "Re-Contextualized Multi-Tasking Attitude", "backlog", 5); 19 | insert into clients values(10,"Romaguera Inc", "Managed Foreground Toolset", "backlog", 6); 20 | insert into clients values(11,"Reilly-King", "Future-Proofed Interactive Toolset", "complete", 2); 21 | insert into clients values(12,"Emard, Champlin and Runolfsdottir", "Devolved Needs-Based Capability", "backlog", 7); 22 | insert into clients values(13,"Fritsch, Cronin and Wolff", "Open-Source 3Rdgeneration Website", "complete", 3); 23 | insert into clients values(14,"Borer LLC", "Profit-Focused Incremental Orchestration", "backlog", 8); 24 | insert into clients values(15,"Emmerich-Ankunding", "User-Centric Stable Extranet", "in-progress", 4); 25 | insert into clients values(16,"Willms-Abbott", "Progressive Bandwidth-Monitored Access", "in-progress", 5); 26 | insert into clients values(17,"Brekke PLC", "Intuitive User-Facing Customerloyalty", "complete", 4); 27 | insert into clients values(18,"Bins, Toy and Klocko", "Integrated Assymetric Software", "backlog", 9); 28 | insert into clients values(19,"Hodkiewicz-Hayes", "Programmable Systematic Securedline", "backlog", 10); 29 | insert into clients values(20,"Murphy, Lang and Ferry", "Organized Explicit Access", "backlog", 11); -------------------------------------------------------------------------------- /db.txt: -------------------------------------------------------------------------------- 1 | [ 2 | {"id":1,"name":"Stark, White and Abbott", "description": "Cloned Optimal Architecture", "status": "in-progress", "priority": 1}, 3 | {"id":2,"name":"Wiza LLC", "description": "Exclusive Bandwidth-Monitored Implementation", "status": "complete", "priority": 1}, 4 | {"id":3,"name":"Nolan LLC", "description": "Vision-Oriented 4Thgeneration Graphicaluserinterface", "status": "backlog", "priority": 1}, 5 | {"id":4,"name":"Thompson PLC", "description": "Streamlined Regional Knowledgeuser", "status": "in-progress", "priority": 2}, 6 | {"id":5,"name":"Walker-Williamson", "description": "Team-Oriented 6Thgeneration Matrix", "status": "in-progress", "priority": 3}, 7 | {"id":6,"name":"Boehm and Sons", "description": "Automated Systematic Paradigm", "status": "backlog", "priority": 2}, 8 | {"id":7,"name":"Runolfsson, Hegmann and Block", "description": "Integrated Transitional Strategy", "status": "backlog", "priority": 3}, 9 | {"id":8,"name":"Schumm-Labadie", "description": "Operative Heuristic Challenge", "status": "backlog", "priority": 4}, 10 | {"id":9,"name":"Kohler Group", "description": "Re-Contextualized Multi-Tasking Attitude", "status": "backlog", "priority": 5}, 11 | {"id":10,"name":"Romaguera Inc", "description": "Managed Foreground Toolset", "status": "backlog", "priority": 6}, 12 | {"id":11,"name":"Reilly-King", "description": "Future-Proofed Interactive Toolset", "status": "complete", "priority": 2}, 13 | {"id":12,"name":"Emard, Champlin and Runolfsdottir", "description": "Devolved Needs-Based Capability", "status": "backlog", "priority": 7}, 14 | {"id":13,"name":"Fritsch, Cronin and Wolff", "description": "Open-Source 3Rdgeneration Website", "status": "complete", "priority": 3}, 15 | {"id":14,"name":"Borer LLC", "description": "Profit-Focused Incremental Orchestration", "status": "backlog", "priority": 8}, 16 | {"id":15,"name":"Emmerich-Ankunding", "description": "User-Centric Stable Extranet", "status": "in-progress", "priority": 4}, 17 | {"id":16,"name":"Willms-Abbott", "description": "Progressive Bandwidth-Monitored Access", "status": "in-progress", "priority": 5}, 18 | {"id":17,"name":"Brekke PLC", "description": "Intuitive User-Facing Customerloyalty", "status": "complete", "priority": 4}, 19 | {"id":18,"name":"Bins, Toy and Klocko", "description": "Integrated Assymetric Software", "status": "backlog", "priority": 9}, 20 | {"id":19,"name":"Hodkiewicz-Hayes", "description": "Programmable Systematic Securedline", "status": "backlog", "priority": 10}, 21 | {"id":20,"name":"Murphy, Lang and Ferry", "description": "Organized Explicit Access", "status": "backlog", "priority": 11} 22 | ] -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import Database from 'better-sqlite3'; 3 | 4 | const app = express(); 5 | 6 | app.use(express.json()); 7 | 8 | app.get('/', (req, res) => { 9 | return res.status(200).send({'message': 'SHIPTIVITY API. Read documentation to see API docs'}); 10 | }); 11 | 12 | // We are keeping one connection alive for the rest of the life application for simplicity 13 | const db = new Database('./clients.db'); 14 | 15 | // Don't forget to close connection when server gets terminated 16 | const closeDb = () => db.close(); 17 | process.on('SIGTERM', closeDb); 18 | process.on('SIGINT', closeDb); 19 | 20 | /** 21 | * Validate id input 22 | * @param {any} id 23 | */ 24 | const validateId = (id) => { 25 | if (Number.isNaN(id)) { 26 | return { 27 | valid: false, 28 | messageObj: { 29 | 'message': 'Invalid id provided.', 30 | 'long_message': 'Id can only be integer.', 31 | }, 32 | }; 33 | } 34 | const client = db.prepare('select * from clients where id = ? limit 1').get(id); 35 | if (!client) { 36 | return { 37 | valid: false, 38 | messageObj: { 39 | 'message': 'Invalid id provided.', 40 | 'long_message': 'Cannot find client with that id.', 41 | }, 42 | }; 43 | } 44 | return { 45 | valid: true, 46 | }; 47 | } 48 | 49 | /** 50 | * Validate priority input 51 | * @param {any} priority 52 | */ 53 | const validatePriority = (priority) => { 54 | if (Number.isNaN(priority)) { 55 | return { 56 | valid: false, 57 | messageObj: { 58 | 'message': 'Invalid priority provided.', 59 | 'long_message': 'Priority can only be positive integer.', 60 | }, 61 | }; 62 | } 63 | return { 64 | valid: true, 65 | } 66 | } 67 | 68 | /** 69 | * Get all of the clients. Optional filter 'status' 70 | * GET /api/v1/clients?status={status} - list all clients, optional parameter status: 'backlog' | 'in-progress' | 'complete' 71 | */ 72 | app.get('/api/v1/clients', (req, res) => { 73 | const status = req.query.status; 74 | if (status) { 75 | // status can only be either 'backlog' | 'in-progress' | 'complete' 76 | if (status !== 'backlog' && status !== 'in-progress' && status !== 'complete') { 77 | return res.status(400).send({ 78 | 'message': 'Invalid status provided.', 79 | 'long_message': 'Status can only be one of the following: [backlog | in-progress | complete].', 80 | }); 81 | } 82 | const clients = db.prepare('select * from clients where status = ?').all(status); 83 | return res.status(200).send(clients); 84 | } 85 | const statement = db.prepare('select * from clients'); 86 | const clients = statement.all(); 87 | return res.status(200).send(clients); 88 | }); 89 | 90 | /** 91 | * Get a client based on the id provided. 92 | * GET /api/v1/clients/{client_id} - get client by id 93 | */ 94 | app.get('/api/v1/clients/:id', (req, res) => { 95 | const id = parseInt(req.params.id , 10); 96 | const { valid, messageObj } = validateId(id); 97 | if (!valid) { 98 | res.status(400).send(messageObj); 99 | } 100 | return res.status(200).send(db.prepare('select * from clients where id = ?').get(id)); 101 | }); 102 | 103 | /** 104 | * Update client information based on the parameters provided. 105 | * When status is provided, the client status will be changed 106 | * When priority is provided, the client priority will be changed with the rest of the clients accordingly 107 | * Note that priority = 1 means it has the highest priority (should be on top of the swimlane). 108 | * No client on the same status should not have the same priority. 109 | * This API should return list of clients on success 110 | * 111 | * PUT /api/v1/clients/{client_id} - change the status of a client 112 | * Data: 113 | * status (optional): 'backlog' | 'in-progress' | 'complete', 114 | * priority (optional): integer, 115 | * 116 | */ 117 | app.put('/api/v1/clients/:id', (req, res) => { 118 | const id = parseInt(req.params.id , 10); 119 | const { valid, messageObj } = validateId(id); 120 | if (!valid) { 121 | res.status(400).send(messageObj); 122 | } 123 | 124 | let { status, priority } = req.body; 125 | let clients = db.prepare('select * from clients').all(); 126 | const client = clients.find(client => client.id === id); 127 | 128 | /* ---------- Update code below ----------*/ 129 | 130 | 131 | 132 | return res.status(200).send(clients); 133 | }); 134 | 135 | app.listen(3001); 136 | console.log('app running on port ', 3001); 137 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 |
8 | 9 | 10 |11 | Task Overview 12 | | 13 | Installation 14 | | 15 | Link to Module 2 16 | | 17 | Link to Y Combinator Program 18 | 19 |
20 | 21 | 22 | # Introduction 23 |
24 | College Students:
25 | Learn how to work at a Y Combinator startup
26 |
Train online for the skills Y Combinator startups are looking for. One of the official ways to get recruited into a Y Combinator startup.
27 |
npm install
63 | to install all dependencies
64 |
65 | Start the server by running:
66 | npm start
67 | This command will run the Express server on localhost:3001
68 |
69 | Try the API by running:
70 | ### curl -X GET http://localhost:3001/api/v1/clients
71 | ### curl -X GET http://localhost:3001/api/v1/clients?status=backlog
72 | ### curl -X GET http://localhost:3001/api/v1/clients/1
73 | ### curl -X PUT http://localhost:3001/api/v1/clients/1 -H "Content-Type: application/json" -d '{"status":"in-progress", "priority": 6}'
74 |
75 |
76 | For this task, you only need to update the API for updating client detail.
77 |
78 | Valid status:
79 | - backlog
80 | - in-progress
81 | - complete
82 |
83 | `client.priority` should be unique per status. Ordered from 1 to x where priority 1 means most important client.
84 |
85 | Some sample curl to help you test your code (make sure you restart your server each time you run this):
86 |
87 | Should do nothing
88 |
89 | ### curl -X PUT http://localhost:3001/api/v1/clients/1 -H "Content-Type: application/json" -d '{"status":"in-progress"}'
90 |
91 | Should insert the client as lowest priority (biggest number) with status complete
92 |
93 | ### curl -X PUT http://localhost:3001/api/v1/clients/1 -H "Content-Type: application/json" -d '{"status":"complete"}'
94 |
95 | Should insert the client at the right priority and reorder the priority in clients with different statuses
96 |
97 | ### curl -X PUT http://localhost:3001/api/v1/clients/1 -H "Content-Type: application/json" -d '{"status":"complete", "priority": 3}'
98 |
99 | ## Additional Resources
100 | Node JS: https://nodejs.org/en/
101 | Express: https://expressjs.com
102 | better-sqlite3: https://github.com/JoshuaWise/better-sqlite3/blob/HEAD/docs/api.md
103 |
--------------------------------------------------------------------------------