Name: cc-api-v3-style-guide
Owner: Cloud Foundry
Description: Style Guide for Cloud Controller v3 API
Created: 2015-08-03 18:14:11.0
Updated: 2017-03-27 03:12:57.0
Pushed: 2017-10-05 22:23:30.0
Homepage: null
Size: 90
Language: null
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
This document serves as a style guide for the Cloud Controller API. It is intended to act as a repository for patterns and best practices when designing and developing new API endpoints.
This is a living document; It will change over time as we learn more about our users and develop features.
Here is an example request to get apps filtered by query parameters:
/v3/apps?names=dora,kailan&order_by=created_at&page=1&per_page=2
Note that the examples in the style guide to not encode query strings. This is to make the examples more human-readable. In actuality, all requests and responses must contain correctly encoded characters. For more information see Query Parameters.
Here is the respective response body:
agination": {
"total_results": 3,
"total_pages": 2,
"first": {
"href": "/v3/apps?names=dora,kailan&order_by=created_at&page=1&per_page=2"
},
"last": {
"href": "/v3/apps?names=dora,kailan&order_by=created_at&page=2&per_page=2"
},
"next": {
"href": "/v3/apps?names=dora,kailan&order_by=created_at&page=2&per_page=2"
},
"previous": null
esources": [
{
"guid": "guid-00133700-abcd-1234-9000-3f70a011bc28",
"name": "dora",
"desired_state": "STOPPED",
"total_desired_instances": 0,
"buildpack": null,
"created_at": "2015-08-06T00:36:20Z",
"updated_at": null,
"environment_variables": {
},
"links": {
"self": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28"
},
"space": {
"href": "/v2/spaces/ab09cd29-9420-f021-g20d-123431420768"
},
"processes": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/processes"
},
"routes": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/routes"
},
"packages": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/packages"
},
"droplets": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/droplets"
},
"start": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/start",
"method": "PUT"
},
"stop": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/stop",
"method": "PUT"
},
"assign_current_droplet": {
"href": "/v3/apps/guid-00133700-abcd-1234-9000-3f70a011bc28/current_droplet",
"method": "PUT"
}
}
},
{
"guid": "guid-bd7369a8-deed-ff1a-2315-77410293a922",
"name": "kailan",
"desired_state": "STOPPED",
"total_desired_instances": 0,
"buildpack": null,
"created_at": "2015-08-07T00:40:52Z",
"updated_at": null,
"environment_variables": {
},
"links": {
"self": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922"
},
"space": {
"href": "/v2/spaces/881029ab-4edd-4920-af10-6386967209d1"
},
"processes": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/processes"
},
"routes": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/routes"
},
"packages": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/packages"
},
"droplets": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/droplets"
},
"start": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/start",
"method": "PUT"
},
"stop": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/stop",
"method": "PUT"
},
"assign_current_droplet": {
"href": "/v3/apps/guid-bd7369a8-deed-ff1a-2315-77410293a922/current_droplet",
"method": "PUT"
}
}
}
All endpoints must be prefixed with /v3/.
Pattern: /v3/...
Collections of resources are referenced by their resource name (plural)
Pattern: /v3/:resource name
Example: /v3/apps
Individual resources are referenced their resource name (plural) followed by the guid
Pattern: /v3/:resource name/:guid
Example: /v3/apps/25fe21b8-8de2-40d0-93b0-c819101d1a11
Used to retrieve a single resource or a list of resources.
Show individual resource:
/v3/apps/:guid
|Scenario|Code|Body| |—|—|—| | Authorized User | 200 | Resource | | Unauthorized User | 404 | Error |
List collection of resources:
/v3/apps/
|Scenario|Code|Body| |—|—|—| | User With Complete Visibility | 200 | List of All Resources | | User With Partial Visibility | 200 | List of Visible Resources | | User With No Visibility | 200 | Empty List |
Used to create a resource.
Create a resource:
/v3/apps/
me: "cool_app",
ace_guid: "123guid"
|Scenario|Code(s)|Body| |—|—|—| | Authorized User (sync) | 201 | Created Resource | | Authorized User (async) | 202 | Empty w/ Location Header -> Job | | Read-only User | 403 | Error | | Unauthorized User | 403 | Error |
Used to trigger an action. To update a resource, use PATCH
Trigger an action:
/v3/apps/:guid/processes/web/scale
nstances": 100,
emory_in_mb": 2048
|Scenario|Code(s)|Body| |—|—|—| | Authorized User (sync) | 200 | Empty | | Authorized User (async) | 202 | Empty w/ Location Header -> Job | | Read-only User | 403 | Error | | Unauthorized User | 404 | Error |
Used to update a portion of a resource.
Partially update a resource:
H /v3/apps/:guid
ame": "new_app_name"
|Scenario|Code(s)|Body| |—|—|—| | Authorized User (sync) | 200 | Updated Resource | | Authorized User (async) | 202 | Empty w/ Location Header -> Job | | Read-only User | 403 | Error | | Unauthorized User | 404 | Error |
Used to delete a resource.
Delete a resource:
TE /v3/apps/:guid
|Scenario|Code(s)|Body| |—|—|—| | Authorized User (sync) | 204 | N/A | | Authorized User (async) | 202 | Empty w/ Location Header -> Job | | Read-only User | 403 | Error | | Unauthorized User | 404 | Error | | Missing Resource | 404 | Error |
A resource represents an individual object within the system, such as an app or a service. It is represented as a JSON object.
A resource MUST contain the following fields:
guid
: a unique identifier for the resourcecreated_at
: an ISO8601 compatible date and time that the resource was createdupdated_at
: an ISO8601 compatible date and time that the resource was last updatedA resource may contain additional fields which are the attributes describing the resource.
A resource MUST contain a links
field containing a links object, which is used to provide URLs to relationships and actions for the resource.
A resource MUST include a self
link object in the links
field.
uid": "a-b-c",
reated_at": "2015-07-06T23:22:56Z",
pdated_at": "2015-07-08T23:22:56Z",
ame": "dora",
escription": "an example app",
inks": {
"self": {
"href": "/v3/apps/a-b-c"
}
Links provide URLs to relationships and actions for a resource. Links are represented as a JSON object.
Each member of a links object is a “link”.
A link MUST be a JSON object.
A link MUST contain a href
field, which is a string containing the link's relative URL.
A link may contain a method
field, which is a string containing the HTTP verb that must be used to follow the URL. If the method
field is not included then the link MUST be available using GET.
ks": {
elf": {
"href": "/v3/apps/a-b-c"
pace": {
"href": "/v3/apps/a-b-c/relationships/space"
rocesses": {
"href": "/v3/apps/a-b-c/relationships/processes"
tart": {
"href": "/v3/apps/a-b-c/start",
"method": "PUT"
Note that the key is links
to reduce the likelihood of collisions with a hypothetical resource field named links
.
A collection is a list of multiple Resources. A collection is represented as a JSON object.
A collection MUST contain a resources
field. The resources field is an array containing multiple Resources.
A collection MUST contain a pagination
field containing a pagination object.
esources": [
{
"guid": "a-b-c",
"created_at": "2015-07-06T23:22:56Z",
"updated_at": "2015-07-08T23:22:56Z",
"links": {
"self": {
"href": "/v3/apps/a-b-c"
}
}
},
{
"guid": "d-e-f",
"created_at": "2015-07-06T23:22:56Z",
"updated_at": "2015-07-08T23:22:56Z",
"links": {
"self": {
"href": "/v3/apps/d-e-f"
}
}
}
agination": {
"total_results": 2,
"total_pages": 1,
"first": {
"href": "/v3/apps?page=1&per_page=10"
},
"last": {
"href": "/v3/apps?page=1&per_page=10"
},
"next": null,
"previous": null
Pagination may be used by Collections to limit the number of resources returned at a time. Pagination is requested by a client through the use of query parameters. Pagination is represented as a JSON object.
Pagination MUST include a total_results
field with an integer value of the total number of records in the collection.
Pagination MUST include a total_pages
field with an integer value of the total number of pages in the collection.
Pagination MUST include the following fields for pagination links:
first
: the first page of resourceslast
: the last page of resourcesprevious
: the previous page of resourcesnext
: the next page of resourcesPagination links may be null
. For example, if the page currently being displayed is the first page, then previous
link will be null.
When pagination links contain a URL, they MUST be a JSON object with a field named href
containing a string with the URL for the next page.
The URL MUST include all query parameters required to maintain consistency with the original pagination request. For example, if the client requested for the collection to be returned in a specific order direction via a query parameter, then the pagination links must include the proper query parameter to maintain the requested direction.
The following query parameters MUST be used for pagination:
page
: the page number of resources to return (default: 1)per_page
: the number of resources to return in a paginated collection request (default: 50)order_by
: a field on the resource to order the collection by; each collection may choose a subset of fields that it can be sorted byWhen collections are ordered by a subset of fields, each field MAY be prepended “-” to indicate descending order direction. If the field is not prepended, the ordering will default to ascending.
If there are additional pagination query parameters, the parameters MUST have names that conform to the acceptable query parameter names.
ination:" {
otal_results": 20,
otal_pages": 2,
irst": {
"href": "/v3/apps?order_by=-created_at&page=1&per_page=10"
ast": {
"href": "/v3/apps?order_by=-created_at&page=2&per_page=10"
ext": {
"href": "/v3/apps?order_by=-created_at&page=2&per_page=10"
revious": null
Actions are API requests that are expected to initiate change within the Cloud Foundry runtime. This is differentiated from requests which update a record, but require additional updates ? such as restarting an app ? to cause changes to a resource to take affect.
Actions MUST use use PUT as their HTTP verb.
Actions may accept a request body.
Actions MUST be listed in the links
for the related resource.
PUT /v3/apps/:guid/start
Query Parameters MUST include ONLY the following characters:
Query parameters that accept multiple values MUST be pluralized.
If any request receives a query parameter it does not understand, the response MUST be a 400 Bad Request
.
All query parameters MUST be properly url-encoded. If a query parameter value includes the comma (,
) character, the comma MUST be double encoded. Note that for readability purposes, the examples throughout this document do not show encoded query strings.
Single value:
GET /v3/apps?names=firstname
Multiple values:
GET /v3/apps?names=firstname,secondname
Single value with comma:
GET /v3/apps?names=comma%2Cname
Resource Fields MUST include ONLY the following characters:
Resource fields that accept multiple values MUST be pluralized.
esources": [
{
"guid": "guid-1",
"environment_variables": {
"animal": "fish",
"color": "teal"
}
}
Filtering is the use of query parameters to return a subset of resources within a Collection.
Filter query parameters MUST have names that conform to the acceptable query parameter names.
Filters MUST allow a client to request resources matching multiple values of by accepting the filter as an array.
Filter parameters MUST be able to be combined with other filters on the same collection.
http://api.server.com/v3/apps?names=first_name,second_name
http://api.server.com/v3/apps?names=the_name
http://api.server.com/v3/apps?names=the_name&space_guids=d-e-f
The HTTP status code returned for errors MUST be included in the documented status codes.
Currently looks like v2.
code": 100001,
description": "The app is invalid: Invalid app state provided",
error_code": "CF-AppInvalid"
error_code
is often ambiguouscode
does not have a clear mapping to what it means or how to resolve itThis proposal includes code
which would be an internal unique identifier of a class of error. This could be used for support scripts for CF operators. The method for maintaining a list of these codes and their meanings would need to be determined
tatus": 400,
ode": 123455,
ype": "Invalid Request",
escription": "The request body is not valid.",
rrors": [
{
"resource": "app",
"messages": [
"Names must be unique",
"Names may not contain numbers"
]
},
{
"resource": "lunch",
"messages": [
"Potatoes cannot be perfectly round"
]
}
|Status Code|Description|Verbs| |—|—|—| |200 OK|This status MUST be returned for synchronous requests that complete successfully and have a response body. This must only be used if there is not a more appropriate 2XX response code. |GET, PATCH, PUT| |201 Created|This status MUST be returned for synchronous requests that result in the creation of a new resource.|POST| |202 Accepted|This status MUST be returned for requests that have been successfully accepted and will be asynchronously completed at a later time. See more in the async section. |POST,PATCH,PUT,DELETE| |204 No Content|This status MUST be returned for synchronous requests that complete successfully and have no response body.|DELETE
|Status Code|Description|Verbs| |—|—|—| |302 Found| This status MUST be returned when the cloud controller redirects to another location. Example: Downloading a package from an external blob store. |GET| |303 See Other| This status MUST be returned when an async job finishes. It must include a location header containing the resource link. See more in the async section. |GET|
|Status Code|Description|Verbs| |—|—|—| |400 Bad Request|This status MUST be returned for requests that provide malformed or invalid data. Examples: invalid JSON, unexpected query parameters or request fields.|GET, PATCH, POST, PUT, DELETE| |401 Unauthenticated|This status MUST be returned if the requested resource requires an authenticated user but there is no OAuth token provided, or the OAuth token provided is invalid.|GET, POST, PATCH, DELETE, PUT| |403 Forbidden|This status MUST be returned if the request cannot be performed by the user due to lack of permissions. Example: User with read-only permissions to a resource tries to update it. |POST, PATCH, DELETE, PUT| |404 Not Found|This status MUST be returned if the requested resource does not exist or if the user requesting the resource has insufficient permissions to view the resource.|GET, POST, PATCH, PUT, DELETE| |422 Unprocessable Entity|This status MUST be returned if the request is semantically valid, but performing the requested operation would result in a invalid state. Example: Attempting to start an app without assigning a droplet.|POST, PATCH, PUT|
|Status Code|Description |—|—|—| |500 Internal Server Error|This status MUST be returned when an unexpected error occurs. |502 Bad Gateway|This status MUST be returned when an upstream service failure causes a request to fail. Example: Being unable to reach requested service broker.
Associations are sometimes created by setting a relationship_guid
field on one of the resources.
POST /v3/apps { "space_guid": "abc" }
creates an app associated to a space.Other times associations are added via PUT requests to a nested resource.
PUT /v3/apps/guid/routes { route_guid: the guid }
will add a route association to an app.An association can then be deleted via DELETE /v3/apps/guid/routes { route_guid: the guid }
.
This currently feels a little clunky for several reasons:
Add a relationship object to resources similar to the jsonapi spec.
Creating an app could change to allow creating relationships at create time by including the relationships object. Some relationships could be required at creation such as space in the app case.
/v3/apps
ame": "blah",
elationships": {
space": {"guid": "1234"},
routes": [
{"guid": "2345"},
{"guid": "3456"}
,
Modifying relationships later could be done through a nested relationship resource
Setting a *-to-one relationship:
H /v3/apps/guid/relationships/space
ata": {"guid": "some-guid"}
Clearing a *-to-one relationship:
H /v3/apps/guid/relationships/space
ata": null
Adding to a *-to-many relationship (not an overwrite/replace):
/v3/apps/guid/relationships/routes
ata": [{"guid": "asdf" }, {"guid": "gfds" }]
Replacing all items in a *-to-many relationship:
H /v3/apps/guid/relationships/routes
ata": [{"guid": "some-guid" }, {"guid": "whatever" }]
Clearing all items in a *-to-many relationship:
H /v3/apps/guid/relationships/routes
ata": []
Removing some items from a *-to-many relationship:
TE /v3/apps/guid/relationships/routes
ata": [{"guid": "asdf" }, {"guid": "hgfg" }]
Nested resources can optionally be accessed through their parent resource.
/v3/apps/:guid/droplets
This will be equivalent to
/v3/droplets?app_guids=:app_guid
These end points are optional and may not exist for all resources. Good opportunities for creating them:
This is a mechanism for including multiple related resources in a single response.
A use case for this would be to display an HTML page that includes information about both an app and its space and would like to gather this information in one HTTP request.
Included resources are in-lined under their pluralized resource name in an included
object on the primary resource. If a resource within a resource ? resource.otherresource
? is requested, it is added in the top level included
object and not repeated. Associations between included resources and requested resources must be shown in the 'relationships' section for the requested resource. Duplicate included resources are not repeated
/v3/apps?include=space,space.organization,space.space_quota_definition,space.organization.quota_definition
agination": {
"total_results": 3,
"total_pages": 1,
"first": {
"href": "/v3/apps?order_by=-created_at&page=1&per_page=10"
},
"last": {
"href": "/v3/apps?order_by=-created_at&page=1&per_page=10"
},
"next": {
"href": "/v3/apps?order_by=-created_at&page=1&per_page=10"
},
"previous": null
esources": [
{
"guid": "643e170c-42cf-4704-840f-4fc22e95f3c5",
"name": "my_app3",
"desired_state": "STOPPED",
"total_desired_instances": 0,
"buildpack": "name-2009",
"created_at": "1970-01-01T00:00:03Z",
"updated_at": null,
"environment_variables": {
"magic": "beautiful"
},
"relationships": {
"space": {
"guid": "space2-guid"
}
},
"links": {
"self": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5"
},
"space": {
"href": "/v2/spaces/space2-guid"
},
"processes": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/processes"
},
"routes": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/routes"
},
"packages": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/packages"
},
"droplets": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/droplets"
},
"start": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/start",
"method": "PUT"
},
"stop": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/stop",
"method": "PUT"
},
"assign_current_droplet": {
"href": "/v3/apps/643e170c-42cf-4704-840f-4fc22e95f3c5/current_droplet",
"method": "PUT"
}
}
},
{
"guid": "3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef",
"name": "my_app2",
"desired_state": "STOPPED",
"total_desired_instances": 0,
"buildpack": null,
"created_at": "1970-01-01T00:00:02Z",
"updated_at": null,
"environment_variables": {
},
"relationships": {
"space": {
"guid": "space1-guid"
}
},
"links": {
"self": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef"
},
"space": {
"href": "/v2/spaces/space1-guid"
},
"processes": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/processes"
},
"routes": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/routes"
},
"packages": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/packages"
},
"droplets": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/droplets"
},
"start": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/start",
"method": "PUT"
},
"stop": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/stop",
"method": "PUT"
},
"assign_current_droplet": {
"href": "/v3/apps/3b310427-c9f0-4e7c-ab66-5f5d9a86a4ef/current_droplet",
"method": "PUT"
}
}
},
{
"guid": "8c943e87-c00c-4d0b-8583-d5c49111a5ec",
"name": "my_app2",
"desired_state": "STOPPED",
"total_desired_instances": 0,
"buildpack": null,
"created_at": "1970-01-01T00:00:02Z",
"updated_at": null,
"environment_variables": {
},
"relationships": {
"space": {
"guid": "space1-guid"
}
},
"links": {
"self": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec"
},
"space": {
"href": "/v2/spaces/space1-guid"
},
"processes": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/processes"
},
"routes": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/routes"
},
"packages": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/packages"
},
"droplets": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/droplets"
},
"start": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/start",
"method": "PUT"
},
"stop": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/stop",
"method": "PUT"
},
"assign_current_droplet": {
"href": "/v3/apps/8c943e87-c00c-4d0b-8583-d5c49111a5ec/current_droplet",
"method": "PUT"
}
}
}
ncluded": {
"spaces": [
{
"metadata": {
"guid": "space1-guid",
"url": "/v2/spaces/space1-guid",
"created_at": "2015-10-07T00:35:20Z",
"updated_at": null
},
"relationships": {
"organization": {"guid": "org1-guid"},
"space_quota_definition": {"guid": "spacequota1-guid}
},
"entity": {
"name": "name-76",
"organization_guid": "org1-guid",
"space_quota_definition_guid": "spacequota1-guid",
"allow_ssh": true,
"organization_url": "/v2/organizations/org1-guid",
"developers_url": "/v2/spaces/space1-guid/developers",
"managers_url": "/v2/spaces/space1-guid/managers",
"auditors_url": "/v2/spaces/space1-guid/auditors",
"apps_url": "/v2/spaces/space1-guid/apps",
"routes_url": "/v2/spaces/space1-guid/routes",
"domains_url": "/v2/spaces/space1-guid/domains",
"service_instances_url": "/v2/spaces/space1-guid/service_instances",
"app_events_url": "/v2/spaces/space1-guid/app_events",
"events_url": "/v2/spaces/space1-guid/events",
"security_groups_url": "/v2/spaces/space1-guid/security_groups"
}
},
{
"metadata": {
"guid": "space2-guid",
"url": "/v2/spaces/space2-guid",
"created_at": "2015-10-07T00:35:20Z",
"updated_at": null
},
"relationships": {
"organization": {"guid": "org2-guid"},
"space_quota_definition": {"guid": "spacequota1-guid}
},
"entity": {
"name": "name-77",
"organization_guid": "org2-guid",
"space_quota_definition_guid": "spacequota1-guid",
"allow_ssh": true,
"organization_url": "/v2/organizations/org2-guid",
"developers_url": "/v2/spaces/space2-guid/developers",
"managers_url": "/v2/spaces/space2-guid/managers",
"auditors_url": "/v2/spaces/space2-guid/auditors",
"apps_url": "/v2/spaces/space2-guid/apps",
"routes_url": "/v2/spaces/space2-guid/routes",
"domains_url": "/v2/spaces/space2-guid/domains",
"service_instances_url": "/v2/spaces/space2-guid/service_instances",
"app_events_url": "/v2/spaces/space2-guid/app_events",
"events_url": "/v2/spaces/space2-guid/events",
"security_groups_url": "/v2/spaces/space2-guid/security_groups"
}
}
],
"organizations": [
{
"metadata": {
"guid": "org1-guid",
"url": "/v2/organizations/org1-guid",
"created_at": "2015-10-13T17:31:34Z",
"updated_at": null
},
"relationships": {
"quota_definition": {"guid": "quota1-guid"}
},
"entity": {
"name": "org1",
"billing_enabled": false,
"quota_definition_guid": "dad3cc94-2ec9-4178-b6af-0c7819812e1c",
"status": "active",
"quota_definition_url": "/v2/quota_definitions/dad3cc94-2ec9-4178-b6af-0c7819812e1c",
"spaces_url": "/v2/organizations/org1-guid/spaces",
"domains_url": "/v2/organizations/org1-guid/domains",
"private_domains_url": "/v2/organizations/org1-guid/private_domains",
"users_url": "/v2/organizations/org1-guid/users",
"managers_url": "/v2/organizations/org1-guid/managers",
"billing_managers_url": "/v2/organizations/org1-guid/billing_managers",
"auditors_url": "/v2/organizations/org1-guid/auditors",
"app_events_url": "/v2/organizations/org1-guid/app_events",
"space_quota_definitions_url": "/v2/organizations/org1-guid/space_quota_definitions"
}
} ,
{
"metadata": {
"guid": "org2-guid",
"url": "/v2/organizations/org2-guid",
"created_at": "2015-10-13T17:38:34Z",
"updated_at": null
},
"relationships": {
"quota_definition": {"guid": "quota2-guid"}
},
"entity": {
"name": "org2",
"billing_enabled": false,
"quota_definition_guid": "dad3cc94-2ec9-4178-b6af-0c7819812e1c",
"status": "active",
"quota_definition_url": "/v2/quota_definitions/dad3cc94-2ec9-4178-b6af-0c7819812e1c",
"spaces_url": "/v2/organizations/org2-guid/spaces",
"domains_url": "/v2/organizations/org2-guid/domains",
"private_domains_url": "/v2/organizations/org2-guid/private_domains",
"users_url": "/v2/organizations/org2-guid/users",
"managers_url": "/v2/organizations/org2-guid/managers",
"billing_managers_url": "/v2/organizations/org2-guid/billing_managers",
"auditors_url": "/v2/organizations/org2-guid/auditors",
"app_events_url": "/v2/organizations/org2-guid/app_events",
"space_quota_definitions_url": "/v2/organizations/org2-guid/space_quota_definitions"
}
}
],
"quota_definitions": [
{
"metadata": {
"guid": "quota1-guid",
"url": "/v2/quota_definitions/quota1-guid",
"created_at": "2015-10-13T17:31:34Z",
"updated_at": null
},
"entity": {
"name": "default",
"non_basic_services_allowed": true,
"total_services": 100,
"total_routes": 1000,
"total_private_domains": -1,
"memory_limit": 10240,
"trial_db_allowed": false,
"instance_memory_limit": -1,
"app_instance_limit": -1
}
},
{
"metadata": {
"guid": "quota2-guid",
"url": "/v2/quota_definitions/quota2-guid",
"created_at": "2015-10-13T17:31:34Z",
"updated_at": null
},
"entity": {
"name": "basic",
"non_basic_services_allowed": false,
"total_services": 100,
"total_routes": 1000,
"total_private_domains": 10,
"memory_limit": 10240,
"trial_db_allowed": false,
"instance_memory_limit": 2048,
"app_instance_limit": 50
}
}
],
"space_quota_definitions": [
{
"metadata": {
"guid": "spacequota1-guid",
"url": "/v2/space_quota_definitions/spacequota1_guid",
"created_at": "2015-10-13T17:31:39Z",
"updated_at": null
},
"entity": {
"name": "spacequota1",
"organization_guid": "org1-guid",
"non_basic_services_allowed": true,
"total_services": 60,
"total_routes": 1000,
"memory_limit": 20480,
"instance_memory_limit": -1,
"app_instance_limit": -1,
"organization_url": "/v2/organizations/org1-guid",
"spaces_url": "/v2/space_quota_definitions/spacequota1-guid/spaces"
}
},
{
"metadata": {
"guid": "spacequota2-guid",
"url": "/v2/space_quota_definitions/spacequota2_guid",
"created_at": "2015-10-13T17:31:39Z",
"updated_at": null
},
"entity": {
"name": "spacequota2",
"organization_guid": "org2-guid",
"non_basic_services_allowed": true,
"total_services": 60,
"total_routes": 1000,
"memory_limit": 20480,
"instance_memory_limit": -1,
"app_instance_limit": -1,
"organization_url": "/v2/organizations/org2-guid",
"spaces_url": "/v2/space_quota_definitions/spacequota2-guid/spaces"
}
},
]
Related resources are paginated in a similar style to how normal responses are paginated.
The pagination data may be excluded if all results are included in the response.
GET /v3/apps/:guid?include=routes
uid": "guid",
ncluded": {
"routes": {
"resources": [
{"guid": "1"},
{"guid": "2"}
],
"pagination": {
"total_results": 20,
"total_pages": 2,
"first": {
"href": "/v3/apps/:guid/routes?order_by=-created_at&page=1&per_page=2"
},
"last": {
"href": "/v3/apps/:guid/routes?order_by=-created_at&page=10&per_page=2"
},
"next": {
"href": "/v3/apps/:guid/routes?order_by=-created_at&page=2&per_page=2"
},
"previous": null
}
}
/apps?fields=guid,name
uid": "some-guid",
ame": "Zach"
If we want to be able to filter the fields of subresources, we could do something like:
/apps?fields[apps]=guid,name&fields[droplets]=buildpack
uid": "some-guid",
ame": "Zach",
ncluded": {
"droplet": {
"buildpack": "ruby"
}
Via Mark: The original impetus for the async
flag was:
The team later learned that not all endpoints need to be async (/v2/info for example). The overhead of background workers/ jobs is not worth it.
async=true
causes the CLI to block and poll indefinitely waiting for job to complete (CC has to enforce a timeout)accepts_incomplete=true
causes the CLI to exit once a poll-able resource is returned, and CC will poll for up to a week. CC ignores async=true
Requests including the async=true
query parameter will resolve asynchronously. Instead of returning whatever resource is requested, the CC will return a job.
async=true
. There doesn't seem to be any indication of what supports it.accepts_incomplete=true
(service-specific). The CC will currently ignore async=true
if accepts_incomplete
is included, even if the broker does not support async operations. This renders async=true
useless for most broker operations.async=true
in many cases will slow down the request, since there is the worker/polling overhead. A 1 second synchronous operation doesn't need to happen out of band with a 5 second polling interval.Remove both flags. Instead, endpoints are responsible for behaving either asynchronously (return 202) or synchronously (don't return 202).
For async endpoints:
POST /v3/resource
The CC will return a 202 with a location header pointing to the job. Depending on the resource, it may also return a skeletal body containing the partial resource.
Accepted
tion: /v3/jobs/123
keletor": "YOU! You will no longer stand between me and my destiny!"
Before the job has completed, GET requests made to the job endpoint will return 200 with information about the status of the job.
/v3/jobs/123
OK
tatus": "in progress"
When the job has completed, GET request made to the job endpoint will return 303 and a location header to the resource (assuming it still exists).
/v3/jobs/123
See Other
tion: /v3/resource/:guid
Note that for asynchronous deletes, the redirect location will be to a no-longer-existent resource.