Apcera REST API

The Apcera API is a collection of HTTP endpoints that accept and return Apcera resources. To call the API your application makes an HTTP request and parses the response. The request and response bodies are JSON objects that are represented by API model objects. This guide describes the operations available with the Apcera API and provides example requests and responses. For steps to perform common tasks with the API, see Apcera REST API Recipes.

API Versioning

Apcera Platform 3.0.0 introduces an API versioning scheme that uses content negotiation. In this approach, rather than have different URL endpoints for different API versions (GET /v1/jobs or GET /v2/jobs, for example) a single endpoint is provided (GET /jobs) and clients specify the desired API version using Accept and Content-Type HTTP request headers. These header values have the form application/vnd.apcera.RESOURCE_TYPE;version=VERSION_NUM.

For example, the following requests version 1 of the GET /services endpoint, indicating version 1 of the application/vnd.apcera.service resource type:

GET /services HTTP/1.1
Accept: application/vnd.apcera.service;version=1

The platform's response to this request includes a Content-Type header that specifies the MIME type and version of the returned resource:

HTTP/1.1 200 OK
Content-Type: application/vnd.apcera.service;version=1

The following request to POST /packages/docker indicates its request body contains version 2 of a CreateDockerPackageRequest object, and expects the same version of a CreateDockerPackageResponse object in the response:

POST /packages/docker HTTP/1.1
Accept: application/vnd.apcera.createdockerpackageresponse;version=2
Content-Type: application/vnd.apcera.createdockerpackagerequest;version=2

{
    "package_fqn":"package::/sandbox/admin::mysql",
    "image_url":"https://registry-1.docker.io/library/mysql:latest"
}

If a client request doesn't contain Accept or Content-Type headers, or specifies an invalid type or version, the platform makes a reasonable guess as to which resource type and version to return. For example, the following request to the GET /services endpoint includes an invalid resource type (application/vnd.apcera.foobar) and version (version=3):

GET /services HTTP/1.1
Accept: application/vnd.apcera.foobar;version=3

Based on the endpoint and method the platform determines the correct Content-Type header value and version to return:

HTTP/1.1 200 OK
Content-Type: application/vnd.apcera.service;version=1

NOTE: The original /v1 API endpoints are still available in Apcera Platform release 3.0.0, and there are no changes to API behavior (the original and new endpoints are routed to the same back-end code). However, new API client authors are encouraged the use the new endpoints to make adapting future API changes easier.

API Hosts

An Apcera cluster has different API hosts to handle different categories of requests. Most Apcera API endpoints for managing a cluster's resources are invoked on the api host. For example, assuming your cluster is deployed to the example.com domain the following invokes the GET /services endpoint:

GET /services HTTP/1.1
Host: api.example.com

APIs related to policy are invoked on a cluster's auth host, for example:

GET /v1/policy HTTP/1.1
Host: auth.example.com

Note: Policy APIs do not currently use the new API versioning scheme and must be called with /v1/ in the path.

APIs related to authentication are invoked on a host whose name depends on the authentication system your cluster uses (LDAP or Google, for example). For instance, if your cluster uses LDAP for authentication then the API hostname is ldapauth, for example:

POST /v1/oauth2/token HTTP/1.1
Host: ldapauth.example.com

Client Authentication

Each API call must include an authentication bearer token in the header of the HTTP request, for example:

GET /services HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ0eXAiO...

You obtain an API token by using the Apcera authentication APIs. See Authenticating with the API Server for details.

If your API client application is running as a job on the Apcera platform you can use "app tokens" to easily authenticate your application. App tokens are are a way for Apcera to issue authentication tokens to applications without the app having to make authentication API calls. See Using App Tokens for more information.

For testing purposes, a quick way to obtain an API token is to copy it from APC's configuration ($HOME/.apc) file after logging in successfully using APC.

To get the API token from your .apc file:

  1. Target your cluster using the APC command apc target <cluster-domain>.
  2. Run the apc login to begin the authentication process.
  3. Follow the steps in the APC output to authenticate.
  4. Once your client is authenticated, open the .apc file located in your home directory ($HOME/.apc) with a text editor and copy the entire Bearer <token> string value:

     {
       "target": "https://example.com",
       "tokens": {
         "https://example.com": "Bearer eyJ0eXAiOiIiLCJhbGciOiIifQ....",
         "..."
       }
     }
    
  5. Add the bearer token to your API client's Authorization HTTP request header, for example:

     GET /info HTTP/1.1
     Authorization: Bearer eyJ0eXAiOiIiLCJhbGciOiIifQ....
     Accept: application/vnd.apcera.info;version=1
    

Using APC's trace mode

Each APC command you run (apc app create, for example) results in a one or more Apcera API requests. If you include the --trace flag in any APC command, the contents of each API request and response is saved to a log file named apc.log in the local directory from where you invoked APC. Looking at the contents of this file can be instructional to see the sequence of API calls that a given APC command requires.

For example, run the following command against your cluster:

$ apc app list --trace
** Trace mode on. Logs will appear in apc.log **
Working in "/sandbox/admin"
╭──────┬────────────────┬────────┬───────────┬────────────────────────────────────────────────╮
│ Name │ Namespace      │ Status │ Instances │ Routes                                         │
├──────┼────────────────┼────────┼───────────┼────────────────────────────────────────────────┤
│ web1 │ /sandbox/admin │ ready  │           │ http://web1-3ps9to.tutorial.apcera-platform.io │
│ web2 │ /sandbox/admin │ ready  │           │ http://web2-pd03a0.tutorial.apcera-platform.io │
╰──────┴────────────────┴────────┴───────────┴────────────────────────────────────────────────╯

Open apc.log to view its contents. You should see the HTTP request to GET /jobs and JSON response containing the list of jobs.

$ cat apc.log
I0322 16:53:09.494776 90281 request.go:160 ctx="apc" trace="1"] -- Sending HTTP Request:
I0322 16:53:09.494792 90281 client_auth.go:357 ctx="apc" trace="1"] GET /jobs?fqn=job%3A%3A%2Fsandbox%2Fadmin&health=true&matchPartialFQN=true&summary=true&tag=app HTTP/1.1
I0322 16:53:09.494799 90281 client_auth.go:357 ctx="apc" trace="1"] Host: api.tutorial.apcera-platform.io
I0322 16:53:09.494800 90281 client_auth.go:357 ctx="apc" trace="1"] User-Agent: APC/v2.0.0 (Continuum Client)
I0322 16:53:09.494802 90281 client_auth.go:357 ctx="apc" trace="1"] Authorization: Bearer eyJ0eXAiOiIiLCJhbGciOiIifQ.eyJpc3MiOiJhdXRoX3NlcnZlckBhcGNlcmEubWUiLCJhdWQiOiJhcGNlcmEubWUiLCJpYXQiOjE0NTg2NzgzNjcsImV4cCI6MTQ1ODc2NDc3NywicHJuIjoiYWRtaW5AYXBjZXJhLm1lIiwiY2xhaW1zIjpbeyJJc3N1ZXIiOiJhdXRoX3NlcnZlckBhcGNlcmEubWUiLCJUeXBlIjoiYXV0aFR5cGUiLCJWYWx1ZSI6ImJhc2ljQXV0aCJ9XX0.MEUCIELB4uTe6Rdze8st1blxWtVzyVZjUq6-C3NLGf9LlZt0AiEAuMsDr8uKuPDbX-Lh9OS1V2iFGKJNfTjlFy4pizgGBFQ
I0322 16:53:09.494805 90281 client_auth.go:357 ctx="apc" trace="1"] Hostname: Tims-MacBook-Pro.local-Client-Hostname
I0322 16:53:09.494807 90281 client_auth.go:357 ctx="apc" trace="1"] Accept-Encoding: gzip
I0322 16:53:09.494809 90281 client_auth.go:357 ctx="apc" trace="1"]
I0322 16:53:09.494810 90281 client_auth.go:357 ctx="apc" trace="1"]
I0322 16:53:09.889994 90281 request.go:184 ctx="apc" trace="2"] -- Received HTTP Response:
I0322 16:53:09.890006 90281 client_auth.go:357 ctx="apc" trace="2"] HTTP/1.1 200 OK
I0322 16:53:09.890017 90281 client_auth.go:357 ctx="apc" trace="2"] Transfer-Encoding: chunked
I0322 16:53:09.890018 90281 client_auth.go:357 ctx="apc" trace="2"] Connection: keep-alive
I0322 16:53:09.890020 90281 client_auth.go:357 ctx="apc" trace="2"] Content-Type: application/json
I0322 16:53:09.890021 90281 client_auth.go:357 ctx="apc" trace="2"] Date: Tue, 22 Mar 2016 23:53:09 GMT
I0322 16:53:09.890022 90281 client_auth.go:357 ctx="apc" trace="2"] Minimum-Apc-Version: 2.0.0
I0322 16:53:09.890024 90281 client_auth.go:357 ctx="apc" trace="2"] Server: nginx
I0322 16:53:09.890025 90281 client_auth.go:357 ctx="apc" trace="2"] Vary: Accept-Encoding
I0322 16:53:09.890028 90281 client_auth.go:357 ctx="apc" trace="2"]
I0322 16:53:09.890030 90281 client_auth.go:357 ctx="apc" trace="2"]
I0322 16:53:09.892560 90281 client_auth.go:357 ctx="apc" trace="2"] [{"uuid":"40e8dad1-ddd8-4a99-9b76-b64193479b4a","updated_by":"","created_by":"","updated_at":"2016-03-22T23:37:42.29114006Z","created_at":"2016-03-22T23:27:01.999395535Z","ports":[{"number":0,"optional":false,"routes":[{"type":"http","endpoint":"web1-3ps9to.tutorial.apcera-platform.io","weight":0}]}],"logs":[],"name":"web1","fqn":"job::/sandbox/admin::web1","num_instances":2,"packages":[],"processes":{},"resources":{"cpu":0,"memory":268435456,"disk":1073741824,"network":5000000,"netmax":0},"rollout":{"force_stop_old_instances_after":0,"flapping_minimum_restarts":0,"flapping_percent":0,"flapping_window":0,"errored_state_window":0},"restart":{"restart_mode":"always"},"state":"ready","tags":{"app":"web1"},"version_id":2,"network_ref":null,"aggregate_network_routes":null},{"uuid":"fe3b71e0-d8f8-42a1-8ce9-ff261549188b","updated_by":"","created_by":"","updated_at":"2016-03-22T23:27:08.284436233Z","created_at":"2016-03-22T23:27:08.284436233Z","ports":[{"number":0,"optional":false,"routes":[{"type":"http","endpoint":"web2-pd03a0.tutorial.apcera-platform.io","weight":0}]}],"logs":[],"name":"web2","fqn":"job::/sandbox/admin::web2","num_instances":2,"packages":[],"processes":{},"resources":{"cpu":0,"memory":268435456,"disk":1073741824,"network":5000000,"netmax":0},"rollout":{"force_stop_old_instances_after":0,"flapping_minimum_restarts":0,"flapping_percent":0,"flapping_window":0,"errored_state_window":0},"restart":{"restart_mode":"always"},"state":"ready","tags":{"app":"web2"},"version_id":1,"network_ref":null,"aggregate_network_routes":null}]