{"action":"created","issue":{"url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/2187","repository_url":"https://api.github.com/repos/thepracticaldev/dev.to","labels_url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/2187/labels{/name}","comments_url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/2187/comments","events_url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/2187/events","html_url":"https://github.com/thepracticaldev/dev.to/issues/2187","id":424677064,"node_id":"MDU6SXNzdWU0MjQ2NzcwNjQ=","number":2187,"title":"Use randomly generated IDs in the REST API","user":{"login":"rhymes","id":146201,"node_id":"MDQ6VXNlcjE0NjIwMQ==","avatar_url":"https://avatars3.githubusercontent.com/u/146201?v=4","gravatar_id":"","url":"https://api.github.com/users/rhymes","html_url":"https://github.com/rhymes","followers_url":"https://api.github.com/users/rhymes/followers","following_url":"https://api.github.com/users/rhymes/following{/other_user}","gists_url":"https://api.github.com/users/rhymes/gists{/gist_id}","starred_url":"https://api.github.com/users/rhymes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rhymes/subscriptions","organizations_url":"https://api.github.com/users/rhymes/orgs","repos_url":"https://api.github.com/users/rhymes/repos","events_url":"https://api.github.com/users/rhymes/events{/privacy}","received_events_url":"https://api.github.com/users/rhymes/received_events","type":"User","site_admin":false},"labels":[{"id":1080965527,"node_id":"MDU6TGFiZWwxMDgwOTY1NTI3","url":"https://api.github.com/repos/thepracticaldev/dev.to/labels/triage","name":"triage","color":"ededed","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":1,"created_at":"2019-03-25T00:00:30Z","updated_at":"2019-03-26T14:32:15Z","closed_at":null,"author_association":"CONTRIBUTOR","body":"**Is your feature request related to a problem? Please describe.**\r\n\r\nI'm opening this ticket after having read [this great article about data analysis on dev.to's articles](https://dev.to/daolf/-what-is-the-best-time-to-post-on-devto-a-data-backed-answer--1kob). \r\n\r\nThe question I'd like to set forth, in preparation for a future \"publication\" of the API, is: should dev.to use randomly generated resource IDs instead of exposing \"internal\" autoincrementing integer primary keys or not?\r\n\r\nA \"classic\" best practice in API design is not to expose internal details of your app, separating as much as possible how the data is organized from how is accessible from third parties. \r\n\r\nAutoincrementing primary keys are usually discouraged in public APIs (by some, not by all) mainly for three reasons:\r\n\r\n1. they expose database IDs to the public. Today you might have data in a relational database, tomorrow that data might be elsewhere and those IDs might not mean much because autoincrementing primary keys are local to one data source.\r\n2. by exposing incrementing IDs an onlooker (or a malicious attacker) can gather two information: size of the tables and growth rate\r\n3. it's easier for a malicious attacker to write a script to scrape data\r\n\r\nThis is more a question of policy than a technical argument because, at least for the second of the three reasons, DEV is perhaps perfectly fine with that.\r\n\r\nSome possible alternatives to auto incrementing integer primary keys:\r\n\r\n* UUIDs: PostgreSQL has a [native indexable UUID type](https://www.postgresql.org/docs/9.6/datatype-uuid.html) with functions to generate default UUIDs, like pgcrypto's `gen_random_uuid()`. UUIDs though are not sortable, they kind of look ugly and they are verbose: `https://dev.to/api/articles/2d931510-d99f-494a-8c67-87feb05e1594` \r\n* KSUIDs: they are [quite new](https://segment.com/blog/a-brief-history-of-the-uuid/) and were \"invented\" by Segment. The characteristic they have is that they are sortable and time dependent: `https://dev.to/api/articles/0ujsszwN8NRY24YaXiTIE2VWDTS`\r\n* some other random alphanumeric ID generated in the app (eg. Ruby's `SecureRandom.alphanumeric(20)`): `https://dev.to/api/articles/cDAkKyz38cqjTI1bV5lG`\r\n\r\nMy preference goes to one of the last two options\r\n\r\n**Describe the solution you'd like**\r\n\r\nBecause the API is not public yet, and it's relatively small (only 8 controllers), I think that the transition would be doable if there's consensus on this. After publication and documentation it might be harder, especially because DEV is already a big community and developers are already jumping at the opportunity to use the API (hence the article ;))\r\n\r\nFor obvious reasons there shouldn't be a situation where both (integer IDs and alphanumeric IDs) would work at the same time. That would only strain the system (because it might result in two queries, instead of one). \r\n\r\nThe frontend/SPA would also need to be aligned and updated.\r\n\r\nWhat do you think?\r\n\r\n**Additional context**\r\n\r\nI did a quick tour of some public APIs (starting from [those used by DEV](https://docs.dev.to/addl-tech/) itself and this is what I've found:\r\n\r\n* [Fastly](https://docs.fastly.com/api/purge) uses both URLs (for obvious reasons) and alphanumeric IDs (eg. `SU1Z0isxPaozGVKXdv0eY`) to identify resources, probably generated by the equivalent of Ruby's `SecureRandom.alphanumeric(21)`\r\n* [Cloudinary](https://cloudinary.com/documentation/upload_images#public_id_the_image_identifier) uses a `public_id` which is a randomly generated string (eg. `8jsb1xofxdqamu2rzwt9q`)\r\n* [Algolia](https://www.algolia.com/doc/rest-api/search) is not super clear about it but it seems to be using numeric IDs but in string form\r\n* [Stripe](https://stripe.com/docs/api/charges/object) uses alphanumeric random strings prefixed by a resource identifier, for example `ch_19yUdh2eZvKYlo2CkFVBOZG7` for a charge and `cus_El7v7DRE34iBPx` for a customer\r\n\r\nA few more: \r\n\r\n* [StackOverflow](https://api.stackexchange.com/docs/types/answer) uses integer IDs\r\n* [Twilio](https://www.twilio.com/docs/sms/api/message-resource) uses string IDs with a prefix for type of resource, similar to Stripe\r\n* [PayPal](https://developer.paypal.com/docs/api/orders/v2/#orders_get) uses alphanumeric IDs\r\n\r\nRefs #911 "},"comment":{"url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/comments/476673408","html_url":"https://github.com/thepracticaldev/dev.to/issues/2187#issuecomment-476673408","issue_url":"https://api.github.com/repos/thepracticaldev/dev.to/issues/2187","id":476673408,"node_id":"MDEyOklzc3VlQ29tbWVudDQ3NjY3MzQwOA==","user":{"login":"rhymes","id":146201,"node_id":"MDQ6VXNlcjE0NjIwMQ==","avatar_url":"https://avatars3.githubusercontent.com/u/146201?v=4","gravatar_id":"","url":"https://api.github.com/users/rhymes","html_url":"https://github.com/rhymes","followers_url":"https://api.github.com/users/rhymes/followers","following_url":"https://api.github.com/users/rhymes/following{/other_user}","gists_url":"https://api.github.com/users/rhymes/gists{/gist_id}","starred_url":"https://api.github.com/users/rhymes/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rhymes/subscriptions","organizations_url":"https://api.github.com/users/rhymes/orgs","repos_url":"https://api.github.com/users/rhymes/repos","events_url":"https://api.github.com/users/rhymes/events{/privacy}","received_events_url":"https://api.github.com/users/rhymes/received_events","type":"User","site_admin":false},"created_at":"2019-03-26T14:32:15Z","updated_at":"2019-03-26T14:32:15Z","author_association":"CONTRIBUTOR","body":"> Similar to KSUID is ObjectId that have been in use in MongoDB for a while.\r\n\r\nCool, seems based on the same principle, the ability to sort and extract time information.\r\n\r\n> A fun app is Twitter. They were originally based on Rails and used sequential IDs until they ran into scaling issues and needed to generate IDs on multiple servers at once. You can read about their fix. (I'm not advocating this as a solution, it's just interesting.)\r\n\r\nYeah that's a classic problem in distributed programming after passing a certain scale I guess, Snowflake is mentioned in the [Segment article](https://segment.com/blog/a-brief-history-of-the-uuid/). Although DEV is probably a little away to have those scaling issues I think it would save a lot of pain down the line to guard against that "}}
{"actor":{"display_login":"rhymes"}}