├── .gitignore ├── Procfile ├── README.md ├── app.js ├── npm-shrinkwrap.json ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node app.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tweet Validator 2 | 3 | Checks for 140 character limit. 4 | 5 | The `/tweet` endpoint responds to **POST** requests with a 6 | *description* field in JSON format. 7 | It sends back a 8 | **200** HTTP status code if *description* is valid and a **400** status code 9 | if it's not. 10 | 11 | Available on Heroku at 12 | 13 | ## Running the app 14 | 15 | * `npm install` 16 | * `node app.js` 17 | 18 | ## Making calls with curl 19 | 20 | Using *curl*, you can make calls like so: 21 | 22 | `curl -H 'Content-Type: application/json' -d '{"description":"Example of description"}' http://localhost:3000/tweet` -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var app = express(); 3 | 4 | var allowAllTheThings = require('permissive-cors'); 5 | app.use(allowAllTheThings()); 6 | 7 | var bodyParser = require('body-parser'); 8 | 9 | app.post('/tweet', bodyParser.json(), function(request, response) { 10 | var description = request.body.description; 11 | var maxLength = request.body.maxLength || 140; 12 | 13 | if(!description || description.length > maxLength){ 14 | response.status(400).json("This Tweet cannot be Tweeted."); 15 | }else{ 16 | response.status(200).json("This Tweet can be Tweeted.") 17 | } 18 | }); 19 | 20 | var port = process.env.PORT || 3000; 21 | 22 | app.listen(port, function() { 23 | console.log('Listening on ' + port); 24 | }); 25 | -------------------------------------------------------------------------------- /npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CanITweetThis", 3 | "version": "1.0.0", 4 | "dependencies": { 5 | "accepts": { 6 | "version": "1.3.3" 7 | }, 8 | "array-flatten": { 9 | "version": "1.1.1" 10 | }, 11 | "body-parser": { 12 | "version": "1.17.1" 13 | }, 14 | "bytes": { 15 | "version": "2.4.0" 16 | }, 17 | "content-disposition": { 18 | "version": "0.5.2" 19 | }, 20 | "content-type": { 21 | "version": "1.0.2" 22 | }, 23 | "cookie": { 24 | "version": "0.3.1" 25 | }, 26 | "cookie-signature": { 27 | "version": "1.0.6" 28 | }, 29 | "debug": { 30 | "version": "2.6.1" 31 | }, 32 | "depd": { 33 | "version": "1.1.0" 34 | }, 35 | "destroy": { 36 | "version": "1.0.4" 37 | }, 38 | "ee-first": { 39 | "version": "1.1.1" 40 | }, 41 | "encodeurl": { 42 | "version": "1.0.1" 43 | }, 44 | "escape-html": { 45 | "version": "1.0.3" 46 | }, 47 | "etag": { 48 | "version": "1.8.0" 49 | }, 50 | "express": { 51 | "version": "4.15.2" 52 | }, 53 | "finalhandler": { 54 | "version": "1.0.1", 55 | "dependencies": { 56 | "debug": { 57 | "version": "2.6.3" 58 | } 59 | } 60 | }, 61 | "forwarded": { 62 | "version": "0.1.0" 63 | }, 64 | "fresh": { 65 | "version": "0.5.0" 66 | }, 67 | "http-errors": { 68 | "version": "1.6.1" 69 | }, 70 | "iconv-lite": { 71 | "version": "0.4.15" 72 | }, 73 | "inherits": { 74 | "version": "2.0.3" 75 | }, 76 | "ipaddr.js": { 77 | "version": "1.3.0" 78 | }, 79 | "media-typer": { 80 | "version": "0.3.0" 81 | }, 82 | "merge-descriptors": { 83 | "version": "1.0.1" 84 | }, 85 | "methods": { 86 | "version": "1.1.2" 87 | }, 88 | "mime": { 89 | "version": "1.3.4" 90 | }, 91 | "mime-db": { 92 | "version": "1.27.0" 93 | }, 94 | "mime-types": { 95 | "version": "2.1.15" 96 | }, 97 | "ms": { 98 | "version": "0.7.2" 99 | }, 100 | "negotiator": { 101 | "version": "0.6.1" 102 | }, 103 | "on-finished": { 104 | "version": "2.3.0" 105 | }, 106 | "parseurl": { 107 | "version": "1.3.1" 108 | }, 109 | "path-to-regexp": { 110 | "version": "0.1.7" 111 | }, 112 | "permissive-cors": { 113 | "version": "1.0.0" 114 | }, 115 | "proxy-addr": { 116 | "version": "1.1.4" 117 | }, 118 | "qs": { 119 | "version": "6.4.0" 120 | }, 121 | "range-parser": { 122 | "version": "1.2.0" 123 | }, 124 | "raw-body": { 125 | "version": "2.2.0" 126 | }, 127 | "send": { 128 | "version": "0.15.1" 129 | }, 130 | "serve-static": { 131 | "version": "1.12.1" 132 | }, 133 | "setprototypeof": { 134 | "version": "1.0.3" 135 | }, 136 | "statuses": { 137 | "version": "1.3.1" 138 | }, 139 | "type-is": { 140 | "version": "1.6.14" 141 | }, 142 | "unpipe": { 143 | "version": "1.0.0" 144 | }, 145 | "utils-merge": { 146 | "version": "1.0.0" 147 | }, 148 | "vary": { 149 | "version": "1.1.1" 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CanITweetThis", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Carlos Souza (http://csouza.me/)", 10 | "license": "ISC", 11 | "dependencies": { 12 | "body-parser": "^1.10.0", 13 | "express": "^4.10.4", 14 | "permissive-cors": "^1.0.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | accepts@~1.3.3: 4 | version "1.3.3" 5 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" 6 | dependencies: 7 | mime-types "~2.1.11" 8 | negotiator "0.6.1" 9 | 10 | array-flatten@1.1.1: 11 | version "1.1.1" 12 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 13 | 14 | body-parser@^1.10.0: 15 | version "1.17.1" 16 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" 17 | dependencies: 18 | bytes "2.4.0" 19 | content-type "~1.0.2" 20 | debug "2.6.1" 21 | depd "~1.1.0" 22 | http-errors "~1.6.1" 23 | iconv-lite "0.4.15" 24 | on-finished "~2.3.0" 25 | qs "6.4.0" 26 | raw-body "~2.2.0" 27 | type-is "~1.6.14" 28 | 29 | bytes@2.4.0: 30 | version "2.4.0" 31 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" 32 | 33 | content-disposition@0.5.2: 34 | version "0.5.2" 35 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" 36 | 37 | content-type@~1.0.2: 38 | version "1.0.2" 39 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" 40 | 41 | cookie-signature@1.0.6: 42 | version "1.0.6" 43 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 44 | 45 | cookie@0.3.1: 46 | version "0.3.1" 47 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" 48 | 49 | debug@2.6.1: 50 | version "2.6.1" 51 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" 52 | dependencies: 53 | ms "0.7.2" 54 | 55 | debug@2.6.3: 56 | version "2.6.3" 57 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" 58 | dependencies: 59 | ms "0.7.2" 60 | 61 | depd@~1.1.0, depd@1.1.0: 62 | version "1.1.0" 63 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" 64 | 65 | destroy@~1.0.4: 66 | version "1.0.4" 67 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 68 | 69 | ee-first@1.1.1: 70 | version "1.1.1" 71 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 72 | 73 | encodeurl@~1.0.1: 74 | version "1.0.1" 75 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" 76 | 77 | escape-html@~1.0.3: 78 | version "1.0.3" 79 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 80 | 81 | etag@~1.8.0: 82 | version "1.8.0" 83 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" 84 | 85 | express@^4.10.4: 86 | version "4.15.2" 87 | resolved "https://registry.yarnpkg.com/express/-/express-4.15.2.tgz#af107fc148504457f2dca9a6f2571d7129b97b35" 88 | dependencies: 89 | accepts "~1.3.3" 90 | array-flatten "1.1.1" 91 | content-disposition "0.5.2" 92 | content-type "~1.0.2" 93 | cookie "0.3.1" 94 | cookie-signature "1.0.6" 95 | debug "2.6.1" 96 | depd "~1.1.0" 97 | encodeurl "~1.0.1" 98 | escape-html "~1.0.3" 99 | etag "~1.8.0" 100 | finalhandler "~1.0.0" 101 | fresh "0.5.0" 102 | merge-descriptors "1.0.1" 103 | methods "~1.1.2" 104 | on-finished "~2.3.0" 105 | parseurl "~1.3.1" 106 | path-to-regexp "0.1.7" 107 | proxy-addr "~1.1.3" 108 | qs "6.4.0" 109 | range-parser "~1.2.0" 110 | send "0.15.1" 111 | serve-static "1.12.1" 112 | setprototypeof "1.0.3" 113 | statuses "~1.3.1" 114 | type-is "~1.6.14" 115 | utils-merge "1.0.0" 116 | vary "~1.1.0" 117 | 118 | finalhandler@~1.0.0: 119 | version "1.0.1" 120 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.1.tgz#bcd15d1689c0e5ed729b6f7f541a6df984117db8" 121 | dependencies: 122 | debug "2.6.3" 123 | encodeurl "~1.0.1" 124 | escape-html "~1.0.3" 125 | on-finished "~2.3.0" 126 | parseurl "~1.3.1" 127 | statuses "~1.3.1" 128 | unpipe "~1.0.0" 129 | 130 | forwarded@~0.1.0: 131 | version "0.1.0" 132 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" 133 | 134 | fresh@0.5.0: 135 | version "0.5.0" 136 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" 137 | 138 | http-errors@~1.6.1: 139 | version "1.6.1" 140 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" 141 | dependencies: 142 | depd "1.1.0" 143 | inherits "2.0.3" 144 | setprototypeof "1.0.3" 145 | statuses ">= 1.3.1 < 2" 146 | 147 | iconv-lite@0.4.15: 148 | version "0.4.15" 149 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" 150 | 151 | inherits@2.0.3: 152 | version "2.0.3" 153 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 154 | 155 | ipaddr.js@1.3.0: 156 | version "1.3.0" 157 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" 158 | 159 | media-typer@0.3.0: 160 | version "0.3.0" 161 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 162 | 163 | merge-descriptors@1.0.1: 164 | version "1.0.1" 165 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 166 | 167 | methods@~1.1.2: 168 | version "1.1.2" 169 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 170 | 171 | mime-db@~1.27.0: 172 | version "1.27.0" 173 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 174 | 175 | mime-types@~2.1.11, mime-types@~2.1.13: 176 | version "2.1.15" 177 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 178 | dependencies: 179 | mime-db "~1.27.0" 180 | 181 | mime@1.3.4: 182 | version "1.3.4" 183 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" 184 | 185 | ms@0.7.2: 186 | version "0.7.2" 187 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 188 | 189 | negotiator@0.6.1: 190 | version "0.6.1" 191 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" 192 | 193 | on-finished@~2.3.0: 194 | version "2.3.0" 195 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 196 | dependencies: 197 | ee-first "1.1.1" 198 | 199 | parseurl@~1.3.1: 200 | version "1.3.1" 201 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" 202 | 203 | path-to-regexp@0.1.7: 204 | version "0.1.7" 205 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 206 | 207 | permissive-cors: 208 | version "1.0.0" 209 | resolved "https://registry.yarnpkg.com/permissive-cors/-/permissive-cors-1.0.0.tgz#97be711fa44b2caea8e7acbb1a0a4ec323fe8d26" 210 | 211 | proxy-addr@~1.1.3: 212 | version "1.1.4" 213 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" 214 | dependencies: 215 | forwarded "~0.1.0" 216 | ipaddr.js "1.3.0" 217 | 218 | qs@6.4.0: 219 | version "6.4.0" 220 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 221 | 222 | range-parser@~1.2.0: 223 | version "1.2.0" 224 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" 225 | 226 | raw-body@~2.2.0: 227 | version "2.2.0" 228 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" 229 | dependencies: 230 | bytes "2.4.0" 231 | iconv-lite "0.4.15" 232 | unpipe "1.0.0" 233 | 234 | send@0.15.1: 235 | version "0.15.1" 236 | resolved "https://registry.yarnpkg.com/send/-/send-0.15.1.tgz#8a02354c26e6f5cca700065f5f0cdeba90ec7b5f" 237 | dependencies: 238 | debug "2.6.1" 239 | depd "~1.1.0" 240 | destroy "~1.0.4" 241 | encodeurl "~1.0.1" 242 | escape-html "~1.0.3" 243 | etag "~1.8.0" 244 | fresh "0.5.0" 245 | http-errors "~1.6.1" 246 | mime "1.3.4" 247 | ms "0.7.2" 248 | on-finished "~2.3.0" 249 | range-parser "~1.2.0" 250 | statuses "~1.3.1" 251 | 252 | serve-static@1.12.1: 253 | version "1.12.1" 254 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.1.tgz#7443a965e3ced647aceb5639fa06bf4d1bbe0039" 255 | dependencies: 256 | encodeurl "~1.0.1" 257 | escape-html "~1.0.3" 258 | parseurl "~1.3.1" 259 | send "0.15.1" 260 | 261 | setprototypeof@1.0.3: 262 | version "1.0.3" 263 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" 264 | 265 | "statuses@>= 1.3.1 < 2", statuses@~1.3.1: 266 | version "1.3.1" 267 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" 268 | 269 | type-is@~1.6.14: 270 | version "1.6.14" 271 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" 272 | dependencies: 273 | media-typer "0.3.0" 274 | mime-types "~2.1.13" 275 | 276 | unpipe@~1.0.0, unpipe@1.0.0: 277 | version "1.0.0" 278 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 279 | 280 | utils-merge@1.0.0: 281 | version "1.0.0" 282 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" 283 | 284 | vary@~1.1.0: 285 | version "1.1.1" 286 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" 287 | 288 | --------------------------------------------------------------------------------