Skip to content

Manage Data

Machinable's main feature is the ability to perform CRUD (Create, Read, Update, Delete) operations on your project's API Resource endpoints. API Resources provide data validation based on the JSON schema.

Note

See API Resources for more information about data validation with JSON Schema.

All examples will be using the Pet Demo project, which has the following project URL:

1
https://pet-demo.machinable.io

Authentication

Note

If your project authentication policy is disabled, you do not need to provide an Authorization header in your requests. The examples on this page do not make use of an Authorization header.

Depending on how you are accessing your project's data, you may need to authenticate your requests.

API Keys

To make authenticated requests with an API Key, add the Authorization header with the apikey text to each request:

1
Authorization: apikey {api_key_string}

Users

User authenticated requests require a bit more work.

First, the user will need to acquire a session. To do that, make an HTTP Basic authentication request to your project's /sessions endpoint. This will return an access_token and a refresh_token in the form of JSON Web Tokens:

1
2
3
4
5
6
7
8
# base64 encode username|password to make HTTP Basic authn request
$ echo "testUser:hunter2" | base64
dGVzdFVzZXI6aHVudGVyMgo=

# POST credentials to /sessions/ endpoint to recieve access token
$ curl -X POST \
  https://pet-demo.machinable.io/sessions/ \
  -H 'authorization: Basic dGVzdFVzZXI6aHVudGVyMg=='
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests

url = "https://pet-demo.machinable.io/sessions/"

headers = {
    'authorization': "Basic dGVzdFVzZXI6aHVudGVyMg=="
    }

response = requests.request("POST", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
var data = null;

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://pet-demo.machinable.io/sessions/");
xhr.setRequestHeader("authorization", "Basic dGVzdFVzZXI6aHVudGVyMg==");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/sessions/"

    req, _ := http.NewRequest("POST", url, nil)

    req.Header.Add("authorization", "Basic dGVzdFVzZXI6aHVudGVyMg==")

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Successful response:

1
2
3
4
5
6
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTIzMjI4MTksInByb2plY3RzIjp7InBldC1kZW1vIjp0cnVlfSwidXNlciI6eyJhY3RpdmUiOnRydWUsImlkIjoiNWM4NjhkNDBhNzc0OGJiMjI0ODMzZjRiIiwibmFtZSI6InRlc3RVc2VyIiwicmVhZCI6dHJ1ZSwidHlwZSI6InByb2plY3QiLCJ3cml0ZSI6dHJ1ZX19.93H4H3FyPGrzOGb3WHRO7RLUGezpYxbVki7oGqdyA6E",
  "message": "Successfully logged in",
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NTI1ODExMTksInNlc3Npb25faWQiOiI1Yzg2OGQ3ZmE3NzQ4YmIyMjQ4MzNmNGMiLCJ1c2VyX2lkIjoiNWM4NjhkNDBhNzc0OGJiMjI0ODMzZjRiIn0.wWyb-nNff3RBw73D1hqN9k8U8_pKMHWGShMwA9YvSAc",
  "session_id": "5c868d7fa7748bb224833f4c"
}

Once the user has a session, authenticated requests can be made by adding the Authorization header with the bearer text and access_token to each request:

1
Authorization: bearer {access_token}

Info

Access tokens have a limited lifetime of 5 minutes. They then need to be exchanged for a new Access token using the refresh token. Refer to Project Users for more information about refreshing an access token.

Create

Create and store a new object in a specific API Resource.

Note

These examples are managing data within an API Resource called dogs at /api/dogs, given the correct JSON schema is defined.

1
2
3
$ curl -X POST \
  https://pet-demo.machinable.io/api/dogs \
  -d '{"name":"Murphy", "age":2, "breed": "French Bulldog"}'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import requests

url = "https://pet-demo.machinable.io/api/dogs"

payload = "{\"name\":\"Murphy\", \"age\":2, \"breed\": \"French Bulldog\"}"
headers = {}

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = "{\"name\":\"Murphy\", \"age\":2, \"breed\": \"French Bulldog\"}";

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("POST", "https://pet-demo.machinable.io/api/dogs");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
    "fmt"
    "strings"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs"

    payload := strings.NewReader("{\"name\":\"Murphy\", \"age\":2, \"breed\": \"French Bulldog\"}")

    req, _ := http.NewRequest("POST", url, payload)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
< HTTP/1.1 201 Created

{
  "_metadata": {
    "created": 1552323811,
    "creator": "anonymous",
    "creator_type": "anonymous"
  },
  "age": 2,
  "breed": "French Bulldog",
  "id": "5c8694e3a7748bb224833f51",
  "name": "Murphy"
}

Read

Retrieve a single object from a resource or list all objects that exist (paginated).

Retrieve single object

To retrieve a single object, make a GET request to the resource with the ID of the object as the last path parameter.

1
2
curl -X GET \
  https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

headers = {}

response = requests.request("GET", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

    req, _ := http.NewRequest("GET", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
< HTTP/1.1 200 OK

{
  "_metadata": {
    "created": 1552326051,
    "creator": "anonymous",
    "creator_type": "anonymous"
  },
  "age": 7,
  "breed": "German Shephard",
  "id": "5c869da3a7748bb224833f5c",
  "name": "Max"
}

List objects

To retrieve a paginated list of objects for this resource, make a GET request to the resource.

1
2
curl -X GET \
  https://pet-demo.machinable.io/api/dogs
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs"

headers = {}

response = requests.request("GET", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("GET", "https://pet-demo.machinable.io/api/dogs");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs"

    req, _ := http.NewRequest("GET", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))
}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
< HTTP/1.1 200 OK

{
  "count": 2,
  "items": [
    {
      "_metadata": {
        "created": 1552323811,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 2,
      "breed": "French Bulldog",
      "id": "5c8694e3a7748bb224833f51",
      "name": "Murphy"
    },
    {
      "_metadata": {
        "created": 1552326051,
        "creator": "anonymous",
        "creator_type": "anonymous"
      },
      "age": 7,
      "breed": "German Shephard",
      "id": "5c869da3a7748bb224833f5c",
      "name": "Max"
    }
  ],
  "links": {
    "self": "https://pet-demo.machinable.io/api/dogs?_limit=10&_offset=0"
  }
}

Notice the resource objects are returned as a list in the items key. A maximum of 10 objects will be returned by default.

See Pagination for more information regarding the page limit as well as the other keys in the root of the response JSON.

Update

Update a single object's values.

1
2
3
4
5
6
curl -X PUT \
  https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c \
  -d '{
        "age": 9,
        "name": "Maximilian"
    }'
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import requests

url = "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

payload = "{\n    \"age\": 9,\n    \"name\": \"Maximilian\"\n}"
headers = {}

response = requests.request("PUT", url, data=payload, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = "{\n    \"age\": 9,\n    \"name\": \"Maximilian\"\n}";

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("PUT", "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package main

import (
    "fmt"
    "strings"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

    payload := strings.NewReader("{\n    \"age\": 9,\n    \"name\": \"Maximilian\"\n}")

    req, _ := http.NewRequest("PUT", url, payload)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Successful response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
< HTTP/1.1 200 OK

{
    "_metadata": {
      "created": 1552326051,
      "creator": "anonymous",
      "creator_type": "anonymous"
    },
    "age": 9,
    "breed": "German Shephard",
    "id": "5c869da3a7748bb224833f5c",
    "name": "Maximilian"
}

Delete

Permanently remove an object.

1
2
curl -X DELETE \
  https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c
1
2
3
4
5
6
7
8
9
import requests

url = "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

headers = {}

response = requests.request("DELETE", url, headers=headers)

print(response.text)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var data = null;

var xhr = new XMLHttpRequest();

xhr.addEventListener("readystatechange", function () {
  if (this.readyState === 4) {
    console.log(this.responseText);
  }
});

xhr.open("DELETE", "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c");

xhr.send(data);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
    "fmt"
    "net/http"
    "io/ioutil"
)

func main() {

    url := "https://pet-demo.machinable.io/api/dogs/5c869da3a7748bb224833f5c"

    req, _ := http.NewRequest("DELETE", url, nil)

    res, _ := http.DefaultClient.Do(req)

    defer res.Body.Close()
    body, _ := ioutil.ReadAll(res.Body)

    fmt.Println(res)
    fmt.Println(string(body))

}

Successful response:

1
< HTTP/1.1 204 No Content