{"action":"created","comment":{"url":"https://api.github.com/repos/Kinto/kinto-website/pulls/comments/91090693","pull_request_review_id":11600365,"id":91090693,"diff_hunk":"@@ -0,0 +1,247 @@\n+Title: How to develop a WebApp with Kinto\n+Date: 2016-12-01 10:20\n+Slug: develop-a-chat-webapp-with-kinto\n+Authors: Enguerran Colson, Frank Taillandier, Kinto Team\n+Summary: An example of how Kinto handles a webapp's data storage.\n+\n+_This post was [originally published in french on Enguerran Colson's blog](https://blog.ticabri.com/2016/11/29/developper-une-webapp-avec-kinto/)._\n+\n+## Our goal\n+\n+Hi folks, today, we are gonna create a simple WebApp that allows visitors to chat in a room accessible from a public URL.\n+\n+![KintoChat, our instant chat WebApp](images/kintochat-fullscreen.png)\n+{.image}\n+\n+* A really simple chat webapp with minimal UI.\n+* We will need a bit of JavaScript to enhance and animate interactions within the application and we will also need a way to store and share the app's data. Ideally, we would like our application to consume a REST API exposing endpoints like `https://api.discute.re/v1/rooms/12345/messages`, where `discute.re` is the domain of our application (*discutere* means to chat in Latin).\n+\n+Our API endpoints would be:\n+\n+* `/rooms` to return all chat rooms,\n+* `/rooms/:id/` to return a particular chat room identified by an ID,\n+* `/rooms/:id/messages` to return all messages from a particular room.\n+\n+To post a message, our front-end will do a POST request to `/rooms/:id/messages`.\n+\n+We would store each message like this:\n+\n+```json\n+{\n+    \"message\": \"I know nothing\",\n+    \"last_modified\": 1480340246147,\n+    \"author\": \"Jon Snow\",\n+    \"id\": \"a1e6e879-5c94-4a01-9ec2-28e152d1d8f4\"\n+}\n+```\n+\n+The JavaScript code could use whatever library or latest hype JS framework but in our example we will stick with modern [Vanilla JS](http://vanilla-js.com/) and use top notch [ES2015 syntax](https://babeljs.io/docs/learn-es2015/).\n+\n+## API creation\n+\n+Hmm… what backend should we use? Django? Express? Firebase?… oh wait, why don’t we give [Kinto](http://www.kinto-storage.org/) a try?\n+\n+Kinto provides a flexible and generic enough API to address the needs of many different kinds of application. Call us lazy, effective or pragmatic but Kinto will prevent us to write our own API and help us handle other APIs.\n+\n+Let's see how to use Kinto for our instant chat WebApp.\n+\n+To show some pride, we will use an explicit subdomain for our main URL `https://kinto.discute.re/v1` to show our configuration rather than an agnostic https://api.discute.re/v1.\n+\n+Using Kinto, here are the native API endpoints we will use to match our application requirements:\n+\n+- `/rooms/4815162342` becomes `/collections/4815162342` ;\n+- `/rooms/4815162342/messages` becomes `/collections/4815162342/records` ;\n+\n+As we have seen before, we can add a new post to our backend with a simple POST request\n+`/collections/4815162342/records`.\n+\n+A Kinto server can handle many Web applications through the concept of [*buckets*](https://kinto.readthedocs.io/en/latest/concepts.html#buckets-collections-and-records); a bucket can contain many *collections*, a collection can contain many *records*, and records can contain arbitrary JSON data.\n+\n+![](https://kinto.readthedocs.io/en/latest/_images/concepts-general.png)\n+{.image}\n+\n+For our application, we’ll create a `chat` bucket, which will contain as many collections as we want distinct chat rooms. Each room collection will itself represent chat messages through records.\n+\n+You can use the [Kinto Admin](http://kinto.github.io/kinto-admin/) to visually browse and manage your application data.\n+\n+![Our records in Kinto Admin](images/kinto-admin-webchat-example.png)\n+{.image}\n+\n+With this in mind:\n+\n+* We will retrieve all messages for a 4815162342 room by requesting `GET https://kinto.discute.re/v1/buckets/chat/collections/4815162342/records`\n+* We will post new messages to the room using `POST https://kinto.discute.re/buckets/chat/collections/4815162342/records`\n+\n+It's very similar to our first envisioned API calls which were:\n+\n+* `GET https://api.dicute.re/v1/rooms/4815162342/messages`,\n+* `POST https://api.dicute.re/v1/rooms/4815162342/messages`.\n+\n+## Let’s install Kinto\n+\n+There are many ways to [install (or deploy) Kinto](https://kinto.readthedocs.io/en/stable/tutorials/install.html):\n+\n+* [on Heroku](https://kinto.readthedocs.io/en/stable/tutorials/install.html#deploying-on-cloud-providers),\n+* [with Docker](https://kinto.readthedocs.io/en/stable/tutorials/install.html#using-docker),\n+* [using a Python package](https://kinto.readthedocs.io/en/stable/tutorials/install.html#using-the-python-package).\n+\n+If you want to play with Kinto, an ephemeral instance is also available on [https://kinto.dev.mozaws.net/v1/](https://kinto.dev.mozaws.net/v1/).\n+\n+Once deployed, we have access to our `https://kinto.discute.re/v1` default URL that returns:\n+\n+```json\n+{\n+    \"project_version\": \"5.0\",\n+    \"settings\": {\n+        \"readonly\": false,\n+        \"batch_max_requests\": 25\n+    },\n+    \"capabilities\": {\n+        \"admin\": {\n+            \"description\": \"Serves the admin console.\",\n+            \"version\": \"1.5.0\",\n+            \"url\": \"https://github.com/Kinto/kinto-admin/\"\n+        },\n+        \"default_bucket\": {\n+            \"description\": \"The default bucket is an alias for a personal bucket where collections are created implicitly.\",\n+            \"url\": \"https://kinto.readthedocs.io/en/latest/api/1.x/buckets.html#personal-bucket-default\"\n+        }\n+    },\n+    \"project_docs\": \"https://kinto.readthedocs.io/\",\n+    \"project_name\": \"kinto\",\n+    \"http_api_version\": \"1.12\",\n+    \"url\": \"http://kinto.discute.re/v1/\"\n+\n+}\n+```\n+\n+And that's it! Now we can move to the front-end development phase.\n+\n+## Viva JavaScript!\n+\n+In order to get the messages, we will have to write a bit of code to get the room's id through the application URL:\n+\n+```js\n+// https://discute.re/#4815162342  is mapped to the collection 4815162342\n+this.collectionName = window.location.hash.slice(1);\n+```\n+\n+Then we need to do a GET request to get the list of all room's messages.","path":"content/2016.12.how-to-develop-a-webapp-with-Kinto.md","position":129,"original_position":129,"commit_id":"b56be193064afe90966defc8407300612ddb6173","original_commit_id":"b56be193064afe90966defc8407300612ddb6173","user":{"login":"enguerran","id":701648,"avatar_url":"https://avatars.githubusercontent.com/u/701648?v=3","gravatar_id":"","url":"https://api.github.com/users/enguerran","html_url":"https://github.com/enguerran","followers_url":"https://api.github.com/users/enguerran/followers","following_url":"https://api.github.com/users/enguerran/following{/other_user}","gists_url":"https://api.github.com/users/enguerran/gists{/gist_id}","starred_url":"https://api.github.com/users/enguerran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/enguerran/subscriptions","organizations_url":"https://api.github.com/users/enguerran/orgs","repos_url":"https://api.github.com/users/enguerran/repos","events_url":"https://api.github.com/users/enguerran/events{/privacy}","received_events_url":"https://api.github.com/users/enguerran/received_events","type":"User","site_admin":false},"body":"Nit?","created_at":"2016-12-06T14:43:16Z","updated_at":"2016-12-06T14:43:16Z","html_url":"https://github.com/Kinto/kinto-website/pull/14#discussion_r91090693","pull_request_url":"https://api.github.com/repos/Kinto/kinto-website/pulls/14","_links":{"self":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/comments/91090693"},"html":{"href":"https://github.com/Kinto/kinto-website/pull/14#discussion_r91090693"},"pull_request":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/14"}}},"pull_request":{"url":"https://api.github.com/repos/Kinto/kinto-website/pulls/14","id":96255929,"html_url":"https://github.com/Kinto/kinto-website/pull/14","diff_url":"https://github.com/Kinto/kinto-website/pull/14.diff","patch_url":"https://github.com/Kinto/kinto-website/pull/14.patch","issue_url":"https://api.github.com/repos/Kinto/kinto-website/issues/14","number":14,"state":"open","locked":false,"title":"Blog post:  Develop a webapp with Kinto","user":{"login":"DirtyF","id":103008,"avatar_url":"https://avatars.githubusercontent.com/u/103008?v=3","gravatar_id":"","url":"https://api.github.com/users/DirtyF","html_url":"https://github.com/DirtyF","followers_url":"https://api.github.com/users/DirtyF/followers","following_url":"https://api.github.com/users/DirtyF/following{/other_user}","gists_url":"https://api.github.com/users/DirtyF/gists{/gist_id}","starred_url":"https://api.github.com/users/DirtyF/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DirtyF/subscriptions","organizations_url":"https://api.github.com/users/DirtyF/orgs","repos_url":"https://api.github.com/users/DirtyF/repos","events_url":"https://api.github.com/users/DirtyF/events{/privacy}","received_events_url":"https://api.github.com/users/DirtyF/received_events","type":"User","site_admin":false},"body":"This post is a translation of @ticabri's https://blog.ticabri.com/2016/11/29/developper-une-webapp-avec-kinto/\r\n\r\nSubmitting to review.\r\n\r\n","created_at":"2016-12-02T10:33:28Z","updated_at":"2016-12-06T14:43:16Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6e904027e8b025bd0a402b5224d0673415836f55","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/Kinto/kinto-website/pulls/14/commits","review_comments_url":"https://api.github.com/repos/Kinto/kinto-website/pulls/14/comments","review_comment_url":"https://api.github.com/repos/Kinto/kinto-website/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Kinto/kinto-website/issues/14/comments","statuses_url":"https://api.github.com/repos/Kinto/kinto-website/statuses/b56be193064afe90966defc8407300612ddb6173","head":{"label":"DirtyF:post-develop-a-webapp","ref":"post-develop-a-webapp","sha":"b56be193064afe90966defc8407300612ddb6173","user":{"login":"DirtyF","id":103008,"avatar_url":"https://avatars.githubusercontent.com/u/103008?v=3","gravatar_id":"","url":"https://api.github.com/users/DirtyF","html_url":"https://github.com/DirtyF","followers_url":"https://api.github.com/users/DirtyF/followers","following_url":"https://api.github.com/users/DirtyF/following{/other_user}","gists_url":"https://api.github.com/users/DirtyF/gists{/gist_id}","starred_url":"https://api.github.com/users/DirtyF/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DirtyF/subscriptions","organizations_url":"https://api.github.com/users/DirtyF/orgs","repos_url":"https://api.github.com/users/DirtyF/repos","events_url":"https://api.github.com/users/DirtyF/events{/privacy}","received_events_url":"https://api.github.com/users/DirtyF/received_events","type":"User","site_admin":false},"repo":{"id":75208944,"name":"kinto-website","full_name":"DirtyF/kinto-website","owner":{"login":"DirtyF","id":103008,"avatar_url":"https://avatars.githubusercontent.com/u/103008?v=3","gravatar_id":"","url":"https://api.github.com/users/DirtyF","html_url":"https://github.com/DirtyF","followers_url":"https://api.github.com/users/DirtyF/followers","following_url":"https://api.github.com/users/DirtyF/following{/other_user}","gists_url":"https://api.github.com/users/DirtyF/gists{/gist_id}","starred_url":"https://api.github.com/users/DirtyF/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/DirtyF/subscriptions","organizations_url":"https://api.github.com/users/DirtyF/orgs","repos_url":"https://api.github.com/users/DirtyF/repos","events_url":"https://api.github.com/users/DirtyF/events{/privacy}","received_events_url":"https://api.github.com/users/DirtyF/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/DirtyF/kinto-website","description":"Website for the kinto ecosystem","fork":true,"url":"https://api.github.com/repos/DirtyF/kinto-website","forks_url":"https://api.github.com/repos/DirtyF/kinto-website/forks","keys_url":"https://api.github.com/repos/DirtyF/kinto-website/keys{/key_id}","collaborators_url":"https://api.github.com/repos/DirtyF/kinto-website/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/DirtyF/kinto-website/teams","hooks_url":"https://api.github.com/repos/DirtyF/kinto-website/hooks","issue_events_url":"https://api.github.com/repos/DirtyF/kinto-website/issues/events{/number}","events_url":"https://api.github.com/repos/DirtyF/kinto-website/events","assignees_url":"https://api.github.com/repos/DirtyF/kinto-website/assignees{/user}","branches_url":"https://api.github.com/repos/DirtyF/kinto-website/branches{/branch}","tags_url":"https://api.github.com/repos/DirtyF/kinto-website/tags","blobs_url":"https://api.github.com/repos/DirtyF/kinto-website/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/DirtyF/kinto-website/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/DirtyF/kinto-website/git/refs{/sha}","trees_url":"https://api.github.com/repos/DirtyF/kinto-website/git/trees{/sha}","statuses_url":"https://api.github.com/repos/DirtyF/kinto-website/statuses/{sha}","languages_url":"https://api.github.com/repos/DirtyF/kinto-website/languages","stargazers_url":"https://api.github.com/repos/DirtyF/kinto-website/stargazers","contributors_url":"https://api.github.com/repos/DirtyF/kinto-website/contributors","subscribers_url":"https://api.github.com/repos/DirtyF/kinto-website/subscribers","subscription_url":"https://api.github.com/repos/DirtyF/kinto-website/subscription","commits_url":"https://api.github.com/repos/DirtyF/kinto-website/commits{/sha}","git_commits_url":"https://api.github.com/repos/DirtyF/kinto-website/git/commits{/sha}","comments_url":"https://api.github.com/repos/DirtyF/kinto-website/comments{/number}","issue_comment_url":"https://api.github.com/repos/DirtyF/kinto-website/issues/comments{/number}","contents_url":"https://api.github.com/repos/DirtyF/kinto-website/contents/{+path}","compare_url":"https://api.github.com/repos/DirtyF/kinto-website/compare/{base}...{head}","merges_url":"https://api.github.com/repos/DirtyF/kinto-website/merges","archive_url":"https://api.github.com/repos/DirtyF/kinto-website/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/DirtyF/kinto-website/downloads","issues_url":"https://api.github.com/repos/DirtyF/kinto-website/issues{/number}","pulls_url":"https://api.github.com/repos/DirtyF/kinto-website/pulls{/number}","milestones_url":"https://api.github.com/repos/DirtyF/kinto-website/milestones{/number}","notifications_url":"https://api.github.com/repos/DirtyF/kinto-website/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/DirtyF/kinto-website/labels{/name}","releases_url":"https://api.github.com/repos/DirtyF/kinto-website/releases{/id}","deployments_url":"https://api.github.com/repos/DirtyF/kinto-website/deployments","created_at":"2016-11-30T17:08:50Z","updated_at":"2016-11-30T17:08:51Z","pushed_at":"2016-12-06T13:40:29Z","git_url":"git://github.com/DirtyF/kinto-website.git","ssh_url":"git@github.com:DirtyF/kinto-website.git","clone_url":"https://github.com/DirtyF/kinto-website.git","svn_url":"https://github.com/DirtyF/kinto-website","homepage":"http://www.kinto-storage.org/","size":2317,"stargazers_count":0,"watchers_count":0,"language":"CSS","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":1,"forks":1,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"Kinto:master","ref":"master","sha":"df1369ebe3587296e7b54197e494b8f5de6f0816","user":{"login":"Kinto","id":13413813,"avatar_url":"https://avatars.githubusercontent.com/u/13413813?v=3","gravatar_id":"","url":"https://api.github.com/users/Kinto","html_url":"https://github.com/Kinto","followers_url":"https://api.github.com/users/Kinto/followers","following_url":"https://api.github.com/users/Kinto/following{/other_user}","gists_url":"https://api.github.com/users/Kinto/gists{/gist_id}","starred_url":"https://api.github.com/users/Kinto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kinto/subscriptions","organizations_url":"https://api.github.com/users/Kinto/orgs","repos_url":"https://api.github.com/users/Kinto/repos","events_url":"https://api.github.com/users/Kinto/events{/privacy}","received_events_url":"https://api.github.com/users/Kinto/received_events","type":"Organization","site_admin":false},"repo":{"id":38381879,"name":"kinto-website","full_name":"Kinto/kinto-website","owner":{"login":"Kinto","id":13413813,"avatar_url":"https://avatars.githubusercontent.com/u/13413813?v=3","gravatar_id":"","url":"https://api.github.com/users/Kinto","html_url":"https://github.com/Kinto","followers_url":"https://api.github.com/users/Kinto/followers","following_url":"https://api.github.com/users/Kinto/following{/other_user}","gists_url":"https://api.github.com/users/Kinto/gists{/gist_id}","starred_url":"https://api.github.com/users/Kinto/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Kinto/subscriptions","organizations_url":"https://api.github.com/users/Kinto/orgs","repos_url":"https://api.github.com/users/Kinto/repos","events_url":"https://api.github.com/users/Kinto/events{/privacy}","received_events_url":"https://api.github.com/users/Kinto/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Kinto/kinto-website","description":"Website for the kinto ecosystem","fork":false,"url":"https://api.github.com/repos/Kinto/kinto-website","forks_url":"https://api.github.com/repos/Kinto/kinto-website/forks","keys_url":"https://api.github.com/repos/Kinto/kinto-website/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Kinto/kinto-website/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Kinto/kinto-website/teams","hooks_url":"https://api.github.com/repos/Kinto/kinto-website/hooks","issue_events_url":"https://api.github.com/repos/Kinto/kinto-website/issues/events{/number}","events_url":"https://api.github.com/repos/Kinto/kinto-website/events","assignees_url":"https://api.github.com/repos/Kinto/kinto-website/assignees{/user}","branches_url":"https://api.github.com/repos/Kinto/kinto-website/branches{/branch}","tags_url":"https://api.github.com/repos/Kinto/kinto-website/tags","blobs_url":"https://api.github.com/repos/Kinto/kinto-website/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Kinto/kinto-website/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Kinto/kinto-website/git/refs{/sha}","trees_url":"https://api.github.com/repos/Kinto/kinto-website/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Kinto/kinto-website/statuses/{sha}","languages_url":"https://api.github.com/repos/Kinto/kinto-website/languages","stargazers_url":"https://api.github.com/repos/Kinto/kinto-website/stargazers","contributors_url":"https://api.github.com/repos/Kinto/kinto-website/contributors","subscribers_url":"https://api.github.com/repos/Kinto/kinto-website/subscribers","subscription_url":"https://api.github.com/repos/Kinto/kinto-website/subscription","commits_url":"https://api.github.com/repos/Kinto/kinto-website/commits{/sha}","git_commits_url":"https://api.github.com/repos/Kinto/kinto-website/git/commits{/sha}","comments_url":"https://api.github.com/repos/Kinto/kinto-website/comments{/number}","issue_comment_url":"https://api.github.com/repos/Kinto/kinto-website/issues/comments{/number}","contents_url":"https://api.github.com/repos/Kinto/kinto-website/contents/{+path}","compare_url":"https://api.github.com/repos/Kinto/kinto-website/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Kinto/kinto-website/merges","archive_url":"https://api.github.com/repos/Kinto/kinto-website/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Kinto/kinto-website/downloads","issues_url":"https://api.github.com/repos/Kinto/kinto-website/issues{/number}","pulls_url":"https://api.github.com/repos/Kinto/kinto-website/pulls{/number}","milestones_url":"https://api.github.com/repos/Kinto/kinto-website/milestones{/number}","notifications_url":"https://api.github.com/repos/Kinto/kinto-website/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Kinto/kinto-website/labels{/name}","releases_url":"https://api.github.com/repos/Kinto/kinto-website/releases{/id}","deployments_url":"https://api.github.com/repos/Kinto/kinto-website/deployments","created_at":"2015-07-01T16:22:24Z","updated_at":"2016-11-07T17:06:54Z","pushed_at":"2016-12-06T08:39:42Z","git_url":"git://github.com/Kinto/kinto-website.git","ssh_url":"git@github.com:Kinto/kinto-website.git","clone_url":"https://github.com/Kinto/kinto-website.git","svn_url":"https://github.com/Kinto/kinto-website","homepage":"http://www.kinto-storage.org/","size":2593,"stargazers_count":2,"watchers_count":2,"language":"CSS","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":8,"mirror_url":null,"open_issues_count":5,"forks":8,"open_issues":5,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/14"},"html":{"href":"https://github.com/Kinto/kinto-website/pull/14"},"issue":{"href":"https://api.github.com/repos/Kinto/kinto-website/issues/14"},"comments":{"href":"https://api.github.com/repos/Kinto/kinto-website/issues/14/comments"},"review_comments":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/14/comments"},"review_comment":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Kinto/kinto-website/pulls/14/commits"},"statuses":{"href":"https://api.github.com/repos/Kinto/kinto-website/statuses/b56be193064afe90966defc8407300612ddb6173"}}}}
{"actor":{"display_login":"enguerran"}}