├── CONTRIBUTING.md ├── CONTRIBUTORS.md ├── LICENSE.md ├── README.md └── tr └── README.md /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | 3 | We welcome contributions to this guide and discussion about its 4 | contents. Please open an issue or pull request on this repository to 5 | propose a change. 6 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | ## Contributors 2 | 3 | * Wesley Beary 4 | * Mark McGranaghan 5 | * Jamu Kakar 6 | * Jonathan Roes 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ## License 2 | 3 | Copyright the [project contributors](CONTRIBUTORS.md). 4 | 5 | Released under a [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/). 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HTTP API Design Guide 2 | 3 | ## Introduction 4 | 5 | This guide describes a set of HTTP+JSON API design practices, originally 6 | extracted from work on the [Heroku Platform API](https://devcenter.heroku.com/articles/platform-api-reference). 7 | 8 | This guide informs additions to that API and also guides new internal 9 | APIs at Heroku. We hope it’s also of interest to API designers 10 | outside of Heroku. 11 | 12 | Our goals here are consistency and focusing on business logic while 13 | avoiding design bikeshedding. We’re looking for _a good, consistent, 14 | well-documented way_ to design APIs, not necessarily _the only/ideal 15 | way_. 16 | 17 | We assume you’re familiar with the basics of HTTP+JSON APIs and won’t 18 | cover all of the fundamentals of those in this guide. 19 | 20 | We welcome [contributions](CONTRIBUTING.md) to this guide. 21 | 22 | ## Contents 23 | 24 | * [Foundations](#foundations) 25 | * [Separate Concerns](#separate-concerns) 26 | * [Require Secure Connections](#require-secure-connections) 27 | * [Require Versioning in the Accepts Header](#require-versioning-in-the-accepts-header) 28 | * [Support ETags for Caching](#support-etags-for-caching) 29 | * [Provide Request-Ids for Introspection](#provide-request-ids-for-introspection) 30 | * [Divide Large Responses Across Requests with Ranges](#divide-large-responses-across-requests-with-ranges) 31 | * [Requests](#requests) 32 | * [Return appropriate status codes](#return-appropriate-status-codes) 33 | * [Provide full resources where available](#provide-full-resources-where-available) 34 | * [Accept serialized JSON in request bodies](#accept-serialized-json-in-request-bodies) 35 | * [Use consistent path formats](#use-consistent-path-formats) 36 | * [Downcase paths and attributes](#downcase-paths-and-attributes) 37 | * [Support non-id dereferencing for convenience](#support-non-id-dereferencing-for-convenience) 38 | * [Minimize path nesting](#minimize-path-nesting) 39 | * [Responses](#responses) 40 | * [Provide resource (UU)IDs](#provide-resource-uuids) 41 | * [Provide standard timestamps](#provide-standard-timestamps) 42 | * [Use UTC times formatted in ISO8601](#use-utc-times-formatted-in-iso8601) 43 | * [Nest foreign key relations](#nest-foreign-key-relations) 44 | * [Generate structured errors](#generate-structured-errors) 45 | * [Show rate limit status](#show-rate-limit-status) 46 | * [Keep JSON minified in all responses](#keep-json-minified-in-all-responses) 47 | * [Artifacts](#artifacts) 48 | * [Provide machine-readable JSON schema](#provide-machine-readable-json-schema) 49 | * [Provide human-readable docs](#provide-human-readable-docs) 50 | * [Provide executable examples](#provide-executable-examples) 51 | * [Describe stability](#describe-stability) 52 | * [Translations](#translations) 53 | 54 | ### Foundations 55 | 56 | #### Separate Concerns 57 | 58 | Keep things simple while designing by separating the concerns between the 59 | different parts of the request and response cycle. Keeping simple rules here 60 | allows for greater focus on larger and harder problems. 61 | 62 | Requests and responses will be made to address a particular resource or 63 | collection. Use the path to indicate identity, the body to transfer the 64 | contents and headers to communicate metadata. Query params may be used as a 65 | means to pass header information also in edge cases, but headers are preferred 66 | as they are more flexible and can convey more diverse information. 67 | 68 | #### Require Secure Connections 69 | 70 | Require secure connections with TLS to access the API, without exception. 71 | It’s not worth trying to figure out or explain when it is OK to use TLS 72 | and when it’s not. Just require TLS for everything. 73 | 74 | Ideally, simply reject any non-TLS requests by not responding to requests for 75 | http or port 80 to avoid any insecure data exchange. In environments where this 76 | is not possible, respond with `403 Forbidden`. 77 | 78 | Redirects are discouraged since they allow sloppy/bad client behaviour without 79 | providing any clear gain. Clients that rely on redirects double up on 80 | server traffic and render TLS useless since sensitive data will already 81 | have been exposed during the first call. 82 | 83 | #### Require Versioning in the Accepts Header 84 | 85 | Versioning and the transition between versions can be one of the more 86 | challenging aspects of designing and operating an API. As such, it is best to 87 | start with some mechanisms in place to mitigate this from the start. 88 | 89 | To prevent surprise, breaking changes to users, it is best to require a version 90 | be specified with all requests. Default versions should be avoided as they are 91 | very difficult, at best, to change in the future. 92 | 93 | It is best to provide version specification in the headers, with other 94 | metadata, using the `Accept` header with a custom content type, e.g.: 95 | 96 | ``` 97 | Accept: application/vnd.heroku+json; version=3 98 | ``` 99 | 100 | #### Support ETags for Caching 101 | 102 | Include an `ETag` header in all responses, identifying the specific 103 | version of the returned resource. This allows users to cache resources 104 | and use requests with this value in the `If-None-Match` header to determine 105 | if the cache should be updated. 106 | 107 | #### Provide Request-Ids for Introspection 108 | 109 | Include a `Request-Id` header in each API response, populated with a 110 | UUID value. By logging these values on the client, server and any backing 111 | services, it provides a mechanism to trace, diagnose and debug requests. 112 | 113 | #### Divide Large Responses Across Requests with Ranges 114 | 115 | Large responses should be broken across multiple requests using `Range` headers 116 | to specify when more data is available and how to retrieve it. See the 117 | [Heroku Platform API discussion of Ranges](https://devcenter.heroku.com/articles/platform-api-reference#ranges) 118 | for the details of request and response headers, status codes, limits, 119 | ordering, and iteration. 120 | 121 | ### Requests 122 | 123 | #### Return appropriate status codes 124 | 125 | Return appropriate HTTP status codes with each response. Successful 126 | responses should be coded according to this guide: 127 | 128 | * `200`: Request succeeded for a `GET` call, for a `DELETE` or 129 | `PATCH` call that completed synchronously, or for a `PUT` call that 130 | synchronously updated an existing resource 131 | * `201`: Request succeeded for a `POST` call that completed 132 | synchronously, or for a `PUT` call that synchronously created a new 133 | resource 134 | * `202`: Request accepted for a `POST`, `PUT`, `DELETE`, or `PATCH` call that 135 | will be processed asynchronously 136 | * `206`: Request succeeded on `GET`, but only a partial response 137 | returned: see [above on ranges](#divide-large-responses-across-requests-with-ranges) 138 | 139 | Pay attention to the use of authentication and authorization error codes: 140 | 141 | * `401 Unauthorized`: Request failed because user is not authenticated 142 | * `403 Forbidden`: Request failed because user does not have authorization to access a specific resource 143 | 144 | Return suitable codes to provide additional information when there are errors: 145 | 146 | * `422 Unprocessable Entity`: Your request was understood, but contained invalid parameters 147 | * `429 Too Many Requests`: You have been rate-limited, retry later 148 | * `500 Internal Server Error`: Something went wrong on the server, check status site and/or report the issue 149 | 150 | Refer to the [HTTP response code spec](https://tools.ietf.org/html/rfc7231#section-6) 151 | for guidance on status codes for user error and server error cases. 152 | 153 | #### Provide full resources where available 154 | 155 | Provide the full resource representation (i.e. the object with all 156 | attributes) whenever possible in the response. Always provide the full 157 | resource on 200 and 201 responses, including `PUT`/`PATCH` and `DELETE` 158 | requests, e.g.: 159 | 160 | ```bash 161 | $ curl -X DELETE \ 162 | https://service.com/apps/1f9b/domains/0fd4 163 | 164 | HTTP/1.1 200 OK 165 | Content-Type: application/json;charset=utf-8 166 | ... 167 | { 168 | "created_at": "2012-01-01T12:00:00Z", 169 | "hostname": "subdomain.example.com", 170 | "id": "01234567-89ab-cdef-0123-456789abcdef", 171 | "updated_at": "2012-01-01T12:00:00Z" 172 | } 173 | ``` 174 | 175 | 202 responses will not include the full resource representation, 176 | e.g.: 177 | 178 | ```bash 179 | $ curl -X DELETE \ 180 | https://service.com/apps/1f9b/dynos/05bd 181 | 182 | HTTP/1.1 202 Accepted 183 | Content-Type: application/json;charset=utf-8 184 | ... 185 | {} 186 | ``` 187 | 188 | #### Accept serialized JSON in request bodies 189 | 190 | Accept serialized JSON on `PUT`/`PATCH`/`POST` request bodies, either 191 | instead of or in addition to form-encoded data. This creates symmetry 192 | with JSON-serialized response bodies, e.g.: 193 | 194 | ```bash 195 | $ curl -X POST https://service.com/apps \ 196 | -H "Content-Type: application/json" \ 197 | -d '{"name": "demoapp"}' 198 | 199 | { 200 | "id": "01234567-89ab-cdef-0123-456789abcdef", 201 | "name": "demoapp", 202 | "owner": { 203 | "email": "username@example.com", 204 | "id": "01234567-89ab-cdef-0123-456789abcdef" 205 | }, 206 | ... 207 | } 208 | ``` 209 | 210 | #### Use consistent path formats 211 | 212 | ##### Resource names 213 | 214 | Use the plural version of a resource name unless the resource in question is a singleton within the system (for example, in most systems a given user would only ever have one account). This keeps it consistent in the way you refer to particular resources. 215 | 216 | ##### Actions 217 | 218 | Prefer endpoint layouts that don’t need any special actions for 219 | individual resources. In cases where special actions are needed, place 220 | them under a standard `actions` prefix, to clearly delineate them: 221 | 222 | ``` 223 | /resources/:resource/actions/:action 224 | ``` 225 | 226 | e.g. 227 | 228 | ``` 229 | /runs/{run_id}/actions/stop 230 | ``` 231 | 232 | #### Downcase paths and attributes 233 | 234 | Use downcased and dash-separated path names, for alignment with 235 | hostnames, e.g: 236 | 237 | ``` 238 | service-api.com/users 239 | service-api.com/app-setups 240 | ``` 241 | 242 | Downcase attributes as well, but use underscore separators so that 243 | attribute names can be typed without quotes in JavaScript, e.g.: 244 | 245 | ``` 246 | service_class: "first" 247 | ``` 248 | 249 | #### Support non-id dereferencing for convenience 250 | 251 | In some cases it may be inconvenient for end-users to provide IDs to 252 | identify a resource. For example, a user may think in terms of a Heroku 253 | app name, but that app may be identified by a UUID. In these cases you 254 | may want to accept both an id or name, e.g.: 255 | 256 | ```bash 257 | $ curl https://service.com/apps/{app_id_or_name} 258 | $ curl https://service.com/apps/97addcf0-c182 259 | $ curl https://service.com/apps/www-prod 260 | ``` 261 | 262 | Do not accept only names to the exclusion of IDs. 263 | 264 | #### Minimize path nesting 265 | 266 | In data models with nested parent/child resource relationships, paths 267 | may become deeply nested, e.g.: 268 | 269 | ``` 270 | /orgs/{org_id}/apps/{app_id}/dynos/{dyno_id} 271 | ``` 272 | 273 | Limit nesting depth by preferring to locate resources at the root 274 | path. Use nesting to indicate scoped collections. For example, for the 275 | case above where a dyno belongs to an app belongs to an org: 276 | 277 | ``` 278 | /orgs/{org_id} 279 | /orgs/{org_id}/apps 280 | /apps/{app_id} 281 | /apps/{app_id}/dynos 282 | /dynos/{dyno_id} 283 | ``` 284 | 285 | ### Responses 286 | 287 | #### Provide resource (UU)IDs 288 | 289 | Give each resource an `id` attribute by default. Use UUIDs unless you 290 | have a very good reason not to. Don’t use IDs that won’t be globally 291 | unique across instances of the service or other resources in the 292 | service, especially auto-incrementing IDs. 293 | 294 | Render UUIDs in downcased `8-4-4-4-12` format, e.g.: 295 | 296 | ``` 297 | "id": "01234567-89ab-cdef-0123-456789abcdef" 298 | ``` 299 | 300 | #### Provide standard timestamps 301 | 302 | Provide `created_at` and `updated_at` timestamps for resources by default, 303 | e.g: 304 | 305 | ```javascript 306 | { 307 | // ... 308 | "created_at": "2012-01-01T12:00:00Z", 309 | "updated_at": "2012-01-01T13:00:00Z", 310 | // ... 311 | } 312 | ``` 313 | 314 | These timestamps may not make sense for some resources, in which case 315 | they can be omitted. 316 | 317 | #### Use UTC times formatted in ISO8601 318 | 319 | Accept and return times in UTC only. Render times in ISO8601 format, 320 | e.g.: 321 | 322 | ``` 323 | "finished_at": "2012-01-01T12:00:00Z" 324 | ``` 325 | 326 | #### Nest foreign key relations 327 | 328 | Serialize foreign key references with a nested object, e.g.: 329 | 330 | ```javascript 331 | { 332 | "name": "service-production", 333 | "owner": { 334 | "id": "5d8201b0..." 335 | }, 336 | // ... 337 | } 338 | ``` 339 | 340 | Instead of e.g.: 341 | 342 | ```javascript 343 | { 344 | "name": "service-production", 345 | "owner_id": "5d8201b0...", 346 | // ... 347 | } 348 | ``` 349 | 350 | This approach makes it possible to inline more information about the 351 | related resource without having to change the structure of the response 352 | or introduce more top-level response fields, e.g.: 353 | 354 | ```javascript 355 | { 356 | "name": "service-production", 357 | "owner": { 358 | "id": "5d8201b0...", 359 | "name": "Alice", 360 | "email": "alice@heroku.com" 361 | }, 362 | // ... 363 | } 364 | ``` 365 | 366 | #### Generate structured errors 367 | 368 | Generate consistent, structured response bodies on errors. Include a 369 | machine-readable error `id`, a human-readable error `message`, and 370 | optionally a `url` pointing the client to further information about the 371 | error and how to resolve it, e.g.: 372 | 373 | ``` 374 | HTTP/1.1 429 Too Many Requests 375 | ``` 376 | 377 | ```json 378 | { 379 | "id": "rate_limit", 380 | "message": "Account reached its API rate limit.", 381 | "url": "https://docs.service.com/rate-limits" 382 | } 383 | ``` 384 | 385 | Document your error format and the possible error `id`s that clients may 386 | encounter. 387 | 388 | #### Show rate limit status 389 | 390 | Rate limit requests from clients to protect the health of the service 391 | and maintain high service quality for other clients. You can use a 392 | [token bucket algorithm](http://en.wikipedia.org/wiki/Token_bucket) to 393 | quantify request limits. 394 | 395 | Return the remaining number of request tokens with each request in the 396 | `RateLimit-Remaining` response header. 397 | 398 | #### Keep JSON minified in all responses 399 | 400 | Extra whitespace adds needless response size to requests, and many 401 | clients for human consumption will automatically "prettify" JSON 402 | output. It is best to keep JSON responses minified e.g.: 403 | 404 | ```json 405 | {"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"} 406 | ``` 407 | 408 | Instead of e.g.: 409 | 410 | ```json 411 | { 412 | "beta": false, 413 | "email": "alice@heroku.com", 414 | "id": "01234567-89ab-cdef-0123-456789abcdef", 415 | "last_login": "2012-01-01T12:00:00Z", 416 | "created_at": "2012-01-01T12:00:00Z", 417 | "updated_at": "2012-01-01T12:00:00Z" 418 | } 419 | ``` 420 | 421 | You may consider optionally providing a way for clients to retreive 422 | more verbose response, either via a query parameter (e.g. `?pretty=true`) 423 | or via an `Accept` header param (e.g. 424 | `Accept: application/vnd.heroku+json; version=3; indent=4;`). 425 | 426 | ### Artifacts 427 | 428 | #### Provide machine-readable JSON schema 429 | 430 | Provide a machine-readable schema to exactly specify your API. Use 431 | [prmd](https://github.com/interagent/prmd) to manage your schema, and ensure 432 | it validates with `prmd verify`. 433 | 434 | #### Provide human-readable docs 435 | 436 | Provide human-readable documentation that client developers can use to 437 | understand your API. 438 | 439 | If you create a schema with prmd as described above, you can easily 440 | generate Markdown docs for all endpoints with with `prmd doc`. 441 | 442 | In addition to endpoint details, provide an API overview with 443 | information about: 444 | 445 | * Authentication, including acquiring and using authentication tokens. 446 | * API stability and versioning, including how to select the desired API 447 | version. 448 | * Common request and response headers. 449 | * Error serialization format. 450 | * Examples of using the API with clients in different languages. 451 | 452 | #### Provide executable examples 453 | 454 | Provide executable examples that users can type directly into their 455 | terminals to see working API calls. To the greatest extent possible, 456 | these examples should be usable verbatim, to minimize the amount of 457 | work a user needs to do to try the API, e.g.: 458 | 459 | ```bash 460 | $ export TOKEN=... # acquire from dashboard 461 | $ curl -is https://$TOKEN@service.com/users 462 | ``` 463 | 464 | If you use [prmd](https://github.com/interagent/prmd) to generate Markdown 465 | docs, you will get examples for each endpoint for free. 466 | 467 | #### Describe stability 468 | 469 | Describe the stability of your API or its various endpoints according to 470 | its maturity and stability, e.g. with prototype/development/production 471 | flags. 472 | 473 | See the [Heroku API compatibility policy](https://devcenter.heroku.com/articles/api-compatibility-policy) 474 | for a possible stability and change management approach. 475 | 476 | Once your API is declared production-ready and stable, do not make 477 | backwards incompatible changes within that API version. If you need to 478 | make backwards-incompatible changes, create a new API with an 479 | incremented version number. 480 | 481 | 482 | ### Translations 483 | * [Korean version](https://github.com/yoondo/http-api-design) (based on [f38dba6](https://github.com/interagent/http-api-design/commit/f38dba6fd8e2b229ab3f09cd84a8828987188863)), by [@yoondo](https://github.com/yoondo/) 484 | * [Simplified Chinese version](https://github.com/ZhangBohan/http-api-design-ZH_CN) (based on [337c4a0](https://github.com/interagent/http-api-design/commit/337c4a05ad08f25c5e232a72638f063925f3228a)), by [@ZhangBohan](https://github.com/ZhangBohan/) 485 | * [Traditional Chinese version](https://github.com/kcyeu/http-api-design) (based on [232f8dc](https://github.com/interagent/http-api-design/commit/232f8dc6a941d0b25136bf64998242dae5575f66)), by [@kcyeu](https://github.com/kcyeu/) 486 | 487 | -------------------------------------------------------------------------------- /tr/README.md: -------------------------------------------------------------------------------- 1 | # HTTP API Tasarım Kılavuzu 2 | 3 | ## Giriş 4 | 5 | Bu kılavuz bir takım HTTP+JSON API tasarımı uygulamalarını açıklar ve 6 | [Heroku Platform API](https://devcenter.heroku.com/articles/platform-api-reference) 7 | çalışmalarından ortaya çıkmıştır. 8 | 9 | Bu kılavuz Heroku'nun yeni iç API'lerini yönlendirirken API hakkında da bilgi 10 | verir. Umarız Heroku dışındaki API tasarımcılarına da yarar sağlar. 11 | 12 | Bizim amaçlarımız oyalanma tasarımından kaçarak tutarlılık ve iş mantığına 13 | odaklanmak. API tasarımı için _sadece ve en ideal olan yolu_ değil _iyi, 14 | tutarlı, güzel dokümante edilmiş bir yol_ aramaktayız. 15 | 16 | Basit HTTP+JSON API arayüzü hakkında bilgi sahibi olduğunuzu varsayıyoruz ve 17 | bu kılavuz API'nin temel konularından bir çok şeyi kapsamayacak. 18 | 19 | Bu kılavuza [katkıları](CONTRIBUTING.md) kabul ediyoruz. 20 | 21 | ## İçerik 22 | 23 | * [Temeller](#temeller) 24 | * [Kaygılarınızı Parçalayın](#kaygılarınızı-parçalayın) 25 | * [Güvenli Bir Bağlantı Gereklidir](#güvenli-bir-bağlantı-gereklidir) 26 | * [Sürüm Bilgisi için "Accepts" Başlığı Gereklidir](#sürüm-bilgisi-için-accepts-başlığı-gereklidir) 27 | * [Önbellekleme için ETags Desteği](#Önbellekleme-için-etags-desteği) 28 | * [Gözlemlemek için `Request-Ids` Oluşturun](#gözlemlemek-için-request-ids-oluşturun) 29 | * [Range'ler ile Yüksek Boyuttaki Cevapları Parçalara Bölün](#rangeler-ile-yüksek-boyuttaki-cevapları-parçalara-bölün) 30 | * [İstekler](#İstekler) 31 | * [Uygun durum kodları(status codes) döndürün](#uygun-durum-kodlarıstatus-codes-döndürün) 32 | * [Uygun Olan Yerlerde Tüm Kaynakları Sunun](#uygun-olan-yerlerde-tüm-kaynakları-sunun) 33 | * [İstek gövdesinde JSON Kabul Edin](#İstek-gövdesinde-json-kabul-edin) 34 | * [Kararlı URL Yolu Formatı Kullanın](#kararlı-url-yolu-formatı-kullanın) 35 | * [Kaynak İsimleri](#kaynak-İsimleri) 36 | * [Olaylar](#olaylar) 37 | * [URL ve Niteliklerde Küçük Harf Kullanın](#downcase-paths-and-attributes) 38 | * [ID Baz Alınmadan Veri Çekmeyi Destekleyin](#id-baz-alınmadan-veri-Çekmeyi-destekleyin) 39 | * [Çok Dallanan URL Yollarını (nested path) Azaltın](#Çok-dallanan-url-yollarını-nested-path-azaltın) 40 | * [Cevaplar](#cevaplar) 41 | * [Kaynaklar için (UU)ID Oluşturun](#kaynaklar-için-uuid-oluşturun) 42 | * [Standart Zaman Damgaları(timestamp) Oluşturun](#standart-zaman-damgalarıtimestamp-oluşturun) 43 | * [ISO8601'deki UTC zamanını kullanın](#iso8601deki-utc-zaman-formatını-kullanın) 44 | * [Dallanan Nesnelerin (Nested Object) İlişkilendirimesi](#dallanan-nesnelerin-nested-object-İlişkilendirimesi) 45 | * [Belirli Yapıda Hatalar Oluşturun](#belirli-yapıda-hatalar-oluşturun) 46 | * [`Rate Limit` Durumunu Gösterin](#rate-limit-durumunu-gösterin) 47 | * [Bütün Cevaplarda JSON Veriniz Sıkıştırılmış(minified) Olsun](#bütün-cevaplarda-json-veriniz-sıkıştırılmışminified-olsun) 48 | * [Artifacts](#artifacts) 49 | * [Programların Okuyabileceği(Machine-readable) JSON Şeması Oluşturun](#programların-okuyabileceğimachine-readable-json-Şeması-oluşturun) 50 | * [İnsanların Okuyabileceği Dokümanlar Oluşturun](#İnsanların-okuyabileceği-dokümanlar-oluşturun) 51 | * [Çalıştırılabilir Örnekler Oluşturun](#Çalıştırılabilir-Örnekler-oluşturun) 52 | * [İstikrarı Açıklayın](#İstikrarı-açıklayın) 53 | * [Çeviriler](#ceviriler) 54 | 55 | ### Temeller 56 | 57 | #### Kaygılarınızı Parçalayın 58 | 59 | Tasarım sırasında nesneleri(kaygılarınızı) istek(request) ve cevap(response) 60 | döngüsündeki farklı bölümler arasında parçalayarak basite indirgeyin. Kuralların 61 | basit tutulması büyük ve zor sorunlar için daha fazla odaklanma sağlar. 62 | 63 | İstek ve cevaplar belirli bir kaynak veya koleksiyon adresine yapılacaktır. 64 | Kimliği belirlemek için adres yolunu, içeriği iletmek için gövdeyi ve meta veri 65 | iletişimi için başlıkları kullanın. Sorgu parametreleri farklı durumlarda başlık(header) 66 | verilerini iletmek için kullanılabilir, ama başlıklar ile iletmek daha esnek ve 67 | daha çeşitli bilgi göndermek için tercih edilir. 68 | 69 | #### Güvenli Bir Bağlantı Gereklidir 70 | 71 | API'ye erişim için istisnasız TLS(Transport Layer Security) ile güvenli bir bağlantı kullanın. 72 | 73 | Güvensiz veri alışverişini önlemek için http veya 80 portu üzerinden gelen 74 | isteklere yanıt vermeyerek, TLS olmayan istekleri basitçe reddet. Mümkün olmayan 75 | ortamlarda `403 Forbidden` ile yanıt ver. 76 | 77 | Herhangi bir net kazancı olmadan özensiz/kötü istemci(client) davranışlarına 78 | izin verdiği için yönlendirmelerden kaçınılmalıdır. İstemciler yönlendirmelere 79 | güvenerek sunucu trafiğini ikiye katlarlar ve hassas veriler ilk sorguda 80 | korunmasız kaldığından TLS kullanmanın bir anlamı olmaz. 81 | 82 | #### Sürüm Bilgisi için "Accepts" Başlığı Gereklidir 83 | 84 | Sürüm ve sürümler arası geçişler API'nin işletilmesi ve tasarlanması aşamasının 85 | en zor yanlarından birisidir. Bunun gibi mekanizmalar ile başlamak, en baştan 86 | bu sıkıntıları azaltmak için en iyisidir. 87 | 88 | Süprizleri önlemek, kullanıcıların değişikliklerini kırmak için en iyi yöntem 89 | bütün isteklerde bir sürüm gerekliliği en iyisidir. Bu anlamda en iyisi, daha 90 | sonra bir değişiklik yapmanın zor olmasını engellemek için varsayılan versiyonlar 91 | kullanılmamalıdır. 92 | 93 | Sürüm özelliklerini başlıklar içerisinde diğer meta veriler ile birlikte sunmak 94 | en iyisidir. `Accept` başlığını kullanma örneği: 95 | 96 | ``` 97 | Accept: application/vnd.heroku+json; version=3 98 | ``` 99 | 100 | #### Önbellekleme için ETags Desteği 101 | 102 | Bütün cevaplar(responses), dönen cevabın içeriğine özel tanımlayıcılar olan, 103 | `ETag` içermelidir. Bu kullanıcılara kaynakları önbelleklemek için ve kendi 104 | belleğindeki(cache) verinin güncellenip güncellemeyeceğini karşılaştırmak 105 | için isteklerde kullanmalarına izin verir. 106 | [`If-None-Match`](https://tools.ietf.org/html/rfc2616#section-14.26) 107 | 108 | #### Gözlemlemek için `Request-Ids` Oluşturun 109 | 110 | Her API cevabında UUID değeri ile doldurulmuş, `Request-Id` başlığı olmalıdır. 111 | Bu değeri, istekleri `trace`, `diagnose` ve `debug` edebilmek için, sunucu, 112 | istemci(client) ve diğer her servis tarafında günlükleme (logging) için 113 | kullanabilirsiniz. 114 | 115 | #### Range'ler ile Yüksek Boyuttaki Cevapları Parçalara Bölün 116 | 117 | Yüksek boyutlardaki cevapları(responses) [`Range`](https://tools.ietf.org/html/rfc2616#section-14.35) 118 | başlığını kullanarak bir kaç parçaya bölebilirsiniz. İstek ve cevapların 119 | başlıklar, durum kodları, limitler, sıralama ve tekrarlama(iteration) hakkında 120 | daha fazla bilgi için [Heroku Platform API discussion of Ranges](https://devcenter.heroku.com/articles/platform-api-reference#ranges) 121 | bağlantısını takip edebilirsiniz. 122 | 123 | ### İstekler 124 | 125 | #### Uygun Durum Kodları(status codes) Döndürün 126 | 127 | Her cevapla birlikte cevaba uygun HTTP durum kodları döndürün. Başarılı cevaplar 128 | bu kılavuza uygun olmalı: 129 | 130 | * `200`: `GET` metodu ile yapılan istek başarılıdır. `DELETE` veya `PATCH` metodu ile yapılan istekler(requests) senkronlu bir şekilde tamamlanmıştır, veya `PUT` metodu ile yapılan istek(request) senkron bir şekilde var olan içeriği güncellemiştir. 131 | * `201`: Senkron bir şekilde yapılan `POST` veya senkron bir şekilde yeni bir içerik yaratan`PUT` isteği(request) başarılı olarak tamamlanmıştır. 132 | * `202`: `POST`, `PUT`, `DELETE`, veya `PATCH` metodu ile asenkron bir şekilde yapılan istek(request) kabul edilmiştir. 133 | * `206`: `GET` ile yapılan istek(request) başarılıdır, fakat sadece cevabın(response) bir kısmı dönmüştür: bakınız [Range'ler ile Yüksek Boyuttaki Cevapları Parçalara Bölün](#divide-large-responses-across-requests-with-ranges) 134 | 135 | Doğrulama(authentication) ve yetki(authorization) kodlarını kullanmaya dikkat edin: 136 | 137 | * `401 Unauthorized`: Kullanıcı yetkilendirilmediği için istek(request) başarısız olmuştur. 138 | * `403 Forbidden`: Kullanıcının belli bir bölüme ulaşma yetkisi olmadığı için istek başarısız olmuştur. 139 | 140 | Ek bilgilerin eklenmesi konusunda bir hata yapıldığında uygun kodları dönün: 141 | 142 | * `422 Unprocessable Entity`: Yapılan istek anlamlandırılmış, fakat gönderilen parametler doğru değildir. 143 | * `429 Too Many Requests`: Yapılan istek sayısı izin verilen limite ulaşmıştır, tekrar deneyin. 144 | * `500 Internal Server Error`: Sunucu üzerinde bir şeyler ters gitti, kontrol edin veya yetkili kişiye rapor edin. 145 | 146 | Sunucu ve kullanıcı hata durum kodları hakkında daha fazla bilgi için 147 | [HTTP response code spec](https://tools.ietf.org/html/rfc7231#section-6) 148 | adresini kontrol edebilirsiniz. 149 | 150 | #### Uygun Olan Yerlerde Tüm Kaynakları Sunun 151 | 152 | İmkan olduğu sürece tüm [kaynakları](https://tools.ietf.org/html/rfc7231#section-2) 153 | (örneğin: bir nesnenin tüm niteliklerini) cevap olarak dönün. `PUT`/`PATCH` 154 | ve `DELETE` istekleri dahil, [200](https://tools.ietf.org/html/rfc7231#section-6.3.1) 155 | ve [201](https://tools.ietf.org/html/rfc7231#section-6.3.2) 156 | cevaplarında daima tüm kaynakları geri döndürün, örneğin: 157 | 158 | ```bash 159 | $ curl -X DELETE \ 160 | https://service.com/apps/1f9b/domains/0fd4 161 | 162 | HTTP/1.1 200 OK 163 | Content-Type: application/json;charset=utf-8 164 | ... 165 | { 166 | "created_at": "2012-01-01T12:00:00Z", 167 | "hostname": "subdomain.example.com", 168 | "id": "01234567-89ab-cdef-0123-456789abcdef", 169 | "updated_at": "2012-01-01T12:00:00Z" 170 | } 171 | ``` 172 | [202](https://tools.ietf.org/html/rfc7231#section-6.3.3) cevapları 173 | kaynakları(resources) içermeyecektir. 174 | Örneğin: 175 | 176 | ```bash 177 | $ curl -X DELETE \ 178 | https://service.com/apps/1f9b/dynos/05bd 179 | 180 | HTTP/1.1 202 Accepted 181 | Content-Type: application/json;charset=utf-8 182 | ... 183 | {} 184 | ``` 185 | 186 | #### İstek gövdesinde JSON Kabul Edin 187 | 188 | `form-encoded` veriyi kullanmak ya da buna ek olarak kullanmak yerine 189 | `PUT`/`PATCH`/`POST` istek gövdelerinde JSON verilerini kabul edin. Bu bir 190 | JSON-serialized cevap gövdesi ile bir simetri oluşturacaktır. 191 | 192 | ```bash 193 | $ curl -X POST https://service.com/apps \ 194 | -H "Content-Type: application/json" \ 195 | -d '{"name": "demoapp"}' 196 | 197 | { 198 | "id": "01234567-89ab-cdef-0123-456789abcdef", 199 | "name": "demoapp", 200 | "owner": { 201 | "email": "username@example.com", 202 | "id": "01234567-89ab-cdef-0123-456789abcdef" 203 | }, 204 | ... 205 | } 206 | ``` 207 | 208 | #### Kararlı URL Yolu Formatı Kullanın 209 | 210 | ##### Kaynak İsimleri 211 | 212 | Eğer kaynak sistemde tekil değilse kaynakların çoğul isimlerini kullanın 213 | (Örneğin, bir çok sistemde kullanıcıların sadece bir kullanıcı hesabı vardır). 214 | Bu özel kaynaklara tutarlılık katar. 215 | 216 | ##### Olaylar 217 | 218 | Özel bir aksiyon gerektiren durumlarda olayları standart bir `actions` öneki ile 219 | tanımlayın: 220 | 221 | ``` 222 | /resources/:resource/actions/:action 223 | ``` 224 | 225 | Örneğin: 226 | 227 | ``` 228 | /runs/{run_id}/actions/stop 229 | ``` 230 | 231 | #### URL ve Niteliklerde Küçük Harf Kullanın 232 | 233 | URL yolu için küçük harf ve `-` ile ayrılmış (dash-seperated) isimler kullanın. 234 | Örneğin: 235 | 236 | ``` 237 | service-api.com/users 238 | service-api.com/app-setups 239 | ``` 240 | 241 | Nitelikleri(attributes) küçük harfe çevirin, kelimeleri `_` kullanarak ayırın. 242 | Böylelikle Javascript'te tırnak işareti kullanmadan yazılabilir. Örneğin: 243 | 244 | ``` 245 | service_class: "first" 246 | ``` 247 | 248 | #### ID Baz Alınmadan Veri Çekmeyi Destekleyin 249 | 250 | Bazı durumlarda son kullanıcı için kaynağı ID ile ilişkilendirmek kolay 251 | olmayabilir. Örneğin, kullanıcılar Heroku uygulama isimleri üzerinden 252 | düşünüyorlar, ama uygulama bir UUID tarafından ile ilişkilendirilmiş olabilir. 253 | Bu durumda id ve name terimlerinin ikisi ile de ulaşılabilir olabilir. Örneğin: 254 | 255 | ```bash 256 | $ curl https://service.com/apps/{app_id_or_name} 257 | $ curl https://service.com/apps/97addcf0-c182 258 | $ curl https://service.com/apps/www-prod 259 | ``` 260 | Bu ID'yi hariç tutup sadece isim ile veri çekilebilir yapmak değildir. 261 | 262 | #### Çok Dallanan URL Yollarını (nested path) Azaltın 263 | 264 | Veri modelinizdeki iç içe ilişkili kaynaklar için çok fazla alt dalları oluşan 265 | URL yollarından kaçının. Aşağıdaki örnek bu karmaşık yapıya örnektir. 266 | 267 | ``` 268 | /orgs/{org_id}/apps/{app_id}/dynos/{dyno_id} 269 | ``` 270 | 271 | Derin ilişkilerin dallanan yollarını ana yollarda kalacak şekilde kısıtlayın. 272 | Örneğin, aşağıdaki örnekte `dyno` bir organizasyonun uygulamasıdır: 273 | 274 | ``` 275 | /orgs/{org_id} 276 | /orgs/{org_id}/apps 277 | /apps/{app_id} 278 | /apps/{app_id}/dynos 279 | /dynos/{dyno_id} 280 | ``` 281 | 282 | ### Cevaplar 283 | 284 | #### Kaynaklar için (UU)ID Oluşturun 285 | 286 | Her kaynak için varsayılan olarak bir `id` parametresi oluşturun. Kullanmamak 287 | için iyi bir sebebiniz olana kadar UUID'leri kullanın. Tüm heryerde tekil 288 | olmayan ID'leri kullanmayın. ID'ler genelde otomatik artan (autoincrement) 289 | olduğu için diğer servislerde yine karşılaşılabilirdir. 290 | 291 | UUID'lerin formatı küçük harflerle ve `8-4-4-4-12` şeklindedir. Örneğin: 292 | 293 | ``` 294 | "id": "01234567-89ab-cdef-0123-456789abcdef" 295 | ``` 296 | 297 | #### Standart Zaman Damgaları(timestamp) Oluşturun 298 | 299 | `created_at` ve `updated_at` zaman damgalarını varsayılan olarak oluşturun. 300 | Örneğin: 301 | 302 | ```javascript 303 | { 304 | // ... 305 | "created_at": "2012-01-01T12:00:00Z", 306 | "updated_at": "2012-01-01T13:00:00Z", 307 | // ... 308 | } 309 | ``` 310 | 311 | Bu zaman damgaları bazı kaynaklar için mantıklı olmayabilir, bu durumlarda 312 | kullanmayabilirsiniz. 313 | 314 | #### ISO8601'deki UTC Zaman Formatını Kullanın 315 | 316 | ISO8601 formatında, UTC zamanını kullanın. Örneğin: 317 | 318 | ``` 319 | "finished_at": "2012-01-01T12:00:00Z" 320 | ``` 321 | 322 | #### Dallanan Nesnelerin (Nested Object) İlişkilendirimesi 323 | 324 | `Foreign Key` referanslarını dallanan nesneler(nested object) ile gösterin, 325 | Örneğin: 326 | 327 | ```javascript 328 | { 329 | "name": "service-production", 330 | "owner": { 331 | "id": "5d8201b0..." 332 | }, 333 | // ... 334 | } 335 | ``` 336 | 337 | Aşağıdaki gibi yapmamaya çalışın: 338 | 339 | ```javascript 340 | { 341 | "name": "service-production", 342 | "owner_id": "5d8201b0...", 343 | // ... 344 | } 345 | ``` 346 | 347 | Bu yaklaşım gerektiğinde size bu dallanan nesneler hakında, cevabınızın yapısını 348 | değiştirmeden ya da bozmadan daha fazla bilgi verebilme imkanı sağlar. Örneğin: 349 | 350 | ```javascript 351 | { 352 | "name": "service-production", 353 | "owner": { 354 | "id": "5d8201b0...", 355 | "name": "Alice", 356 | "email": "alice@heroku.com" 357 | }, 358 | // ... 359 | } 360 | ``` 361 | 362 | #### Belirli Yapıda Hatalar Oluşturun 363 | 364 | Tutarlı, belirli yapıda hatalar oluşturun. Bir programın okuyabileceği hata 365 | `id`'leri ve insanların anlayabileceği hata `message`'ları, daha fazla bilgi 366 | alabilecekleri ve çözüm bulabilecekleri hata `url`'leri belirleyin. Örneğin: 367 | 368 | ``` 369 | HTTP/1.1 429 Too Many Requests 370 | ``` 371 | 372 | ```json 373 | { 374 | "id": "rate_limit", 375 | "message": "Account reached its API rate limit.", 376 | "url": "https://docs.service.com/rate-limits" 377 | } 378 | ``` 379 | 380 | Kullanıcılarınız karşılaşabileceği hata formatlarınızı dokümante edin. 381 | 382 | #### `Rate Limit` Durumunu Gösterin 383 | 384 | `Rate Limit` diğer kullanıcıların servisi sağlıklı kullanabilmeleri için 385 | istemcinin isteklerinini sınırlandırılmasıdır. Bunun için 386 | [token bucket algorithm](http://en.wikipedia.org/wiki/Token_bucket) 387 | algoritmasını kullanabilirsiniz. 388 | 389 | Kalan istek sayılarını `RateLimit-Remaining` başlığı içerisinde sunun. 390 | 391 | #### Bütün Cevaplarda JSON Veriniz Sıkıştırılmış(minified) Olsun 392 | 393 | Ekstra boşluklar isteklerin cevaplarını gereksiz yere büyütür, ve bir çok 394 | istemci zaten otomatik olarak bu verileri güzel görünür hale getirmektedir. 395 | En iyisi JSON verinizi sıkıştırılmış halde tutmaktır. Örneğin: 396 | 397 | ```json 398 | {"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"} 399 | ``` 400 | 401 | Aşağıdakinin yerine: 402 | 403 | ```json 404 | { 405 | "beta": false, 406 | "email": "alice@heroku.com", 407 | "id": "01234567-89ab-cdef-0123-456789abcdef", 408 | "last_login": "2012-01-01T12:00:00Z", 409 | "created_at": "2012-01-01T12:00:00Z", 410 | "updated_at": "2012-01-01T12:00:00Z" 411 | } 412 | ``` 413 | 414 | Sorgu paramatreleri ile (Örneğin: `?pretty=true`) veya başlık parametresi 415 | (Örneğin: `Accept: application/vnd.heroku+json; version=3; indent=4;`) olarak 416 | kullanıcılarınıza güzel görünümlü hali için bir seçenek sunabilirsiniz. 417 | 418 | ### Artifacts 419 | 420 | #### Programların Okuyabileceği(Machine-readable) JSON Şeması Oluşturun 421 | 422 | API arayüzünüzü ayrıntılarıyla belirtmek için programların anlayabileceği 423 | şemalar oluşturun. Şemanızı yönetmek için [prmd](https://github.com/interagent/prmd) 424 | kullanabilirsiniz, ve `prmd verify` ile geçerliliğini doğrulayın. 425 | 426 | #### İnsanların Okuyabileceği Dokümanlar Oluşturun 427 | 428 | API'nizi kullanmak isteyecek istemci developerların anlayabileceği dokümanlar 429 | oluşturun. 430 | 431 | Eğer daha önce bahsedildiği gibi prmd ile bir şema oluşturursanız, `prmd doc` 432 | komutu ile son kullanıcılarınıza kolayca Markdown dokümanı oluşturabilirsiniz 433 | 434 | Son kullanıcılara ek olarak, aşağıdaki konuları içeren bir API'ye genel bakış 435 | bölümün oluşturun: 436 | 437 | * Authentication(Kimlik DOğrulama), bilgilerini edinme ve kullanımı. 438 | * API kararlılığı ve versiyonlama, API versiyonlarını seçimi 439 | * Genel istek ve cevap başlıkları 440 | * Hata formatları 441 | * API arayüzünü farklı dillerdeki kullanıcılar ile kullanım örnekleri 442 | 443 | #### Çalıştırılabilir Örnekler Oluşturun 444 | 445 | Kullanıcılarınızın terminal arayüzünden direk çağırabileceği çalıştırılabilir 446 | örnekler hazırlayın. Bu örneklerin, kullanıcının API arayüzü ile çalışırken 447 | minimum enerjiyi harcaması için, mümkün olduğunca kelimesi kelimesine 448 | kullanılabilir olmasını sağlayın. Örneğin: 449 | 450 | ```bash 451 | $ export TOKEN=... # acquire from dashboard 452 | $ curl -is https://$TOKEN@service.com/users 453 | ``` 454 | 455 | Eğer siz Markdown dokümanı oluştururken [prmd](https://github.com/interagent/prmd) 456 | kullanırsanız, ücretsiz, her son kullanıcı örnekleriniz olur. 457 | 458 | #### İstikrarı Açıklayın 459 | 460 | API'nizin istikrarlılığını açıklayın veya kararlılığına ve olgunluğuna göre 461 | birden fazla bağlantı seçeneği sunun, örneğin: prototype/development/production 462 | seçenekleri ile. 463 | 464 | [Heroku API compatibility policy](https://devcenter.heroku.com/articles/api-compatibility-policy) 465 | dokümanını, yönetim yaklaşımlarınının değişikliği ve olası kararlılıkları için, 466 | örnek alabilirsiniz. 467 | 468 | API arayüzünüz kararlı ve production'a bir kez çıktıktan sonra geriye dönük 469 | versiyon uyumsuzlukları çıkarmamaya çalışın. Eğer böyle bir uyumsuzluk olması 470 | gerekiyor ise yeni bir version numarası ile API çıkarın. 471 | 472 | 473 | ### Çeviriler 474 | * [Korean version](https://github.com/yoondo/http-api-design) (based on [f38dba6](https://github.com/interagent/http-api-design/commit/f38dba6fd8e2b229ab3f09cd84a8828987188863)), by [@yoondo](https://github.com/yoondo/) 475 | * [Simplified Chinese version](https://github.com/ZhangBohan/http-api-design-ZH_CN) (based on [337c4a0](https://github.com/interagent/http-api-design/commit/337c4a05ad08f25c5e232a72638f063925f3228a)), by [@ZhangBohan](https://github.com/ZhangBohan/) 476 | * [Traditional Chinese version](https://github.com/kcyeu/http-api-design) (based on [232f8dc](https://github.com/interagent/http-api-design/commit/232f8dc6a941d0b25136bf64998242dae5575f66)), by [@kcyeu](https://github.com/kcyeu/) 477 | 478 | --------------------------------------------------------------------------------