├── Procfile ├── .gitignore ├── .gitattributes ├── .travis.yml ├── .github ├── FUNDING.yml └── build.js ├── public ├── favicon.ico ├── become_a_patron_button.png ├── style.css ├── guide.html └── index.html ├── index.js ├── CHANGELOG.md ├── src └── app.js ├── test └── app.js ├── LICENSE ├── package.json ├── README.md ├── seed.js └── templates ├── GUIDE.md ├── layout.html └── index.html /Procfile: -------------------------------------------------------------------------------- 1 | web: node index.js 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | **/*.log -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | public/* linguist-documentation 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: typicode 2 | patreon: typicode 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typicode/jsonplaceholder/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.github/build.js: -------------------------------------------------------------------------------- 1 | // Convert to markdown 2 | // use layout to 3 | // create index.html 4 | // create guide.html 5 | -------------------------------------------------------------------------------- /public/become_a_patron_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/typicode/jsonplaceholder/HEAD/public/become_a_patron_button.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const app = require('./src/app') 2 | const port = process.env.PORT || 3000 3 | 4 | app.listen(port, () => { 5 | console.log('JSONPlaceholder listening on http://localhost:' + port) 6 | }) 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## 2018-08-16 4 | 5 | * Replace [placehold.it](http://placehold.it) (previous name) with [placeholder.com](http://placeholder.com) (new name) 6 | * Use `https` protocol for image URLs 7 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | const jsonServer = require('json-server') 2 | const clone = require('clone') 3 | const data = require('../data.json') 4 | 5 | const app = jsonServer.create() 6 | const router = jsonServer.router(clone(data), { _isFake: true }) 7 | 8 | app.use((req, res, next) => { 9 | if (req.path === '/') return next() 10 | router.db.setState(clone(data)) 11 | next() 12 | }) 13 | 14 | app.use(jsonServer.defaults({ 15 | logger: process.env.NODE_ENV !== 'production' 16 | })) 17 | 18 | app.use(router) 19 | 20 | module.exports = app 21 | -------------------------------------------------------------------------------- /test/app.js: -------------------------------------------------------------------------------- 1 | const test = require('tape') 2 | const request = require('supertest') 3 | const app = require('../src/app') 4 | 5 | test('GET /', (t) => { 6 | request(app) 7 | .get('/') 8 | .expect(200, (err) => t.end(err)) 9 | }) 10 | 11 | test('POST /', (t) => { 12 | const max = 10 13 | t.plan(max * 3) 14 | 15 | // Test concurrency 16 | for (var i = 0; i < max; i++) { 17 | request(app) 18 | .post('/posts') 19 | .send({ body: 'foo' }) 20 | .expect(201, (err) => { 21 | t.error(err) 22 | // Check that GET /posts length still returns 100 items 23 | request(app) 24 | .get('/posts') 25 | .expect(200, (err, res) => { 26 | t.error(err) 27 | const { length } = res.body 28 | t.equal( 29 | length, 30 | 100, 31 | `more than 100 posts found (${length})` 32 | ) 33 | }) 34 | }) 35 | } 36 | }) 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 typicode 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jsonplaceholder", 3 | "version": "0.3.3", 4 | "description": "A simple fake REST API server for testing and prototyping.", 5 | "keywords": [ 6 | "fake", 7 | "JSON", 8 | "server", 9 | "REST", 10 | "dummy", 11 | "data", 12 | "API", 13 | "testing", 14 | "prototyping" 15 | ], 16 | "homepage": "http://jsonplaceholder.typicode.com", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/typicode/jsonplaceholder.git" 20 | }, 21 | "scripts": { 22 | "build": "node build", 23 | "build:watch": "nodemon --watch build.js --watch templates -e js,md,html build.js", 24 | "start": "node index", 25 | "test": "node test/app" 26 | }, 27 | "dependencies": { 28 | "clone": "^2.1.2", 29 | "json-server": "^0.16.0", 30 | "marked": "^0.8.0" 31 | }, 32 | "devDependencies": { 33 | "Faker": "~0.7.2", 34 | "husky": "^4.2.2", 35 | "nodemon": "^2.0.2", 36 | "pupa": "^2.0.1", 37 | "rosie": "~2.0.1", 38 | "showdown": "^1.9.1", 39 | "supertest": "^4.0.2", 40 | "tape": "^4.13.0", 41 | "underscore": "~1.12.1" 42 | }, 43 | "engines": { 44 | "node": "14.x" 45 | }, 46 | "license": "MIT", 47 | "husky": { 48 | "hooks": { 49 | "pre-commit": "npm test" 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSONPlaceholder 2 | 3 | [JSONPlaceholder](https://jsonplaceholder.typicode.com) is a simple fake REST API for testing and prototyping. 4 | 5 | It's like an [image placeholder](http://placehold.it/) but for web developers. 6 | 7 | JSONPlaceholder is powered by [JSON Server](https://github.com/typicode/json-server). 8 | 9 | 10 | 11 | 12 | 13 | ## Why? 14 | 15 | Most of the time when trying a new library, hacking a prototype or following a tutorial, I found myself in need of some data. 16 | 17 | I didn't like the idea of using some public API because I had the feeling that I was spending more time registering a client and understanding a complex API than focusing on my task. 18 | 19 | But I liked the idea of image placeholders for web designers. So I decided to code a little Express server inspired by that and here is JSONPlaceholder. 20 | 21 | You can find it running here and are free to use it in your developments: https://jsonplaceholder.typicode.com. 22 | 23 | I hope you will find it useful. 24 | 25 | ## Features 26 | 27 | * No registration 28 | * Zero-config 29 | * Basic API 30 | * "Has many" relationships 31 | * Filters and nested resources 32 | * Cross-domain ([CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) and [JSONP](http://en.wikipedia.org/wiki/JSONP)) 33 | * Supports GET, POST, PUT, PATCH, DELETE and OPTIONS verbs 34 | * HTTP or HTTPS 35 | * Compatible with React, Angular, Vue, Ember, ... 36 | 37 | ## Guide 38 | 39 | For examples and more, you can visit https://jsonplaceholder.typicode.com 40 | -------------------------------------------------------------------------------- /seed.js: -------------------------------------------------------------------------------- 1 | // Run this to generate data.json 2 | var fs = require('fs') 3 | var _ = require('underscore') 4 | var Factory = require('rosie').Factory 5 | var Faker = require('Faker') 6 | var db = {} 7 | 8 | // Credit http://www.paulirish.com/2009/random-hex-color-code-snippets/ 9 | function hex() { 10 | return Math.floor(Math.random()*16777215).toString(16) 11 | } 12 | 13 | // Tables 14 | db.posts = [] 15 | db.comments = [] 16 | db.albums = [] 17 | db.photos = [] 18 | db.users = [] 19 | db.todos = [] 20 | 21 | // Factories 22 | Factory.define('post') 23 | .sequence('id') 24 | .attr('title', function() {return Faker.Lorem.sentence()}) 25 | .attr('body', function() {return Faker.Lorem.sentences(4)}) 26 | 27 | Factory.define('comment') 28 | .sequence('id') 29 | .attr('name', function() {return Faker.Lorem.sentence()}) 30 | .attr('email', function() {return Faker.Internet.email()}) 31 | .attr('body', function() {return Faker.Lorem.sentences(4)}) 32 | 33 | Factory.define('album') 34 | .sequence('id') 35 | .attr('title', function() {return Faker.Lorem.sentence()}) 36 | 37 | Factory.define('photo') 38 | .sequence('id') 39 | .attr('title', function() {return Faker.Lorem.sentence()}) 40 | .option('color', hex()) 41 | .attr('url', [ 'color' ], function(color) { 42 | return 'http://placehold.it/600/' + color 43 | }) 44 | .attr('thumbnailUrl', [ 'color' ], function(color) { 45 | return 'http://placehold.it/150/' + color 46 | }) 47 | 48 | Factory.define('todo') 49 | .sequence('id') 50 | .attr('title', function() {return Faker.Lorem.sentence()}) 51 | .attr('completed', function() { return _.random(1) ? true : false}) 52 | 53 | Factory.define('user') 54 | .sequence('id') 55 | .after(function(user) { 56 | var card = Faker.Helpers.userCard() 57 | _.each(card, function(value, key) { 58 | user[key] = value 59 | }) 60 | }) 61 | 62 | // Has many relationships 63 | // Users 64 | _(10).times(function () { 65 | var user = Factory.build('user') 66 | db.users.push(user) 67 | 68 | // Posts 69 | _(10).times(function() { 70 | // userId not set in create so that it appears as the last 71 | // attribute 72 | var post = Factory.build('post', {userId: user.id}) 73 | db.posts.push(post) 74 | 75 | // Comments 76 | _(5).times(function () { 77 | var comment = Factory.build('comment', {postId: post.id}) 78 | db.comments.push(comment) 79 | }) 80 | }) 81 | 82 | // Albums 83 | _(10).times(function() { 84 | var album = Factory.build('album', {userId: user.id}) 85 | db.albums.push(album) 86 | 87 | // Photos 88 | _(50).times(function() { 89 | var photo = Factory.build('photo', {albumId: album.id}) 90 | db.photos.push(photo) 91 | }) 92 | }) 93 | 94 | // Todos 95 | _(20).times(function() { 96 | var todo = Factory.build('todo', {userId: user.id}) 97 | db.todos.push(todo) 98 | }) 99 | }) 100 | 101 | fs.writeFileSync('db.json', JSON.stringify(db, null, 2)); 102 | -------------------------------------------------------------------------------- /public/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: system-ui, BlinkMacSystemFont, -apple-system, Segoe UI, Roboto, 3 | Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 4 | color: rgba(0, 0, 0, 0.84); 5 | line-height: 1.5; 6 | } 7 | 8 | a { 9 | color: #1e87f0; 10 | text-decoration: none; 11 | border-bottom: 1px solid transparent; 12 | } 13 | 14 | div.announcement { 15 | display: block; 16 | padding: 1rem; 17 | font-weight: bold; 18 | border-width: 0; 19 | border-style: solid; 20 | border-color: currentColor; 21 | text-align: center; 22 | background: #ffe0b2; 23 | color: #e65100; 24 | } 25 | 26 | div.announcement a { 27 | color: inherit; 28 | text-decoration: underline; 29 | } 30 | 31 | div.announcement a:hover { 32 | text-decoration: none; 33 | } 34 | 35 | a:hover { 36 | text-decoration: underline; 37 | } 38 | 39 | h1 { 40 | margin: 0; 41 | font-size: 4rem; 42 | font-weight: 300; 43 | letter-spacing: 0.05em; 44 | } 45 | 46 | @media (max-width: 768px) { 47 | h1 { 48 | font-size: 2rem; 49 | } 50 | } 51 | 52 | h2 { 53 | margin-top: 6rem; 54 | margin-bottom: 1.5rem; 55 | font-size: 2rem; 56 | font-weight: normal; 57 | } 58 | 59 | header { 60 | position: sticky; 61 | top: 0; 62 | background: #ffffff; 63 | z-index: 999; 64 | } 65 | 66 | nav { 67 | margin: 0; 68 | overflow-x: auto; 69 | text-align: center; 70 | border-width: 0 0 1px 0; 71 | border-color: #e4e4e4; 72 | border-style: solid; 73 | } 74 | 75 | nav ul { 76 | display: flex; 77 | margin: 0; 78 | padding: 0; 79 | list-style: none; 80 | } 81 | 82 | nav li:first-of-type { 83 | flex-grow: 1; 84 | text-align: left; 85 | } 86 | 87 | nav li:first-of-type a { 88 | padding-left: 0; 89 | } 90 | 91 | nav li:last-of-type a { 92 | padding-right: 0; 93 | } 94 | 95 | nav li a { 96 | display: block; 97 | padding: 1.5rem; 98 | color: inherit; 99 | white-space: nowrap; 100 | } 101 | 102 | .hljs { 103 | padding: 1rem; 104 | } 105 | 106 | td:first-child { 107 | width: 8rem; 108 | } 109 | 110 | .container { 111 | max-width: 60rem; 112 | margin: auto; 113 | padding: 0 1rem; 114 | } 115 | 116 | .hero { 117 | padding: 6rem 0; 118 | text-align: center; 119 | } 120 | 121 | .sponsors { 122 | margin-bottom: 2rem; 123 | padding: 6rem 0; 124 | border-width: 1px 0; 125 | border-style: solid; 126 | border-color: #e4e4e4; 127 | text-align: center; 128 | } 129 | 130 | .sponsors h3 { 131 | font-size: 1.5rem; 132 | font-weight: normal; 133 | margin-top: 0; 134 | margin-bottom: 2rem; 135 | } 136 | 137 | .box { 138 | display: flex; 139 | justify-content: center; 140 | align-items: center; 141 | width: 20rem; 142 | margin: auto; 143 | border-radius: 0.2rem; 144 | border: 1px dashed currentColor; 145 | } 146 | 147 | .box a { 148 | display: inline-block; 149 | padding: 4rem; 150 | color: inherit; 151 | } 152 | 153 | .sponsors p { 154 | margin-top: 2rem; 155 | margin-bottom: 0; 156 | } 157 | 158 | main { 159 | margin-bottom: 6rem; 160 | } 161 | 162 | #run-button { 163 | padding: 0.5rem 1rem; 164 | margin-right: 1rem; 165 | border-width: 0; 166 | border-radius: 0.25rem; 167 | background-color: #1e87f0; 168 | color: white; 169 | cursor: pointer; 170 | transition: all 0.25s; 171 | } 172 | 173 | #run-message { 174 | opacity: 0; 175 | transition: all 0.25s; 176 | } 177 | 178 | pre { 179 | /* hack */ 180 | background: #f8f8f8; 181 | } 182 | 183 | code { 184 | padding: 2rem !important; 185 | } 186 | 187 | ul { 188 | list-style: none; 189 | } 190 | 191 | #result { 192 | margin: 1.5rem 0 0; 193 | height: 176px; 194 | opacity: 0; 195 | transition: all 0.25s; 196 | } 197 | 198 | footer { 199 | padding: 6rem; 200 | background-color: #f8fafc; 201 | text-align: center; 202 | } 203 | -------------------------------------------------------------------------------- /templates/GUIDE.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | ## Guide 4 | 5 | You can use JSONPlaceholder with any type of project that needs to get JSON data (React, Vue, Node, Rails, Swift, Android, ...). 6 | 7 | Below you'll find examples using [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). You can copy paste them in your browser Console to quickly test JSONPlaceholder. 8 | 9 | ### Get a resource 10 | 11 | ```js 12 | fetch('https://jsonplaceholder.typicode.com/posts/1') 13 | .then(response => response.json()) 14 | .then(json => console.log(json)) 15 | 16 | // Output 17 | { 18 | id: 1, 19 | title: '[...]', 20 | body: '[...]', 21 | userId: 1 22 | } 23 | ``` 24 | 25 |
26 | 27 | 28 | ### List all resources 29 | 30 | ```js 31 | fetch('https://jsonplaceholder.typicode.com/posts') 32 | .then(response => response.json()) 33 | .then(json => console.log(json)) 34 | 35 | // Output 36 | [ 37 | { id: 1, title: '[...]' /* ... */ }, 38 | /* ... */ 39 | { id: 100, title: '[...]' /* ... */ } 40 | ] 41 | ``` 42 | 43 | ### Create a resource 44 | 45 | ```js 46 | fetch('https://jsonplaceholder.typicode.com/posts', { 47 | method: 'POST', 48 | body: JSON.stringify({ 49 | title: 'foo', 50 | body: 'bar', 51 | userId: 1 52 | }), 53 | headers: { 54 | "Content-type": "application/json; charset=UTF-8" 55 | } 56 | }) 57 | .then(response => response.json()) 58 | .then(json => console.log(json)) 59 | 60 | // Output 61 | { 62 | id: 101, 63 | title: 'foo', 64 | body: 'bar', 65 | userId: 1 66 | } 67 | ``` 68 | 69 | Important: the resource will not be really created on the server but it will be faked as if. In other words, if you try to access a post using 101 as an id, you'll get a 404 error. 70 | 71 | ### Update a resource 72 | 73 | #### With PUT 74 | 75 | ```js 76 | fetch('https://jsonplaceholder.typicode.com/posts/1', { 77 | method: 'PUT', 78 | body: JSON.stringify({ 79 | id: 1, 80 | title: 'foo', 81 | body: 'bar', 82 | userId: 1 83 | }), 84 | headers: { 85 | "Content-type": "application/json; charset=UTF-8" 86 | } 87 | }) 88 | .then(response => response.json()) 89 | .then(json => console.log(json)) 90 | 91 | // Output 92 | { 93 | id: 1, 94 | title: 'foo', 95 | body: 'bar', 96 | userId: 1 97 | } 98 | ``` 99 | 100 | #### With PATCH 101 | 102 | ```js 103 | fetch('https://jsonplaceholder.typicode.com/posts/1', { 104 | method: 'PATCH', 105 | body: JSON.stringify({ 106 | title: 'foo' 107 | }), 108 | headers: { 109 | "Content-type": "application/json; charset=UTF-8" 110 | } 111 | }) 112 | .then(response => response.json()) 113 | .then(json => console.log(json)) 114 | 115 | // Output 116 | { 117 | id: 1, 118 | title: 'foo', 119 | body: '[...]', 120 | userId: 1 121 | } 122 | ``` 123 | 124 | Important: the resource will not be really updated on the server but it will be faked as if. 125 | 126 | ### Delete a resource 127 | 128 | ```js 129 | fetch('https://jsonplaceholder.typicode.com/posts/1', { 130 | method: 'DELETE' 131 | }) 132 | ``` 133 | 134 | Important: the resource will not be really deleted on the server but it will be faked as if. 135 | 136 | ### Filter resources 137 | 138 | Basic filtering is supported through query parameters. 139 | 140 | ```js 141 | // Will return all the posts that belong to the first user 142 | fetch('https://jsonplaceholder.typicode.com/posts?userId=1') 143 | .then(response => response.json()) 144 | .then(json => console.log(json)) 145 | ``` 146 | 147 | ### Nested resources 148 | 149 | One level of nested route is available. 150 | 151 | ```js 152 | // Equivalent to /comments?postId=1 153 | fetch('https://jsonplaceholder.typicode.com/posts/1/comments') 154 | .then(response => response.json()) 155 | .then(json => console.log(json)) 156 | ``` 157 | 158 | Available nested routes: 159 | 160 | * https://jsonplaceholder.typicode.com/posts/1/comments 161 | * https://jsonplaceholder.typicode.com/albums/1/photos 162 | * https://jsonplaceholder.typicode.com/users/1/albums 163 | * https://jsonplaceholder.typicode.com/users/1/todos 164 | * https://jsonplaceholder.typicode.com/users/1/posts 165 | 166 |
167 | -------------------------------------------------------------------------------- /templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 14 | 18 | 19 | 25 | 28 | JSONPlaceholder - Fake online REST API for developers 29 | 30 | 31 | 32 |
33 |
34 | This service is maintained and provided for free, please consider 35 | supporting it on 36 | GitHub Sponsors 39 | ❤️ 40 |
41 | 51 |
52 | 53 |
54 | {content} 55 |
56 | 57 | 58 | 80 | 81 | 82 | 110 | 111 | 112 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

5 | JSONPlaceholder 6 |

7 | 8 |

9 | Fake Online REST API for Testing and Prototyping 10 |
Serving ~350M requests per month 11 |
Powered by 12 | JSON Server 13 | + 14 | LowDB 15 |

16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 |
24 | 25 | 26 |
27 |

Gold Sponsors

28 | 29 |

30 | 31 | 32 | 33 |

34 | 35 |

36 | 37 | 38 | 39 |

40 | 41 |

42 | Your Company Logo Here 43 |

44 |
45 | 46 | 47 |
48 |
49 | 50 |

Intro

51 |

52 | JSONPlaceholder is a free online REST API that you can use whenever you need some fake data. 53 |
It's great for tutorials, testing new libraries, sharing code examples, ... 54 |

55 | 56 | 57 |

Example

58 |

59 | Run this code in a console or from any site: 60 |

61 | 62 |
fetch('https://jsonplaceholder.typicode.com/todos/1')
 63 |   .then(response => response.json())
 64 |   .then(json => console.log(json))
 65 | 
66 | 67 |

68 | 69 |

70 | 71 |
72 | Congrats you've made your first call to JSONPlaceholder! 😃 🎉 73 | 74 |

75 | Tip: you can use 76 | 77 | http:// 78 | or 79 | 80 | https:// 81 | when making requests to JSONPlaceholder. 82 |

83 | 84 |
85 | 86 | 87 | 88 |

Resources

89 |

90 | JSONPlaceholder comes with a set of 6 common resources: 91 |

92 | 93 | 94 | 95 | 98 | 99 | 100 | 101 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 | 116 | 117 | 118 | 119 | 122 | 123 | 124 | 125 | 128 | 129 | 130 |
96 | /posts 97 | 100 posts
102 | /comments 103 | 500 comments
108 | /albums 109 | 100 albums
114 | /photos 115 | 5000 photos
120 | /todos 121 | 200 todos
126 | /users 127 | 10 users
131 | 132 |

133 | Note: resources have relations. For example: 134 | posts have many 135 | comments, 136 | albums have many 137 | photos, ... see below for routes examples. 138 |

139 | 140 | 141 |

Routes

142 |

143 | All HTTP methods are supported. 144 |

145 | 146 | 147 | 148 | 149 | 152 | 153 | 154 | 155 | 158 | 159 | 160 | 161 | 164 | 165 | 166 | 167 | 170 | 171 | 172 | 173 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 |
GET 150 | /posts 151 |
GET 156 | /posts/1 157 |
GET 162 | /posts/1/comments 163 |
GET 168 | /comments?postId=1 169 |
GET 174 | /posts?userId=1 175 |
POST/posts
PUT/posts/1
PATCH/posts/1
DELETE/posts/1
195 | 196 |

197 | Note: you can view detailed examples 198 | here. 199 |

200 | 201 | 202 |

Use your own data

203 | 210 | 211 |

212 | With My JSON Server online service and a simple GitHub repo, you can have your own online fake REST server in seconds. 213 |

214 |
215 |
216 | -------------------------------------------------------------------------------- /public/guide.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 14 | 18 | 19 | 25 | 28 | JSONPlaceholder - Fake online REST API for developers 29 | 30 | 31 | 32 |
33 |
34 | This service is maintained and provided for free, please consider 35 | supporting it on 36 | GitHub Sponsors 39 | ❤️ 40 |
41 | 51 |
52 | 53 |
54 |

55 |

Guide

56 |

You can use JSONPlaceholder with any type of project that needs to get JSON data (React, Vue, Node, Rails, Swift, Android, …).

57 |

Below you'll find examples using Fetch API. You can copy paste them in your browser Console to quickly test JSONPlaceholder.

58 |

Get a resource

59 |
fetch('https://jsonplaceholder.typicode.com/posts/1')
 60 |   .then(response => response.json())
 61 |   .then(json => console.log(json))
 62 | 
 63 | // Output
 64 | {
 65 |   id: 1,
 66 |   title: '[...]',
 67 |   body: '[...]',
 68 |   userId: 1
 69 | }
 70 | 
71 |
72 | 73 |

List all resources

74 |
fetch('https://jsonplaceholder.typicode.com/posts')
 75 |   .then(response => response.json())
 76 |   .then(json => console.log(json))
 77 | 
 78 | // Output
 79 | [
 80 |   { id: 1, title: '[...]' /* ... */ },
 81 |   /* ... */
 82 |   { id: 100, title: '[...]' /* ... */ }
 83 | ]
 84 | 
85 |

Create a resource

86 |
fetch('https://jsonplaceholder.typicode.com/posts', {
 87 |     method: 'POST',
 88 |     body: JSON.stringify({
 89 |       title: 'foo',
 90 |       body: 'bar',
 91 |       userId: 1
 92 |     }),
 93 |     headers: {
 94 |       "Content-type": "application/json; charset=UTF-8"
 95 |     }
 96 |   })
 97 |   .then(response => response.json())
 98 |   .then(json => console.log(json))
 99 | 
100 | // Output
101 | {
102 |   id: 101,
103 |   title: 'foo',
104 |   body: 'bar',
105 |   userId: 1
106 | }
107 | 
108 |

Important: the resource will not be really created on the server but it will be faked as if. In other words, if you try to access a post using 101 as an id, you'll get a 404 error.

109 |

Update a resource

110 |

With PUT

111 |
fetch('https://jsonplaceholder.typicode.com/posts/1', {
112 |     method: 'PUT',
113 |     body: JSON.stringify({
114 |       id: 1,
115 |       title: 'foo',
116 |       body: 'bar',
117 |       userId: 1
118 |     }),
119 |     headers: {
120 |       "Content-type": "application/json; charset=UTF-8"
121 |     }
122 |   })
123 |   .then(response => response.json())
124 |   .then(json => console.log(json))
125 | 
126 | // Output
127 | {
128 |   id: 1,
129 |   title: 'foo',
130 |   body: 'bar',
131 |   userId: 1
132 | }
133 | 
134 |

With PATCH

135 |
fetch('https://jsonplaceholder.typicode.com/posts/1', {
136 |     method: 'PATCH',
137 |     body: JSON.stringify({
138 |       title: 'foo'
139 |     }),
140 |     headers: {
141 |       "Content-type": "application/json; charset=UTF-8"
142 |     }
143 |   })
144 |   .then(response => response.json())
145 |   .then(json => console.log(json))
146 | 
147 | // Output
148 | {
149 |   id: 1,
150 |   title: 'foo',
151 |   body: '[...]',
152 |   userId: 1
153 | }
154 | 
155 |

Important: the resource will not be really updated on the server but it will be faked as if.

156 |

Delete a resource

157 |
fetch('https://jsonplaceholder.typicode.com/posts/1', {
158 |   method: 'DELETE'
159 | })
160 | 
161 |

Important: the resource will not be really deleted on the server but it will be faked as if.

162 |

Filter resources

163 |

Basic filtering is supported through query parameters.

164 |
// Will return all the posts that belong to the first user
165 | fetch('https://jsonplaceholder.typicode.com/posts?userId=1')
166 |   .then(response => response.json())
167 |   .then(json => console.log(json))
168 | 
169 |

Nested resources

170 |

One level of nested route is available.

171 |
// Equivalent to /comments?postId=1
172 | fetch('https://jsonplaceholder.typicode.com/posts/1/comments')
173 |   .then(response => response.json())
174 |   .then(json => console.log(json))
175 | 
176 |

Available nested routes:

177 | 184 |

185 |
186 | 187 | 188 | 210 | 211 | 212 | 240 | 241 | 242 | 285 | 286 | 287 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 13 | 14 | 18 | 19 | 25 | 28 | JSONPlaceholder - Fake online REST API for developers 29 | 30 | 31 | 32 |
33 |
34 | This service is maintained and provided for free, please consider 35 | supporting it on 36 | GitHub Sponsors 39 | ❤️ 40 |
41 | 51 |
52 | 53 |
54 | 55 |
56 |
57 |

58 | JSONPlaceholder 59 |

60 | 61 |

62 | Fake Online REST API for Testing and Prototyping 63 |
Serving ~350M requests per month 64 |
Powered by 65 | JSON Server 66 | + 67 | LowDB 68 |

69 | 70 | 71 | 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 |
80 |

Gold Sponsors

81 | 82 |

83 | 84 | 85 | 86 |

87 | 88 |

89 | 90 | 91 | 92 |

93 | 94 |

95 | Your Company Logo Here 96 |

97 |
98 | 99 | 100 |
101 |
102 | 103 |

Intro

104 |

105 | JSONPlaceholder is a free online REST API that you can use whenever you need some fake data. 106 |
It's great for tutorials, testing new libraries, sharing code examples, ... 107 |

108 | 109 | 110 |

Example

111 |

112 | Run this code in a console or from any site: 113 |

114 | 115 |
fetch('https://jsonplaceholder.typicode.com/todos/1')
116 |   .then(response => response.json())
117 |   .then(json => console.log(json))
118 | 
119 | 120 |

121 | 122 |

123 | 124 |
125 | Congrats you've made your first call to JSONPlaceholder! 😃 🎉 126 | 127 |

128 | Tip: you can use 129 | 130 | http:// 131 | or 132 | 133 | https:// 134 | when making requests to JSONPlaceholder. 135 |

136 | 137 |
138 | 139 | 140 | 141 |

Resources

142 |

143 | JSONPlaceholder comes with a set of 6 common resources: 144 |

145 | 146 | 147 | 148 | 151 | 152 | 153 | 154 | 157 | 158 | 159 | 160 | 163 | 164 | 165 | 166 | 169 | 170 | 171 | 172 | 175 | 176 | 177 | 178 | 181 | 182 | 183 |
149 | /posts 150 | 100 posts
155 | /comments 156 | 500 comments
161 | /albums 162 | 100 albums
167 | /photos 168 | 5000 photos
173 | /todos 174 | 200 todos
179 | /users 180 | 10 users
184 | 185 |

186 | Note: resources have relations. For example: 187 | posts have many 188 | comments, 189 | albums have many 190 | photos, ... see below for routes examples. 191 |

192 | 193 | 194 |

Routes

195 |

196 | All HTTP methods are supported. 197 |

198 | 199 | 200 | 201 | 202 | 205 | 206 | 207 | 208 | 211 | 212 | 213 | 214 | 217 | 218 | 219 | 220 | 223 | 224 | 225 | 226 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 |
GET 203 | /posts 204 |
GET 209 | /posts/1 210 |
GET 215 | /posts/1/comments 216 |
GET 221 | /comments?postId=1 222 |
GET 227 | /posts?userId=1 228 |
POST/posts
PUT/posts/1
PATCH/posts/1
DELETE/posts/1
248 | 249 |

250 | Note: you can view detailed examples 251 | here. 252 |

253 | 254 | 255 |

Use your own data

256 | 263 | 264 |

265 | With My JSON Server online service and a simple GitHub repo, you can have your own online fake REST server in seconds. 266 |

267 |
268 |
269 | 270 |
271 | 272 | 273 | 295 | 296 | 297 | 325 | 326 | 327 | 370 | 371 | 372 | --------------------------------------------------------------------------------