The API is currently in beta. We are looking for feedback on both, the API design itself as well as the documentation.
The Humanitec API allows for automating and integrating of Humanitec into your workflows The API is a REST based API. It is based around a set of concepts:
Almost all requests made to the Humanitec API require Authentication. Humanitec provides 2 ways of authenticating with the API: Bearer
and JWT
.
This form of authentication makes use of a static token. It is intended to be used when machines interact with the Humanitec API. Bearer tokens should be used for very narrow purposes. This allows for the token to be revoked if it is compromised and so limit the scope of exposure. New Bearer tokens can be obtained via the UI:
The token is passed to the API via the Authorization
header. Assuming the issued token is HUMANITEC_TOKEN
, the request could be made as follows:
curl -H 'Authorization: Bearer HUMANITEC_TOKEN' https://api.humanitec.io/orgs/my-org/apps
This form of authentication makes use of a JSON Web Token (JWT). It is intended to be used when humans interact with the Humanitec API. JWTs expire after a period of time. This means that a new JWT will need to be generated regularly. This makes them well suited to working in short sessions, but not for automation. (See Bearer Authentication.)
The token is passed to the API via the Authorization
header. Assuming the issued token is HUMANITEC_JWT
, the request could be made as follows:
curl -H 'Authorization: JWT HUMANITEC_JWT' https://api.humanitec.io/orgs/my-org/apps
All of the Humanitec API unless explicitly only accepts content types of application/json
and will always return valid application/json
or an empty response.
Any response code in the 2xx
range should be regarded as success.
Code | Meaning |
---|---|
200 |
Success |
201 |
Success (In future, 201 will be replaced by 200 ) |
204 |
Success, but no content in response |
Note: We plan to simplify the interface by replacing 201 with 200 status codes.
Any response code in the 4xx
should be regarded as an error which can be rectified by the client. 5xx
error codes indicate errors that cannot be corrected by the client.
Code | Meaning |
---|---|
400 |
General error. (Body will contain details) |
401 |
Attempt to access protected resource without Authorization Header. |
403 |
The Bearer or JWT does not grant access to the requested resource. |
404 |
Resource not found. |
405 |
Method not allowed |
409 |
Conflict. Usually indicated a resource with that ID already exists. |
422 |
Unprocessable Entity. The body was not valid JSON, was empty or contained an object different from what was expected. |
429 |
Too many requests - request rate limit has been reached. |
500 |
Internal Error. If it occurs repeatedly, contact support. |
The core objects in the API provide the structure that allows Continuous Delivery to be well organized. The core objects are summarised as:
Object | Description |
---|---|
Organization |
The root of the object hierarchy representing unrelated teams or companies. |
Application |
A logical collection of related Kubernetes workloads that should run in the same namespace. |
Environment |
An independent space that an Application can be deployed into. |
Deployment |
A specific version of code and configuration that has been deployed into an Environment. |
The hierarchy is illustrated by this Entity Relationship Diagram (ERD):
In addition to Organizations, Applications, Environments, and Deployments, a number of other objects are included in this section:
Object | Description |
---|---|
Image |
Represents many builds (aka versions) of the same container image. |
Image Source |
How Images are brought into Humanitec. |
Environment Type |
A way of grouping and managing Environments. |
Not everything required by an Application can be run in a Kubernetes cluster. It does not make sense to run some things in a cluster such as Public DNS. Sometimes developers and architectures may prefer to take advantage of "Managed Services" instead of running them inside a cluster. Humanitec can manage and provision dependencies that are external to the cluster. We call these "External Resources". Examples include:
All External Resources have a Type. This defines what technology the Application has the dependency on and is distinct from the implementation of that technology. For example, the redis
type represents a Redis store but does not specify if it is provided via an actual Redis Cluster or via a compatible service such as Google's Memorystore or Amazon ElastiCache for Redis.
Each Resource Type has its own way of being parameterized. For example, a resource of type dns
needs to know the IP address that A
record should point at.
An Active Resource describes a provisioned and usable resource. This represents an instance of the resource, e.g. the actual database that data can be stored in or the DNS name that can be used to resolve the IP address serving a service.
Active Resources are specified via Resource Definitions. These tell Humanitec how to provision a resource of a particular Resource Type. Resource Definitions are chosen based on Matching Criteria. There are two different kinds of Resource Definition, Dynamic Resource Definitions, and Static Resource Definitions.
Humanitec chooses which Resource Definition to use based on Matching Criteria. A Matching Criteria specifies a set of values that the properties of an Environment must have in order for the Resource Definition to be matched and so used to provision the resource. These properties include:
Property | Description |
---|---|
app_id |
The ID of the Application that an Environment belongs to. |
env_id |
The ID of a particular Environment. |
env_type |
The Environment Type that an Environment has. |
res_id |
The ID of the resource as specified in the Deployment Set. |
A Matching Criteria can specify 0, 1, or more properties at once. In the event of multiple matches, the most specific match is chosen. For example: if two Resource Definitions for resources with type postgres
have the matching criteria:
Resource Definition A:
env_type = development
Resource Definition B:
env_type = development
res_id = modules.my-service.exernals.my-db
and a resource is needed for an Environment of type development
and a Postgres database with ID modules.my-service.exernals.my-db
, Resource Definition B will be chosen.
Dynamic Resource Definitions specify Active Resources where Humanitec manages the full lifecycle. In this instance, if a resource is needed it it created by Humanitec and destoryed when it is no longer needed. This is done by specifying a Resource Driver that manages the resource.
Static Resource Definitions specify Active Resources that are managed outside of Humanitec. For example, a pre-existing database can be used via a Static Resource Definition. In this case, nothing is created or destroyed by Humanitec.
Resource Drivers are code that fulfills the Humanitec Resource Driver Interface. This interface allows for certain actions to be performed on resources such as creation and destruction. Humanitec provides a number of Resource Drivers "out of the box". It is also possible to use 3rd party Resource Drivers or even to write your own. Resource Drivers typically call APIs associated with managed services. They use the credentials provided by Resource Accounts in order to manipulate resources provided via managed services.
Resource Accounts are identities that are used to provision and manage resources via Dynamic Resource Definitions. They can represent a range of identities including Cloud Provider Service Accounts, VPN Accounts and SSH accounts
Deployment Sets and Deployment Deltas (referred to in the rest of this document as "Sets" and "Deltas") provide the means of managing the non-environment specific configuration for an Application. A Set contains all non-environment specific configuration for an Application. A Delta describes the difference between two Sets - specifically what needs to be done to change one Set into another.
Sets and Deltas form a closed algebra over a 3 operations:
Set [apply] Delta -> Set
A Delta applied to a Set generates another set. NOTE: This is the only operation that generates a Set. To bootstrap the creation of Sets, a Delta can be applied to the "Empty Set".
Set [diff] Set -> Delta
The difference between two Sets generates a Delta.
Delta [combine] Delta -> Delta
Combining 2 or more Deltas results in a Delta.
Every Deployment that occurs through Humanitec is based on a Set. Every Deployment has one Set associated with it. Upon deployment, the supplied Delta is applied to the Set associated with a previous Deployment. This previous Deployment is often but not always the last Deployment in an Environment. See Rebasing an Environment for a description of such a scenario.
A good model for understanding how Sets and Deltas work is by analogy with Version Control Systems.
VCS Concept | Analogous Concept in Humanitec |
---|---|
Commit | A Set |
Branch | Environment |
Log | Deployment History in an Environment |
Diff | A Delta generated from the difference between 2 Sets |
Patch | A Delta that can be applied to a Set |
There is no analogy to "merging" - however, an Environment can have the same Set deployed in it by way of Rebasing an Environment.
In this guide, we would like to show you how to deploy your application via the Humanitec API. Please refer to the API reference for any specific details.
We will go over the creation of an application with the default environment Development
. Then, we'll add a frontend and a backend service to the application based on our Sample Tutorial Application. We'll go over the configuration of those services and finally, we will deploy the application environment to a kubernetes cluster.
In order to make authenticated requests to the Humanitec API you'll need to have a valid API token. Please refer to API Authentication to learn how to obtain one. Export the token as an environment variable to use it with your API calls.
export HUMANITEC_TOKEN="your-token"
First, we need to obtain your organization id as it is essential for the API path.
HUMANITEC_USER_JSON=$(curl -XGET -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' 'https://api.humanitec.io/users/me' | jq .)
HUMANITEC_ORG=$(echo $HUMANITEC_USER_JSON | jq '.orgs[].id' | tr -d '"')
This cURL will create an application draft with the default environment Development
. The application will act as a container for your environments which can contain different configurations of your application.
curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d '{"id":"my-sample-app","name":"My Sample App"}' \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps
To fill this application with services we need to define an empty application delta first. The delta is a configuration that is getting applied to the environment of your application upon deployment.
DELTA_ID=$(curl -X POST -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d '{"modules": {}}' \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas | tr -d '"')
The images for the Sample Tutorial Application already exist in Humanitec. If you'd like to add your own images and services to an application, please refer to the API Documentation about Images.
Create the payload for the cURL command. In this payload, we already define some default settings. These settings like resource limits and requests as well as the service port can be overwritten later if required.
cat << 'EOF' > payload.json
[
{
"modules": {
"add": {
"sample-service": {
"profile": "humanitec/default-module",
"spec": {
"service": {
"ports": [
{
"service_port": 8080
}
]
},
"ingress": {
"enabled": false
},
"containers": {
"sample-service": {
"id": "sample-service",
"image": "dev-registry.humanitec.io/public/sample-service:1.2.0",
"resources": {
"limits": {
"cpu": "0.250",
"memory": "256Mi"
},
"requests": {
"cpu": "0.025",
"memory": "64Mi"
}
},
"variables": {
},
"secrets": {
}
}
}
},
"externals": {
}
}
}
}
}
]
EOF
Now we apply the payload.json
via a PATCH call to update the existing Delta for the application.
curl -X PATCH -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d "@payload.json" \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas/$DELTA_ID
With this payload and PATCH to the delta, we will add a cloudsql Postgres DB to the backend service.
cat << 'EOF' > payload.json
[
{
"modules": {
"update": {
"sample-service": [
{
"op": "add",
"path": "/externals/postgres",
"value": {
"type": "postgres"
}
}
]
}
}
}
]
EOF
Applying the payload with PATCHing the delta.
curl -X PATCH -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d "@payload.json" \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas/$DELTA_ID
With this payload and PATCH to the delta, we will add an environment variable to the service which is containing the connection string to the database. In this string are placeholder variables which will be automatically filled with the credentials to connect to the database once it's created with the deployment.
cat << 'EOF' > payload.json
[
{
"modules": {
"update": {
"sample-service": [
{
"op": "add",
"path": "/spec/containers/sample-service/variables/CONNECTION_STRING",
"value": "postgresql://${externals.postgres.username}:${externals.postgres.password}@${externals.postgres.host}:${externals.postgres.port}/${externals.postgres.name}"
}
]
}
}
}
]
EOF
Applying the payload with PATCHing the delta.
curl -X PATCH -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d "@payload.json" \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas/$DELTA_ID
Similar to the Backend, we add a second module/service to the application delta containing the frontend service.
cat << 'EOF' > payload.json
[
{
"modules": {
"add": {
"sample-app": {
"profile": "humanitec/default-module",
"spec": {
"service": {
"ports": [
{
"service_port": 8080
}
]
},
"ingress": {
"enabled": false
},
"containers": {
"sample-app": {
"id": "sample-app",
"image": "dev-registry.humanitec.io/public/sample-app:1.3.0",
"resources": {
"limits": {
"cpu": "0.250",
"memory": "256Mi"
},
"requests": {
"cpu": "0.025",
"memory": "64Mi"
}
},
"variables": {
},
"secrets": {
}
}
}
},
"externals": {
}
}
}
}
}
]
EOF
Now we apply the payload.json
via a PATCH call to update the existing Delta for the application.
curl -X PATCH -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d "@payload.json" \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas/$DELTA_ID
Here we define an ingress to be created in order for the app to be exposed under a generated DNS and URL.
cat << 'EOF' > payload.json
[
{
"modules": {
"update": {
"sample-app": [
{
"op": "add",
"path": "/spec/ingress/enabled",
"value": true
}
]
}
}
}
]
EOF
Now we apply the payload.json
via a PATCH call to update the existing Delta for the application.
curl -X PATCH -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d "@payload.json" \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sample-app/deltas/$DELTA_ID
Now everything is configured. We can now deploy the application using the updated delta.
curl -X POST -v -H 'Content-Type: application/json' -H 'Authorization:Bearer '$HUMANITEC_TOKEN'' \
-d '{"delta_id":"'$DELTA_ID'","comment":"My Sample App Deployment"}' \
https://api.humanitec.io/orgs/$HUMANITEC_ORG/apps/my-sam