Chapter 21. The REST API

Table of Contents

21.1. Introduction
21.2. Getting started
21.3. Resource Examples
21.4. Resources
21.5. Configuration Meta-Data
21.6. Request/Response headers
21.7. Special characters
21.8. Error Responses
21.9. The Query API
21.10. Custom Response HTTP Headers
21.11. HTTP Status Codes

21.1. Introduction

This document describes a RESTful API over HTTP for accessing data defined in YANG. It tries to follow the RESTCONF Internet Draft [draft-ietf-netconf-restconf-00] but since it predates the creation of RESTCONF, a number of differences exists. Whenever such a difference occur, it will be clearly stated.

The RESTCONF protocol operates in the configuration datastores defined in NETCONF. It defines a set of Create, Retrieve, Update, Delete (CRUD) operations that can be used to access these datastores. The YANG language defines the syntax and semantics of datastore content, operational data and protocol operations. REST operations are used to access the hierarchical data within a datastore. Request and response data can be in XML or JSON format, where XML is the default format.

To get a quick introduction to how to enable REST in ConfD and how to run the CRUD operations, continue to Section 21.2, “Getting started”.

To read more about resources, continue to Section 21.4, “Resources”.

Tip

All REST request/response examples in this chapter are based on the examples.confd/rest/router example. Go to this example to play around and get familiar with the REST api.

Tip

Sending REST requests using a browser is an easy way to test things. But using REST with Basic Authentication in the browser should not be used because of security considerations. Use the JSON-RPC login mechanism instead. Once authenticated, REST requests don't need Basic Authentication anymore. You can read more about the JSON login mechanism in ????.

21.2. Getting started

In order to enable REST in ConfD, REST must be enabled in confd.conf . The web server configuration for REST is shared with the WebUI's config. However, the WebUI does not have to be enabled for REST to work.

Here's a minimal example of what is needed in the conf file:

Example 21.1. ConfD configuration for REST

    <rest>
      <enabled>true</enabled>
    </rest>

    <webui>
      <enabled>false</enabled>
      <transport>
        <tcp>
          <enabled>true</enabled>
          <ip>0.0.0.0</ip>
          <port>8008</port>
        </tcp>
      </transport>
    </webui>
  


21.2.1. Request URI structure

Resources are represented with URIs following the structure for generic URIs in [RFC3986].

Example 21.2. Request URI structure

        <OP> /api/<path>?<query>#<fragment>

         ^    ^     ^        ^       ^
         |    |     |        |       |
       method entry resource query fragment

         M      M      O       O     I

       M=mandatory, O=optional, I=ignored


       <text> replaced by client with real values
       

A REST operation is derived from the HTTP method and the request URI, using the following conceptual fields:

  • "method": the HTTP method identifying the REST operation requested by the client, to act upon the target resource specified in the request URI.

  • "entry": the well-known REST entry point ("/api").

    Note

    THIS DIFFERS FROM RESTCONF!

  • "resource": the path expression identifying the resource that is being accessed by the operation. If this field is not present, then the target resource is the API itself, represented by the media type "application/vnd.yang.api".

    Note

    THE MEDIA TYPE DIFFERS FROM RESTCONF!

  • "query": the set of parameters associated with the REST message. These have the familiar form of "name=value" pairs. There is a specific set of parameters defined, see Section 21.2.10, “Query Parameters”. The contents of the query parameter value must be encoded according to [RFC2396], section 3.4. Any reserved characters must be encoded with escape sequences, according to [RFC2396], section 2.4.

  • "fragment": This field is not used by the REST protocol.

The REST protocol uses HTTP methods to identify the CRUD operation requested for a particular resource. The following table shows how the REST operations relate to NETCONF protocol operations:

Table 21.1. REST vs NETCONF operations

RESTNETCONF
GET<get-config>, <get>
POST<edit-config> (operation="create")
PUT<edit-config> (operation="replace")
PATCH<edit-config> (operation="merge")
DELETE<edit-config> (operation="delete")
OPTIONSnone
HEADnone

21.2.2. Accessing the REST API

The REST API can be accessed, e.g., by using curl:

Example 21.3. Using curl for accessing ConfD

    curl -u admin:admin -s http://localhost:8008/api/foo/bar -X GET
    

To provide an HTTP header use the -H switch:

    ... -H "Accept: application/vnd.data+xml"
    

Note that in the following examples we will shorten the curl calls to:

    GET /foo/bar
    Accept: application/vnd.data+xml
    


By default curl will display responses on standard output. The headers are not included. To include these the "-i" switch has to be added.

    curl -i ...
    

The response can then typically look like:


    HTTP/1.1 200 OK
    Server: ConfD/5.3.0
    Cache-control: private, no-cache, must-revalidate, proxy-revalidate
    Date: Fri, 05 Sep 2014 13:09:46 GMT
    Content-Type: application/vnd.yang.data+json
    Transfer-Encoding: chunked
    Etag: 1409-922585-953711
    Last-Modified: Fri, 01 Jan 1971 00:00:00 GMT

    {
      "some-data": {
        "some-value": "value"
      }
    }

    

In the examples shown in this chapter we will from the beginning show all headers with the response. In later examples the headers will be omitted for brevity.

21.2.3. GET

The GET method is sent by the client to retrieve data and meta-data for a resource. It is supported for all resource types, except operation resources. The request must contain a request URI that contains at least the entry point component (/api). Note how we make use of the Accept HTTP header to indicate what format we want the returned result to be in. The value of the Accept HTTP header, in this example: application/yang.data+json, must be a valid media type. Since XML is the default format we need to explicitly request JSON in the example below. To read more about the media types, see Section 21.4, “Resources”.

Example 21.4. Get the "sys/interfaces" resource represented as JSON

GET /running/sys/interfaces/ex:serial
Accept: application/vnd.yang.collection+json

The server might respond:

HTTP/1.1 200 OK
Server: 
Date: Wed, 12 Aug 2015 11:38:20 GMT
Last-Modified: Fri, 01 Jan 1971 00:00:00 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379499-898453
Content-Type: application/vnd.yang.collection+json
Transfer-Encoding: chunked
Pragma: no-cache

{
  "collection": {
    "example-serial:serial": [
      {
        "name": "ppp0",
        "ppp": {
          "accounting": "acme"
        },
        "authentication": {
          "method": "pap"
        },
        "authorization": "admin",
        "ipcp": {
        }
      }
    ]
  }
}


Note

To indicate a particular YANG namespace in the URI, the YANG module prefix is used. In the example we are using a module prefix: ex .
THIS DIFFERS FROM RESTCONF!

In accordance with RESTCONF, the returned "serial" container is using a module name: example-serial to indicate a particular YANG namespace.

To read more about the ETag and Last-Modified response headers, see Section 21.6, “Request/Response headers”.

Refer to Section 21.3.1, “GET and Query examples” for more resource retrieval examples.

21.2.4. POST

The POST method is sent by the client to create a data resource or invoke an operation resource ("rpc" or "tailf:action").

Here we show an example of resource creation using POST. For an example of operation invokation see Section 21.3.3, “Invoke Operations”

Example 21.5.  Create a new "sys/routes/inet/route" resource, with JSON payload

POST /running/sys/routes/inet
Content-Type: application/vnd.yang.data+json

{
  "route": {
    "name": "10.20.1.0",
    "prefix-length": "24"
  }
}

If the resource is created, the server might respond as follows:

HTTP/1.1 100 Continue
Server: 
Allow: GET, POST, OPTIONS, HEAD
Content-Length: 0

HTTP/1.1 201 Created
Server: 
Location: 
http://127.0.0.1:8008/api/running/sys/routes/inet/route/10.20.1.0,24
Date: Wed, 12 Aug 2015 11:38:20 GMT
Allow: GET, POST, OPTIONS, HEAD
Last-Modified: Wed, 12 Aug 2015 11:38:20 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379500-235361
Content-Length: 0
Content-Type: text/html
Pragma: no-cache


If the POST method succeeds, a "201 Created" Status-Line is returned and there is no response message body. Also, a "Location" header identifying the child resource that was created is present in the response.

Refer to the section called “Create a List Instance with POST” for more examples of creating resources.

If the target resource type is an operation resource, then the POST method is treated as a request to invoke that operation. The message body (if any) is processed as the operation input parameters. Refer to Section 21.4.5, “Operations and Actions” for details on operation resources.

21.2.5. PUT

The PUT method is sent by the client to create or replace the target resource. The request must contain a request URI that contains a target resource that identifies the data resource to create or replace.

Example 21.6. Replace the "sys/routes/inet/route" resource contents

PUT /running/sys/routes/inet/route/10.20.1.0,24
Content-Type: application/vnd.yang.data+json

{
  "route": {
    "name": "10.20.1.0",
    "prefix-length": "24",
    "description": "Example route",
    "enabled" : "false"
  }
}

If the resource is updated, the server might respond:

HTTP/1.1 100 Continue
Server: 
Allow: GET, POST, OPTIONS, HEAD
Content-Length: 0

HTTP/1.1 204 No Content
Server: 
Date: Wed, 12 Aug 2015 11:38:20 GMT
Allow: GET, POST, OPTIONS, HEAD
Last-Modified: Wed, 12 Aug 2015 11:38:20 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379500-401146
Content-Length: 0
Content-Type: text/html
Pragma: no-cache


The "insert" and "resource" query parameters are supported by the PUT method for data resources, for more examples see the section called “Insert Data into Resources”.

Note

The "resource" query parameter correspond to the "point" query parameter in RESTCONF.
THIS DIFFERS FROM RESTCONF!

If the PUT method creates a new resource, a "201 Created" Status-Line is returned. If an existing resource is modified, either "200 OK" or "204 No Content" are returned.

Refer to the section called “Create and Replace a List Instance with PUT” for more examples on how to use PUT.

21.2.6. PATCH

The PATCH method is used to create or update a sub-resource within the target resource. If the target resource instance does not exist, the server WILL NOT create it.

To replace just the "enabled" field in the "route" list resource (instead of replacing the entire resource with the PUT method), the client might send a plain patch as follows.

Example 21.7. Update the "sys/routes/inet/route" resource contents

PATCH /running/sys/routes/inet/route/10.20.1.0,24
Content-Type: application/vnd.yang.data+json

{
  "route": {
    "enabled" : "true"
  }
}

If the resource is updated, the server might respond:

HTTP/1.1 100 Continue
Server: 
Allow: GET, POST, OPTIONS, HEAD
Content-Length: 0

HTTP/1.1 204 No Content
Server: 
Date: Wed, 12 Aug 2015 11:38:20 GMT
Allow: GET, POST, OPTIONS, HEAD
Last-Modified: Wed, 12 Aug 2015 11:38:20 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379500-570215
Content-Length: 0
Content-Type: text/html
Pragma: no-cache


Refer to the section called “Update Existing List Instance with PATCH” for more examples on how to use PATCH.

21.2.7. DELETE

The DELETE method is used to delete the target resource. If the DELETE method succeeds, a "204 No Content" Status-Line is returned, and there is no response message body.

Example 21.8. Delete the "sys/routes/inet/route" resource contents

DELETE /running/sys/routes/inet/route/10.20.1.0,24

If the resource is successfully deleted, the server might respond:

HTTP/1.1 204 No Content
Server: 
Date: Wed, 12 Aug 2015 11:38:20 GMT
Last-Modified: Wed, 12 Aug 2015 11:38:20 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379500-746781
Content-Length: 0
Content-Type: text/html
Pragma: no-cache


Refer to Section 21.3.4, “Delete Data Resources” for more examples on how to use DELETE.

21.2.8. OPTIONS

The OPTIONS method is sent by the client to discover which methods are supported by the server for a specific resource. The supported methods are listed in the ALLOW header.

Example 21.9. Get options for the "sys" resource

OPTIONS /running/sys

The server might respond:

HTTP/1.1 200 OK
Server: 
Allow: DELETE, GET, HEAD, PATCH, POST, PUT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Content-Length: 0
Content-Type: text/html
Pragma: no-cache


Here the options method responds with an ALLOW header indicating that all methods are allowed on the "sys" resource.

21.2.9. HEAD

The HEAD method is sent by the client to retrieve just the headers that would be returned for the comparable GET method, without the response body. The access control behavior is enforced as if the method was GET instead of HEAD. The server will respond the same as if the method was GET instead of HEAD, except that no response body is included.

Example 21.10. Get head for the "sys/interfaces/ex:serial" resource

HEAD /running/sys/interfaces/ex:serial

The server might respond:

HTTP/1.1 200 OK
Server: 
Date: Wed, 12 Aug 2015 11:38:20 GMT
Last-Modified: Wed, 12 Aug 2015 11:38:20 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379500-746781
Content-Length: 0
Content-Type: application/vnd.yang.collection+xml
Pragma: no-cache


Here the "Content-Length" header is 0. This is because the content length calculation is not eligible when the actual content is suppressed as with the HEAD method.

21.2.10. Query Parameters

Each REST operation allows zero or more query parameters to be present in the request URI. The specific parameters that are allowed depends on the resource type, and sometimes the specific target resource used, in the request.

Table 21.2. Query Parameters

NameMethodsDescription
deepGETRetrieve a resource with all subresources inline.
insertPOST For an ordered-by user list, we can specify where a resource, to be created, should be inserted. This query parameter is used together with the resource query parameter. Possible values are: after, before,first and last. See the section called “Insert Data into Resources” for details.
limitGET Used by the client to specify a limited set of list entries to retrieve. See the section called “Partial Responses” for details.
offsetGET Used by the client to specify a limited set of list entries to retrieve. See the section called “Partial Responses” for details.
operationsGET Used by the client to include/exclude operations (tailf:actions) in the result. Possible values are: true, which is the default value, and false.
resourcePOST For an ordered-by user list, we can specify where a resource, to be created, should be inserted. This query parameter is used together with the insert query parameter. See the section called “Insert Data into Resources” for details.
selectGET Used by the client to select which nodes and subresources in a resource to retrieve. See the section called “Partial Responses” for details.
shallowGETRetrieve a resource with no subresources inline.
unhideGET Used by the client to unhide hidden nodes. See the section called “Hidden Nodes” for details.
verboseGET Used by the client to control display of the "self" and "path" attributes of the resource. See the section called “Displaying Default Data” for details.
with-defaultsGET Used by the client to control display of default data in GET requests. See the section called “Displaying Default Data” for details.

Note

The query parameters of the REST API is not the same as for RESTCONF.
THIS DIFFERS FROM RESTCONF!

If neither "deep" nor "shallow" is used, you will get a variable depth returned. The output shown will stop at the first encountered presence container or list key value(s).

21.3. Resource Examples

21.3.1. GET and Query examples

Retrieve Data Resources

If a resource only needs to be outlined, the shallow query parameter can be used on the GET request.

Example 21.11. Shallow get for the "sys" resource

GET /running/sys?shallow

The server might respond:

<sys xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <interfaces/>
  <routes/>
  <syslog/>
  <ntp/>
  <dns/>
</sys>


On the other hand, if the full subtree under a resource is required, the deep query parameter can be used on the GET request.

Example 21.12. Deep get for the "sys/interfaces/interface" resource

GET /running/sys/interfaces/interface?deep

The server might respond:

<collection xmlns:y="http://tail-f.com/ns/rest">
  <interface xmlns="http://example.com/router">
    <name>eth0</name>
    <unit xmlns="http://example.com/router">
      <name>0</name>
      <enabled>true</enabled>
      <status xmlns="http://example.com/router">
      </status>
      <family xmlns="http://example.com/router">
        <inet xmlns="http://example.com/router">
          <address xmlns="http://example.com/router">
            <name>192.168.1.2</name>
            <prefix-length>16</prefix-length>
          </address>
        </inet>
      </family>
    </unit>
    <unit xmlns="http://example.com/router">
      <name>1</name>
      <enabled>true</enabled>
      <status xmlns="http://example.com/router">
      </status>
      <family xmlns="http://example.com/router">
        <inet xmlns="http://example.com/router">
          <address xmlns="http://example.com/router">
            <name>192.168.1.3</name>
            <prefix-length>16</prefix-length>
          </address>
        </inet>
      </family>
    </unit>
    <unit xmlns="http://example.com/router">
      <name>2</name>
      <enabled>true</enabled>
      <description>My Vlan</description>
      <vlan-id>18</vlan-id>
      <status xmlns="http://example.com/router">
      </status>
    </unit>
  </interface>
</collection>


For more info about "deep" vs "shallow", see: Section 21.2.10, “Query Parameters”

Partial Responses

By default, the server sends back the full representation of a resource after processing a request. For better performance, the server can be instructed to send only the nodes the client really needs in a partial response.

To request a partial response for a set of list entries, use the "offset" and "limit" query parameters to specify a limited set of entries to be returned.

For example, if we what to retrieve only 2 entries from the sys/routes/inte/route list we can issue the command:

Example 21.13. Limit the response

GET /running/sys/routes/inet/route?offset=3&limit=2

The following request retrieves 2 entries starting from entry 3 (the first entry is 0):

<collection xmlns:y="http://tail-f.com/ns/rest">
  <route xmlns="http://example.com/router">
    <name>10.40.0.0</name>
    <prefix-length>16</prefix-length>
    <description>Route 4</description>
    <next-hop xmlns="http://example.com/router">
      <name>192.168.10.4</name>
    </next-hop>
  </route>
  <route xmlns="http://example.com/router">
    <name>10.50.0.0</name>
    <prefix-length>16</prefix-length>
    <description>Route 5</description>
    <next-hop xmlns="http://example.com/router">
      <name>192.168.10.5</name>
    </next-hop>
  </route>
</collection>


To request a filtered partial response, use the "select" query parameter to specify the nodes and subresources to be returned.

  • Use a semicolon-separated list to select multiple nodes.

  • Use "a/b" to select a node "b" that is nested within node "a"; use "a/b/c" to select a node "c" nested within "b".

  • Specify node subselectors to request only specific subnodes by placing expressions in parentheses "( )" after any selected node.

  • To specify all subnodes of a specific node use the special wildcard notion within parentheses "(*)"

NOTE: "a/b/c;a/b/d" is equivalent to "a/b(c;d)"

The following request selects the routes name and next-hop/name nodes:

Example 21.14. Limit the response with select

GET 
/running/sys/routes/inet/route/10.20.0.0,16?select=name;next-hop(name)

The server might respond:

<route xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <name>10.20.0.0</name>
  <next-hop>
    <name>192.168.10.2</name>
  </next-hop>
</route>


Hidden Nodes

Hidden nodes are described in Section 10.7, “Hidden Data”. By default, hidden nodes are not visible in the REST interface. In order to unhide hidden nodes for retrieval or editing, clients can use the query parameter "unhide". The format of the "unhide" parameter is a comma-separated list of

<groupname>[;<password>]

As an example:

unhide=extra,debug;secret

This example unhides the normal group "extra" and the password-protected group "debug" with the password "secret".

Displaying Default Data

Normally, leaf nodes that are not set but has a default value are not displayed at a GET request. This behavior can be controlled by the use of the "with-defaults" query parameter. This parameter can take one of four values:

  • "report-all": all data nodes are be reported, including any data nodes considered to be default data by the server.

  • "explicit": a data node that has been explicitly set is reported. This is also the case when a data node is explicitly set to a value that coincide with the default value for the node.

  • "trim": data nodes are not reported if they contain default value even if this was explicitly set to that value.

  • "report-all-tagged": In this mode the server returns all data nodes, just like the "report-all" mode, except a data node that is considered by the server to contain default data will include an attribute to indicate this condition.

A request with the "with-defaults" query parameter without a specified value will be interpreted as "report-all".

If we make a normal GET of the "sys/ntp/server" resource. The default values are not retrieved:

Example 21.15. The "sys/ntp/server" list (no defaults)

GET /running/sys/ntp/server

<collection xmlns:y="http://tail-f.com/ns/rest">
  <server xmlns="http://example.com/router">
    <name>10.2.3.4</name>
    <key>2</key>
  </server>
</collection>


We can get also the default values by setting the query parameter with-defaults=report-all.

Example 21.16. The "sys/ntp/server" list with all defaults

GET /running/sys/ntp/server?with-defaults=report-all

<collection xmlns:y="http://tail-f.com/ns/rest">
  <server xmlns="http://example.com/router">
    <name>10.2.3.4</name>
    <enabled>true</enabled>
    <peer>false</peer>
    <version>4</version>
    <key>2</key>
  </server>
</collection>


21.3.2. Examples using POST, PUT and PATCH

To create a child resource you POST the child resource to its parent (target) resource, and in a successful result you will get returned the URI to the created resource in the Location header.

With PUT you will create or replace a target (data) resource. The message body is expected to contain the content used to create or replace the target resource.

Create a List Instance with POST

POST can be used to create a child resource to the resource specified by the uri. In this example we create a "route" list entry. The URI points to the parent container of the list. The payload in the POST request contain a "route" node that, at least, contain the list keys.

Note

When creating a list entry all keys must be given in the payload.

Example 21.17. Creating a "sys/routes/inet/route" resource

POST /running/sys/routes/inet
Content-Type: application/vnd.yang.data+xml

<route>
  <name>10.20.3.0</name>
  <prefix-length>24</prefix-length>
</route>

The server might respond:

HTTP/1.1 201


When an element is successfully created the HTTP status response is 201. If the element already existed the status response is 409.

Create a Presence Container, within a list, with POST

In this example we create a "multilink" presence container. The URI points to the list instance that contains the presence container, i.e the URI ends with the key(s). The payload in the POST request contain a "multilink" node that contain a value for the leaf node "group".

Note

It is not possible to create a non-presence container with POST, as non-presence containers per definition always exists.

Example 21.18. Creating a "sys/interfaces/serial/ppp0/multilink" resource

POST /running/sys/interfaces/serial/ppp0
Content-Type: application/vnd.yang.data+xml | egrep 
'(HTTP.*Created.*|Locat*)'

<multilink>
  <group>1</group>
</multilink>

The server might respond:

HTTP/1.1 201 Created
Location: 
http://127.0.0.1:8008/api/running/sys/interfaces/ex:serial/ppp0/multil
ink


Create and Replace a List Instance with PUT

PUT can be used to create or replace a resource. No distinction is made in the prerequisites for PUT. If no resource existed it is created, but if it existed it is replaced. In the example, note how the URI ends with the keys.

Example 21.19. Creating a "route" resource using PUT

PUT /running/sys/routes/inet/route/10.30.3.0,24
Content-Type: application/vnd.yang.data+xml

<route>
  <name>10.30.3.0</name>
  <prefix-length>24</prefix-length>
  <next-hop>
    <name>192.168.4.4</name>
    <metric>100</metric>
  </next-hop>
</route>

The server might respond:

HTTP/1.1 201


When an element is successfully created the HTTP status response is 201. We make a GET to verify the "route" list after the PUT of the element.

Example 21.20. The "route" resource after creation

GET /running/sys/routes/inet/route/10.30.3.0,24

<route xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <name>10.30.3.0</name>
  <prefix-length>24</prefix-length>
  <next-hop>
    <name>192.168.4.4</name>
  </next-hop>
</route>


Note

We didn't get the "metric" in the above result from the GET! This has to do with the (non) use of "deep" and "shallow", see: Section 21.2.10, “Query Parameters”

We will now do a replace of the same "route" element.

Example 21.21. Replacing a "route" resource using PUT

PUT /running/sys/routes/inet/route/10.30.3.0,24
Content-Type: application/vnd.yang.data+xml

<route>
  <name>10.30.3.0</name>
  <prefix-length>24</prefix-length>
  <next-hop>
    <name>192.168.3.1</name>
    <metric>100</metric>
  </next-hop>
  <next-hop>
    <name>192.168.4.2</name>
    <metric>200</metric>
  </next-hop>
</route>

The server might respond:

HTTP/1.1 204


We get the 204 response as the resource already existed. We can verify that the element is replaced.

Example 21.22. The "route" resource after replace

GET /running/sys/routes/inet/route/10.30.3.0,24

<route xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <name>10.30.3.0</name>
  <prefix-length>24</prefix-length>
  <next-hop>
    <name>192.168.3.1</name>
  </next-hop>
  <next-hop>
    <name>192.168.4.2</name>
  </next-hop>
</route>


Create and Replace Presence Container with PUT

In this example we create a "multilink" presence container. The uri points to the not yet existing URI for the presence container "multilink". The payload in the PUT request contain a "multilink" node that contain a value for the leaf node 'group'.

Example 21.23. Creating a "sys/interfaces/serial/ppp0/multilink" resource

PUT /running/sys/interfaces/serial/ppp0/multilink
Content-Type: application/vnd.yang.data+xml

<multilink>
  <group>1</group>
</multilink>

The server might respond:

HTTP/1.1 201


Any subsequent request to the same URI will replace the content of "multilink" with the new payload. But the response code will instead be 204, since the resource already exists.

Note

Have in mind that PUT will replace everything with the provided payload. So in the example above, if the container "multilink" contained additional subnodes, other than "group", they would have been deleted as they were not present in the payload.

Replace Non-Presence Container with PUT

In this example we "populate" a non-presence container with subnode data. The URI points to the existing URI for the non-presence container "authentication", since a non-presence container always exist if its parent exist.

Example 21.24. Creating a "sys/interfaces/serial/ppp0/authentication" resource

PUT /running/sys/interfaces/serial/ppp0/authentication
Content-Type: application/vnd.yang.data+xml

<authentication>
  <method>pap</method>
  <list-name>foobar</list-name>
</authentication>

The server might respond:

HTTP/1.1 204


Note

Have in mind that PUT will replace everything with the provided payload. So in the example above, if the container "authentication" contained additional subnodes, they would have been deleted as they were not present in the payload.

Example 21.25. The "authentication" resource after replace

GET /running/sys/interfaces/serial/ppp0/authentication

<authentication xmlns="http://example.com/example-serial" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:ex="http://example.com/example-serial"  
xmlns:r="http://example.com/router">
  <method>pap</method>
  <list-name>foobar</list-name>
</authentication>


Update Existing List Instance with PATCH

To update an existing resource the PATCH method can be used. PATCH will not be allowed on non-existent resources. When we use PATCH the payload should only contain the data that should be modified.

Example 21.26. Updating a "route" resource using PATCH

PATCH /running/sys/routes/inet/route/10.30.3.0,24
Content-Type: application/vnd.yang.data+xml

<route>
  <next-hop>
    <name>192.168.5.1</name>
    <metric>400</metric>
  </next-hop>
</route>

The server might respond:

HTTP/1.1 204


The response status 204 indicated successful update. Here we can see that a new next-hop entry has been added to the route.

Example 21.27. The "route" resource after update

GET /running/sys/routes/inet/route/10.30.3.0,24

<route xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <name>10.30.3.0</name>
  <prefix-length>24</prefix-length>
  <next-hop>
    <name>192.168.3.1</name>
  </next-hop>
  <next-hop>
    <name>192.168.4.2</name>
  </next-hop>
  <next-hop>
    <name>192.168.5.1</name>
  </next-hop>
</route>


Update Presence Container with PATCH

PATCH can not be used to create new resources directly, since it must operate on existing resources. PATCH, in contrast to PUT, only merges the provided payload with the existing configuration, which makes it possible to create child resources within the target resource. In this example we create a "multilink" presence container. The uri points to the existing parent resource for the presence container "multilink".

Example 21.28. Creating a "sys/interfaces/serial/ppp0/multilink" resource

PATCH /running/sys/interfaces/serial/ppp0
Content-Type: application/vnd.yang.data+xml

<serial>
  <multilink>
    <group>1</group>
  </multilink>
</serial>

The server might respond:

HTTP/1.1 204


Update Non-Presence Container with PATCH

In this example we "populate" a non-presence container with subnode data. The URI points to the existing URI for the non-presence container "authentication", since a non-presence container always exist if its parent exist.

Example 21.29. Creating a "sys/interfaces/serial/ppp0/authentication" resource

PATCH /running/sys/interfaces/serial/ppp0/authentication
Content-Type: application/vnd.yang.data+xml

<authentication>
  <method>eap</method>
</authentication>

The server might respond:

HTTP/1.1 204


Note

Have in mind that PATCH will merge the existing configuration with the provided payload. So in the example above, if the container "authentication" contained additional subnodes not present in the payload, they will remain in the resulting configuration. Below the node 'list-name' was not present in the payload, but is still present in the resulting configuration.

Example 21.30. The "authentication" resource after update

GET /running/sys/interfaces/serial/ppp0/authentication

<authentication xmlns="http://example.com/example-serial" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:ex="http://example.com/example-serial"  
xmlns:r="http://example.com/router">
  <method>eap</method>
  <list-name>foobar</list-name>
</authentication>


Insert Data into Resources

For an ordered-by user list, the POST request can include the query parameters insert and resource.

The insert parameter indicated where the new element should be created. Legal values are:

  • first: insert on top of list.

  • last: insert on bottom of list.

  • before: insert before the element indicated by the resource parameter.

  • after: insert after the element indicated by the resource parameter.

The resource parameter contains the uri to an existing element in the list.

So we verify this functionality by first retrieving the "sys/dns/server" list:

Example 21.31. The "sys/dns/server" list before insert

GET /running/sys/dns

<dns xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <server>
    <address>10.2.3.4</address>
  </server>
</dns>


We now insert a new element before the existing element:

Example 21.32. Insert=before in the "sys/dns/server" list

POST 
/running/sys/dns?insert=before&resource=/api/running/sys/dns/server/10
.2.3.4
Content-Type: application/vnd.yang.data+xml

<server>
  <address>10.1.1.2</address>
</server>

The server might respond:

HTTP/1.1 201


We get a 201 status when successful and we verify the result by retreiving the list once again:

Example 21.33. The "sys/dns/server" list after insert

GET /running/sys/dns

<dns xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <server>
    <address>10.1.1.2</address>
  </server>
  <server>
    <address>10.2.3.4</address>
  </server>
</dns>


21.3.3. Invoke Operations

To invoke an operation, use the POST method. The message body (if any) is processed as the operation input parameters.

Example 21.34. An "archive-log" action request example

The following yang model snippet shows the definition of the action archive-log:

  grouping syslog {
    list server {
      key "name";
      leaf name {
        type inet:host;
      }
      leaf enabled {
        type boolean;
      }
      list selector {
        key "name";
        leaf name {
          type int32;
        }
        leaf negate {
          type boolean;
        }
        leaf comparison {
          type enumeration {
            enum "same-or-higher";
            enum "same";
          }
        }
        leaf level {
          type syslogLevel;
        }
        leaf-list facility {
          type syslogFacility;
          min-elements 1;
          max-elements "8";
        }
      }
      leaf administrator {
        type string;
        tailf:hidden maint;
      }
      tailf:action archive-log {
        tailf:exec "./scripts/archive-log";
        input {
          leaf archive-path {
            type string;
          }
          leaf compress {
            type boolean;
          }
        }
        output {
          leaf result {
            type string;
          }
        }
      }
    }
  }

The action is invoked using the following URI. Note, the _operations tag that indicates the action invocation:

POST /running/sys/syslog/server/10.3.4.5/
operations/archive-log
Content-Type: application/vnd.yang.data+xml

<input>
  <archive-path>/tmp</archive-path>
  <compress>false</compress>
</input>

The server might respond:

<output xmlns='http://example.com/router'>
  <result>success</result>
</output>


If the POST method succeeds, a "200 OK" Status-Line is returned if there is a response message body, and a "204 No Content" Status-Line is returned if there is no response message body.

If the user is not authorized to invoke the target operation, an error response containing a "403 Forbidden" Status-Line is returned to the client.

21.3.4. Delete Data Resources

A delete removes all data in the subtree under a resource. In this example we remove the complete "sys/interfaces/ex:serial" list.

Example 21.35. delete the "sys/interfaces/ex:serial" list

DELETE /running/sys/interfaces/ex:serial

The server might respond:

HTTP/1.1 204


The response status 204 indicates success. If we retrieve the "sys/interfaces" resource we can verify that the "ex:serial" list is removed.

Example 21.36. The "sys/interfaces" resource after delete

GET /running/sys/interfaces

<interfaces xmlns="http://example.com/router" 
xmlns:y="http://tail-f.com/ns/rest"  
xmlns:r="http://example.com/router">
  <interface>
    <name>eth0</name>
  </interface>
</interfaces>


Whenever a change is made and a rollback resource is created we can set a label and a comment for that change. If we used that together with the DELETE above, we could have used this command instead.

Example 21.37. delete the "sys/interfaces/ex:serial" list with rollback label and comment


DELETE /running/sys/interfaces/ex:serial?rollback-comment=remove%20subtree&ro
llback-label=delete


21.4. Resources

The RESTCONF protocol operates on a hierarchy of resources, starting with the top-level API resource itself. Each resource represents a manageable component within the device.

A resource can be considered a collection of conceptual data and the set of allowed methods on that data. It can contain child nodes that are nested resources. The child resource types and methods allowed on them are data-model specific.

A resource has its own media type identifier, represented by the Content-Type header in the HTTP response message. A resource can contain zero or more nested resources. A resource can be created and deleted independently of its parent resource, as long as the parent resource exists.

The RESTCONF resources are accessed via a set of URIs defined in this document. The set of YANG modules supported by the server will determine the additional data model specific operations, top-level data node resources, and notification event messages supported by the server.

The resources used in the RESTCONF protocol are identified by the "path" component in the request URI, see Example 21.2, “Request URI structure”. Each operation is performed on a target resource.

21.4.1. Representation

The RESTCONF protocol defines some application specific media types to identify each of the available resource types. The following resource types are defined in the REST API:

Table 21.3. Resources and their Media Types

ResourceMedia Type
APIapplication/vnd.yang.api
Datastoreapplication/vnd.yang.datastore
Dataapplication/vnd.yang.data
Operationapplication/vnd.yang.operation

Note

The REST API does not support all of the datastores defined in RESTCONF, neither does it use the same media types.
THIS DIFFERS FROM RESTCONF!

XML representation

A resource is represented in XML as an XML element, with an XML attribute "y:self" that contains the URI for the resource. In the XML representation, every resource has an XML attribute:

y:self="..."
          

Leafs are properties of the resource. They are encoded in XML as elements.

XML namespaces must be used whenever there are multiple sibling nodes with the same local name. This only happens if a YANG module augments a node with the same name as another node in the same container or list. XML namespaces MAY always be used, even if there are no risk of a conflict.

JSON representation

In the JSON representation, this URI is encoded as:

"_self": "..."
          

In the representation of a list resource, the keys are always present, and encoded first.

JSON doesn't have anything similar to XML namespaces. However, we have adopted the notion defined in the Internet Draft: "Modeling JSON Text with YANG", where a <yang-module-name>:<tag> tag name is used in the JSON data to indicate the namespace. Note that it is only when the namespace changes that this notion is used.

Example 21.38. Namespaces in JSON

   ...
    "foo": [
      {
        "_self": "/api/operational/x/foo/1",
        "id": 1,
        // Note: the 'card' container exist in a different namespace
        //       compared to its parent 'foo' list element. The
        //       'a' is the Yang module name where 'card' is defined
        "a:card": {
          "_self": "/api/operational/x/foo/1/a:card",
          "id": 1
        }
   ...
        

21.4.2. API Resource (/api)

The top-level resource has the media type "application/vnd.yang.api+xml" or "application/vnd.yang.api+json". It is accessible through the well-known URI "/api".

This resource has the following fields:

Table 21.4. Fields of the /api resource

FieldDescription
versionThe version of the REST api.
configLink to the "config" resource.
runningLink to the "running" resource.
startupLink to the "startup" resource.
candidateLink to the "candidate" resource.
operationalLink to the "operational" resource.
operationsContainer for available operations (i.e: YANG rpc statements).
rollbacksContainer for available rollback files.

In XML, this resource is represented as an XML document with the document root element "y:api", underneath which all the resource's fields are represented as subelements.

In JSON, this resource is represented as a JSON object.

Supported HTTP methods: GET, HEAD, OPTIONS.

The version Field

The "version" field is a string identifying the version of the REST api.

The config Resource

The "config" resource represents a unified configuration datastore, used to simplify resource management for the client. The underlying NETCONF datastores are used to implement the unified datastore, but the clients do not have to care about which underlying datastore to used.

The server hides all NETCONF datastore details for edit operations, such as the :candidate and :startup capabilities. When a client writes to this resource, the server performs the edits in the datastores used; if the candidate is enabled, the changes are written to the candidate, and then the candidate is committed; if the startup is enabled, the changes are written to running and running is copied to startup.

The media type of this resource is either "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

Note

This resource resembles the RESTCONF "Datastore Resource" except that it does not contain operational data. RESTCONF differs from the REST API as it does not have separate NETCONF datastores for "running", "candidate" and "startup".

The running Resource

The "running" resource represents the running configuration datastore, and is present on all devices. Not all devices support direct modification to this resource.

The media type of this resource is either "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

The startup Resource

The "startup" resource represents the startup configuration datastore. Not all devices support this resource.

The media type of this resource is "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

The candidate Resource

The "candidate" resource represents the candidate configuration datastore. Not all devices support this resource.

The media type of this resource is "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

The operational Resource

The "operational" read-only resource represents the state data as well as the config data on the device, and is present on all devices. Note that actions defined as config false also will show up in this resource.

The media type of this resource is "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

Note

This resource resembles the RESTCONF "Datastore Resource" except that it is read-only.

The transaction Resource

The "transaction" resource represents a transaction datastore created by the JSON-RPC API. This allows REST API requests that read or write towards an existing transaction, without committing the transaction (this is left up to other entities e.g. the JSON-RPC API).

The media type of this resource is either "application/vnd.yang.datastore+xml" or "application/vnd.yang.datastore+json".

The operations Container

The "operations" container contains all operations defined with the "rpc" statement in the YANG models supported on the device.

The rollbacks Container

The "rollbacks" container contains all available rollback files to be used to rollback the configuration state to an earlier incarnation.

The logout Resource

The "logout" read-only resource is a meta-resource that always replies with 401 Unauthorized in order to aid scenarios where the REST API credentials are being cached by the HTTP client (e.g. a browser). Calling this resource will prompt for new credentials on subsequent requests to any other resource on the same realm.

Examples

In order to retrieve the representation of this resource, a client can send:

Note the use of the 'verbose' query parameter, see Section 21.2.10, “Query Parameters”.

Example 21.39. GET the /api resource

GET /api?verbose
Application:vnd.yang.api+xml

The server might respond:

HTTP/1.1 200 OK
Server: 
Date: Wed, 12 Aug 2015 11:38:23 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Content-Length: 288
Content-Type: application/vnd.yang.api+xml
Vary: Accept-Encoding
Pragma: no-cache

<api xmlns="http://tail-f.com/ns/rest" 
xmlns:y="http://tail-f.com/ns/rest" y:self="/api">
  <version>0.5</version>
  <config y:self="/api/config"/>
  <running y:self="/api/running"/>
  <operational y:self="/api/operational"/>
  <operations/>
  <rollbacks y:self="/api/rollbacks"/>
</api>


21.4.3. Datastore Resource (/api/<datastore>)

The media types "application/vnd.yang.datastore+xml" and "application/vnd.yang.datastore+json" represent a complete datastore. All three configuration datastores defined by NETCONF are available, as the resources:

  • running

  • candidate

  • startup

  • operational (read-only)

Note

The state data defined by NETCONF is available as a read-only resource "operational".
THIS DIFFERS FROM RESTCONF!

A config datastore (i.e one of "running", "candidate","startup") resource has the following fields:

Table 21.5. Fields of the /api/<datastore> resource

FieldDescription
operationsContainer for available built-in operations.
y:operationsContainer for available user defined actions.
<all top-level data models nodes>Top-level nodes from the YANG models.

The "operational" datastore contains both operational and config data; as well as the containers as shown in the table: Table 21.5, “Fields of the /api/<datastore> resource”.

The REST API has a number of built-in operations that may be applicable for a particular datastore, and if they are applicable they are included in the operations container as described below:

Table 21.6. Built in operations

FieldDescription
commitLink to the "commit" resource.
copy-running-to-startupLink to the "copy-running-to-startup" resource.
discard-changesLink to the "discard-changes" resource.
lockLink to the "lock" resource.
validateLink to the "validate" resource.

In XML, the /api/<datastore> resource is represented as an XML document with the document root element "y:data", underneath which all the resource's fields are represented as subelements.

In JSON, this resource is represented as a JSON object.

The operations are described below, and all represented by the media type "application/vnd.yang.operation", see Section 21.3.3, “Invoke Operations”.

The lock Resource

In order to access a datastore through a lock, the client needs to POST to the "lock" resource. If the server is able to lock the datastore, the POST request succeeds with the status code "201 Created", and the "Location" HTTP header contains the URI to a newly created resource representing the locked datastore. To unlock the datastore, the client deletes the newly created resource using the HTTP method DELETE.

The "config" resource cannot be locked.

In the representation of a locked datastore, the "lock" operation is not available.

In order to facilitate recovery from failing clients with outstanding locks, the REST server deletes the resource representing the lock after some time of inactivity.

The media type of this resource is "application/vnd.yang.operation+xml".

The commit Resource

In the representation of the candidate datastore, the "commit" operation is present, and can be POSTed to by the client to commit candidate to running, as described in section 8.3 in RFC 6241.

The media type of this resource is "application/vnd.yang.operation".

The copy-running-to-startup Resource

In the representation of the running datastore, the "copy-running-to-startup" operation is present, if the server also supports the startup datastore, and can be POSTed to by the client to copy the contents of running to startup, as described in section 8.7 in RFC 6241.

The media type of this resource is "application/vnd.yang.operation".

The discard-changes Resource

In the representation of the candidate datastore, the "discard-changes" operation is present, and can be POSTed to by the client to revert the candidate to the current running configuration, as described in section 8.3.4.2 in RFC 6241.

The media type of this resource is "application/vnd.yang.operation".

The validate Resource

In the representation of the candidate datastore, the "validate" operation is present, and can be POSTed to by the client to validate the contents of the candidate, as described in section 8.6.4.1 in RFC 6241.

The media type of this resource is "application/vnd.yang.operation".

Examples

The examples in this section could instead have been performed using JSON specific mime types such as "application/vnd.yang.api+json", "application/vnd.yang.datastore+json" and "application/vnd.yang.data+json".

To retrieve a representation of the running datastore in XML format, a client can send:

(Note the use of the 'verbose' query parameter, see Section 21.2.10, “Query Parameters”)

Example 21.40. GET the /api/running resource

GET /api/running?verbose
Application:vnd.yang.api+xml

The server might respond:

HTTP/1.1 200 OK
Server: 
Date: Wed, 12 Aug 2015 11:38:23 GMT
Last-Modified: Wed, 12 Aug 2015 11:38:23 GMT
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Etag: 1439-379503-31029
Content-Type: application/vnd.yang.datastore+xml
Transfer-Encoding: chunked
Pragma: no-cache

<data xmlns:y="http://tail-f.com/ns/rest" y:self="/api/running">
  <sys xmlns="http://example.com/router" y:self="/api/running/sys">
 ...
  </sys>
 ...
  <operations>
    <lock y:self="/api/running/_lock">/api/running/_lock</lock>
    <rollback 
y:self="/api/running/_rollback">/api/running/_rollback</rollback>
  </operations>
</data>

To copy running to startup, a client can send:

            
    POST /api/running/_copy-running-to-startup
    Host: example.com
    Accept: application/vnd.yang.operations+xml
            


Note that any action defined as "config false" will only show up under the /api/operational datastore.

Example 21.41. Action in /api/operational

    ...
    <blaha xmlns="http://example.com/ns/ktm"
           y:self="/api/operational/blaha">
      <y:operations y:path="/blaha">
        <bar y:self="/api/operational/blaha/_operations/bar"/>
        <!-- NOTE: this action is defined as 'config false'
             and hence, shows up under the 'operational'
             datastore  -->
      </y:operations>
    </blaha>
    ...
          

21.4.4. Data Resource (/api/<datastore>/<data>)

By default, all top-level objects, list entries, and containers are resources. Any resource derived from a YANG module is represented with the media type "application/vnd.yang.data+xml".

When such a resource is retrieved, a "path" property is included in its representation (a "y:path" attribute in XML). The value of this property is the resource's instance-identifier.

Supported HTTP methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT.

Note that resources representing non-presence containers cannot be deleted, and thus they do not support the DELETE method.

Refer to Section 21.3, “Resource Examples” for examples of how to operate on "application/vnd.yang.data+xml".

21.4.5. Operations and Actions

YANG-defined operations, defined with the YANG statements "rpc" or "tailf:action", and the built-in operations, are represented with the media type "application/vnd.yang.operation".

Resources of this type accept only the method "POST".

In XML, such resources are encoded as subelements to the XML element "y:operations". In JSON, they are encoded under "_operations".

If an operation does not require any parameters, the POST message has no body. If the client wishes to send parameters to the operation, they are encoded as an XML document with the document element "input".

If an operation does not produce any output, the HTTP response code is 204 (No Content). If it produces output, the HTTP response code is 200 (OK), and the output of the operation is encoded as an XML document with the document element "output".

Supported HTTP methods: POST

21.4.6. The Rollback Resource

The rollback resource can be accessed from the top level "/api/rollbacks" resource as described above, and a rollback file can be applied to any database.

Listing and Inspecting Rollback Files

In order to list available a rollback files, a client can send:

Example 21.42. GET rollback files information

GET /api/rollbacks
Application:vnd.yang.api+xml

The server might respond:

<rollbacks xmlns="http://tail-f.com/ns/rest" 
xmlns:y="http://tail-f.com/ns/rest">
  <file>
    <name>0</name>
    <creator>admin</creator>
    <date>2015-08-12 13:38:23</date>
    <via>rest</via>
    <label></label>
    <comment></comment>
  </file>
  <file>
    <name>1</name>
    <creator>admin</creator>
    <date>2015-08-12 13:38:22</date>
    <via>rest</via>
    <label></label>
    <comment></comment>
  </file>
</rollbacks>


Note how each rollback file is represented as separate resources, e.g. "/api/rollbacks/0". We can also see how the 'rollback-label' and 'rollback-comment' is used in "/api/rollbacks/0/label" and "/api/rollbacks/0/comment". These resources can be inspected individually and a client can send:

Example 21.43. GET rollback file content

GET /api/rollbacks/0
Application:vnd.yang.api+xml

The server might respond:

# Created by: admin
# Date: 2015-08-12 13:38:23
# Via: rest
# Type: delta
# Label: 
# Comment: 
# No: 10016

sys {
    interfaces {
        serial ppp0 {
            ppp {
                accounting acme;
            }
            authentication {
                method    eap;
                list-name foobar;
            }
            authorization admin;
            multilink {
                group 1;
            }
        }
    }
 }


The payload is in the same curly bracket rollback format as used in the NETCONF, CLI and Web UI agents.

Applying Rollback Files

To apply a rollback file to a database use the appropriate "rollback" resource/operation in the datastore of your choice:

Example 21.44. Find and use the rollback operation resource

GET /api/running
Application:vnd.yang.datastore+xml

The server might respond:

<data xmlns:y="http://tail-f.com/ns/rest">
  <sys xmlns="http://example.com/router">
 ...
  </sys>
 ...
  <operations>
    <lock>/api/running/_lock</lock>
    <rollback>/api/running/_rollback</rollback>
  </operations>
</data>

Note the "/api/running/_rollback" resource operation.

POST an appropriate rollback file name to the "/api/running/_rollback" resource operation to apply it:

POST /api/running/_rollback
Content-Type: application/vnd.yang.data+xml
<file>0</file>

The server might respond:

HTTP/1.1 204


21.5. Configuration Meta-Data

As described in Chapter 8, Configuration Meta-Data it is possible to associate meta-data with the configuration data. For REST, resources such as containers, lists as well as leafs and leaf-lists can have such meta-data. For XML, this meta-data is represented as attributes, attached to the XML element in question. For JSON, there does not exist a natural way to represent this info. Hence we have introduced a special notation, see the example below.

Example 21.45. XML representation of meta-data

<x xmlns="urn:x"
   y:self="/api/running/x"
   xmlns:y="http://tail-f.com/ns/rest"
   xmlns:x="urn:x"
   y:path="/x:x">
  <id tags=" important ethernet " annotation="hello world">42</id>
  <person y:self="/api/running/x/person" annotation="This is a person">
    <name>Bill</name>
    <person annotation="This is another person">grandma</person>
  </person>
</x>

Example 21.46. JSON representation of meta-data

{
  "x": {
    "_self": "/api/running/x",
    "_path": "/x:x",
    "id": 42,
    "@id": {"tags": ["important","ethernet"],"annotation": "hello world"},
    "person": {
      "_self": "/api/running/x/person",
      // NB: the below refers to the parent object
      "@@person": {"annotation": "This is a person"},
      "name": "Bill",
      "person": "grandma",
      // NB: the below refers to the sibling object
      "@person": {"annotation": "This is another person"}
    }
  }
}

For JSON, note how we represent the meta data for a certain object "x" by another object constructed of the object name prefixed with either one or two "@" signs. The meta-data object "@x" refers to the sibling object "x" and the "@@x" object refers to the parent object.

Note

THIS DIFFERS FROM RESTCONF!

21.6. Request/Response headers

There are some optional request and response headers that are of interest since some functionality is obtained by their use. We here focus on the Etag and Last-Modified response headers, and the request headers that are correlated to these (If-Match, If-None-Match, If-Modified-Since and If-Unmodified-since).

21.6.1. Response headers

  • Etag: This header (entity-tag) is a string representing the latest transaction id in the database. This header is only available for the "running" resource or equivalent.

  • Last-Modified: This header contains the timestamp for the last change in the database. This header is only available for the "running" resource or equivalent. Also, this header is only available if rollback files are enabled.

21.6.2. Request headers

  • If-None-Match: This header evaluates to true if the supplied value does not match the latest Etag value. If evaluated to false an error response with status 304 (Not Modified) will be sent with no body. The usage of this is for instance for a GET operation to get information if the data has changed since last retrieval. This header carry only meaning if the Etag response header has previously been acquired.

  • If-Modified-Since: This request-header field is used with a HTTP method to make it conditional, i.e if the requested variant has not been modified since the time specified in this field, an entity will not be returned from the server; instead, a 304 (Not Modified) response will be returned without any message-body.

    Usage of this is for instance for a GET operation to get information if (and only if) the data has changed since last retrieval. Thus, this header should use the value of a Last-Modified response header that has previously been acquired.

  • If-Match: This header evaluates to true if the supplied value matches the latest Etag value. If evaluated to false an error response with status 412 (Precondition Failed) will be sent with no body.

    The usage of this can be to control if a POST operation should be executed or not (i.e. do not execute if the database has changed). This header carry only meaning if the Etag response header has previously been acquired.

  • If-Unmodified-Since: This header evaluates to true if the supplied value is later or equal to the last acquired Last-Modified timestamp. If evaluated to false an error response with status 412 (Precondition Failed) will be sent with no body.

    The usage of this can be to control if a POST operation should be executed or not (i.e. do not execute if the database has changed). This header carry only meaning if the Last-Modified response header has previously been acquired.

21.7. Special characters

When setting or retrieving data it is sometimes necessary to represent special characters in the payload. In the REST api the payload can have both XML and JSON format. The special characters handled in the REST api are:

  • "new line": representing a line feed (decimal ascii value 10)

  • "carriage return": representing carriage return (decimal ascii value 13)

  • "horizontal tab": representing a tabulation (decimal ascii value 9)

The ambition in the REST api is that special characters should be handled in the same way as they are in the CLI. Since the CLI is capable to present configuration data both as strings and XML the CLI representation can be used as template for both the XML and JSON format.

21.7.1. XML representation of special characters

When in the XML case the special characters uses the representation &#xH; where H is the ascii hex value or &#DD; where DD is the ascii decimal value. Since "&" is the quoting character this is also treated as a special character, and so is "<" since this is the separator character indicating the beginning of a tag value. The following is the list of XML special characters:

  • "new line": represented by &#xA; or &#10;

  • "carriage return": represented by &#xD; or &#13;

  • "horizontal tab": represented by &#x9; or &#09;

  • "&": represented by &amp;

  • "<": represented by &lt;

An example XML fragment is

 
<foo>123\n456\\n &lt;&amp;></foo>

 which is interpreted as:

123
456\n <&>

      

21.7.2. JSON representation of special characters

In the JSON formatted string case the quote character "\" and string separator characters are used "\"" which also becomes special characters in the string case. The complete list of JSON special characters become:

  • "new line": represented by \n

  • "carriage return": represented by \r

  • "horizontal tab": represented by \t

  • "\": represented by \ or \\

  • """: represented by \"

The \ quote character is used in the following way: A single \ in a string that is not directly followed by characters n,r or t are unaltered (as a \ character). Two \\ are interpreted as \ (the escaped \). This implies that both \\\ and \\\\ are are interpreted as \\ and so forth.

An example JSON string is

 
"123\n456\\n \\\"

 which is interpreted as:

123
456\n \\

      

21.8. Error Responses

Error responses are formatted either in XML and JSON depending on the preferred MIME type in the request.

In your installed release you should be able to find a Yang file named tailf-rest-error.yang that defines the structure of these error replies. An easy way to find the file run, from the top directory of your installation:

      find . -name tailf-rest-error.yang
      

Let's start by looking at an example of how a structured error reply can look like.

Example 21.47. Example of a XML formatted error message

 curl -i -X PUT "localhost:8008/api/running/hosts"
-H "Content-Type: application/vnd.yang.data+xml" ...
HTTP/1.1 500 Internal Server Error
Server: ConfD/5.3.0
Cache-control: private, no-cache, must-revalidate, proxy-revalidate
Date: Thu, 10 Jul 2014 07:59:04 GMT
Content-Length: 259
Content-Type: text/xml


<errors xmlns="http://tail-f.com/ns/tailf-rest-error">
  <error>
    <error-tag>operation-failed</error-tag>
    <error-urlpath>/api/running/hosts</error-urlpath>
    <error-message>internal error</error-message>
  </error>
</errors>
      

Example 21.48. Example of a JSON formatted error message

 curl -i -X POST "localhost:8008/api/running/hosts2" \
-H "Content-Type: application/vnd.yang.data+json" ...
HTTP/1.1 400 Bad Request
Server: ConfD/5.3.0
Cache-control: private, no-cache, must-revalidate, proxy-revalidate
Date: Thu, 10 Jul 2014 09:11:13 GMT
Content-Length: 199
Content-Type: text/json

{"errors":
  {"error":
     [{
       "error-message": "unexpected trailing data: hosts",
       "error-urlpath": "/api/running/hosts",
       "error-tag": "malformed-message"
       }
      ]
  }
}
      

The YANG model for the error messages is taken from the NETCONF specification. However, note that the REST API currently only sets three values when reporting an error:

  • "error-tag": An error classification tag.

  • "error-urlpath": The URI used by the error generating request.

  • "error-message": A descriptive error message.

The error-tag element has a number of predefined values and there is also a preferred HTTP status code connected to each error-tag. These are:

  • "in-use": HTTP Status: 409 Conflict

  • "invalid-value": HTTP Status: 400 Bad Request

  • "too-big": HTTP Status: 413 Request Entity Too Large

  • "missing-attribute": HTTP Status: 400 Bad Request

  • "bad-attribute": HTTP Status: 400 Bad Request

  • "unknown-attribute": HTTP Status: 400 Bad Request

  • "bad-element": HTTP Status: 400 Bad Request

  • "unknown-element": HTTP Status: 400 Bad Request

  • "unknown-namespace": HTTP Status: 400 Bad Request

  • "access-denied": HTTP Status: 403 Forbidden

  • "lock-denied": HTTP Status: 409 Conflict

  • "resource-denied": HTTP Status: 409 Conflict

  • "rollback-failed": HTTP Status: 500 Internal Server Error

  • "data-exists": HTTP Status: 409 Conflict

  • "data-missing": HTTP Status: 409 Conflict

  • "operation-not-supported": HTTP Status: 501 Not Implemented

  • "operation-failed": HTTP Status: 500 Internal Server Error

  • "partial-operation": HTTP Status: 500 Internal Server Error

  • "malformed-message": HTTP Status: 400 Bad Request

21.8.1. User extended error messages

For data providers, hooks, transforms etc there exist a possibility to add extensions to error messages and change error codes before sending errors back to the server from the callbacks (see: Section 28.14, “Error Message Customization”). These codes and error messages will also be visible over the REST interface. More on how to use these options can be found in the confd_lib_dp(3) man page, e.g under the confd_db_seterr_extended function, or in the Javadoc for the com.tailf.dp.DpCallbackExtendedException class.

Using the above mechanism to change the errorcode for an emitted error, will have effect on the REST HTTP response statuses. The following table show their relationship:

Table 21.7. Error code vs HTTP Status

Error CodeHTTP Status
CONFD_ERRCODE_IN_USE409 Conflict
CONFD_ERRCODE_RESOURCE_DENIED409 Conflict
CONFD_ERRCODE_INCONSISTENT_VALUE400 Bad Request
CONFD_ERRCODE_ACCESS_DENIED403 Forbidden
CONFD_ERRCODE_APPLICATION400 Bad Request
CONFD_ERRCODE_APPLICATION_INTERNAL500 Internal Server Error
CONFD_ERRCODE_DATA_MISSING409 Conflict
CONFD_ERRCODE_INTERRUPT500 Internal Server Error

21.9. The Query API

The Query API consists of a number of Requests and Replies which are sent as payload via the (REST) HTTP connection.

In your installed release you should be able to find two YANG files named tailf-rest-query.yang and tailf-common-query.yang that defines the structure of these Requests / Replies. An easy way to find the files is to run the following command from the top directory of your installation:

      find . -name tailf-rest-query.yang
      

The API consists of the following Requests:

  • "start-query": Start a query and return a query handle.

  • "fetch-query-result": Use a query handle to repeatedly fetch chunks of the result.

  • "reset-query": (Re)set where the next fetched result will begin from.

  • "stop-query": Stop (and close) the query.

The API consists of the following Replies:

  • "start-query-result": Reply to the start-query request

  • "query-result": Reply to the fetch-query-result request

In the following examples, we'll use this data model:

container x {
  list host {
    key number;
    leaf number {
      type int32;
    }
    leaf enabled {
      type boolean;
    }
    leaf name {
      type string;
    }
    leaf address {
      type inet:ip-address;
    }
  }
}

The actual format of the payload should be represented either in XML or JSON. For XML it could look like this:

    <start-query xmlns="http://tail-f.com/ns/tailf-rest-query">
      <foreach>
        /x/host[enabled = 'true']
      </foreach>
      <select>
        <label>Host name</label>
        <expression>name</expression>
        <result-type>string</result-type>
      </select>
      <select>
        <expression>address</expression>
        <result-type>string</result-type>
      </select>
      <sort-by>name</sort-by>
      <limit>100</limit>
      <offset>1</offset>
    </start-query>
    

An informal interpretation of this query is:

For each '/x/host' where 'enabled' is true, select its 'name', and 'address', and return the result sorted by 'name', in chunks of 100 results at the time.

Let us discuss the various pieces of this request. To start with, when using XML, we need to specify the name space as shown:

    <start-query xmlns="http://tail-f.com/ns/tailf-rest-query">
    

The actual XPath query to run is specified by the 'foreach' element. In the example below will search for all '/x/host' nodes that has the 'enabled' node set to 'true':

      <foreach>
        /x/host[enabled = 'true']
      </foreach>
      

Now we need to define what we want to have returned from the node set by using one or more 'select' sections. What to actually return is defined by the XPath 'expression'.

Choose how the result should be represented. Basically, it can be the actual value or the path leading to the value. This is specified per select chunk The possible result-types are: 'string' , 'path' , 'leaf-value' and 'inline'.

The difference between 'string' and 'leaf-value' is somewhat subtle. In the case of 'string' the result will be processed by the XPath function: string() (which if the result is a node-set will concatenate all the values). The 'leaf-value' will return the value of the first node in the result. As long as the result is a leaf node, 'string' and 'leaf-value' will return the same result. In the example above, the 'string' is used as shown below. At least one result-type must be specified.

The result-type 'inline' makes it possible to return the full sub-tree of data, either in XML or in JSON format. The data will be enclosed with a tag: 'data'.

It is possible to specify an optional 'label' for a convenient way of labeling the returned data:

    <select>
      <label>Host name</label>
      <expression>name</expression>
      <result-type>string</result-type>
    </select>
    <select>
      <expression>address</expression>
      <result-type>string</result-type>
    </select>
      

The returned result can be sorted. This is expressed as XPath expressions, which in most cases are very simple and refers to the found node set. In this example we sort the result by the content of the 'name' node:

      <sort-by>name</sort-by>
      

To limit the max amount of results in each chunk that 'fetch-query-result' will return we can set the 'limit' element. The default is to get all results in one chunk.

    <limit>100</limit>
      

With the 'offset' element we can specify at which node we should start to receive the result. The default is 1, i.e., the first node in the resulting node-set.

    <offset>1</offset>
      

This request, expressed in JSON, would look like this:

    {
     "start-query": {
       "foreach": "/x/host[enabled = 'true']",
       "select": [
         {
           "label": "Host name",
           "expression": "name",
           "result-type": ["string"]
         },
         {
           "expression": "address",
           "result-type": ["string"]
         }
       ],
       "sort-by": ["name"],
       "limit": 100,
       "offset": 1
     }
    }
      

Now, if we continue by putting this XML example in a file test.xml we can send a request, using the command 'curl', like this:

    curl -i 'http://admin:admin@localhost:8008/api/query' \
         -X POST -T test.xml \
         -H "Content-Type: application/vnd.yang.data+xml"
      

The important parts of the above is the '/api/query' in the URI and that we send a HTTP 'POST' with the correct 'Content-Type'.

The result would look something like this:

    <start-query-result>
      <query-handle>12345</query-handle>
    </start-query-result>
      

The query handle (in this example '12345') must be used in all subsequent calls. To retrieve the result, we can now send:

    <fetch-query-result xmlns="http://tail-f.com/ns/tailf-rest-query">
      <query-handle>12345</query-handle>
    </fetch-query-result>
      

Which will result in something like the following:

    <query-result xmlns="http://tail-f.com/ns/tailf-rest-query">
      <result>
        <select>
          <label>Host name</label>
          <value>One</value>
        </select>
        <select>
          <value>10.0.0.1</value>
        </select>
      </result>
      <result>
        <select>
          <label>Host name</label>
          <value>Three</value>
        </select>
        <select>
          <value>10.0.0.3</value>
        </select>
      </result>
    </query-result>
      

If we try to get more data with the 'fetch-query-result' we might get more 'result' entries in return until no more data exists and we get an empty query result back:

    <query-result xmlns="http://tail-f.com/ns/tailf-rest-query">
    </query-result>
      

If we want to go back in the "stream" of received data chunks and have them repeated, we can do that with the 'reset-query' request. In the example below we ask to get results from the 42:nd result entry:

    <reset-query xmlns=\"http://tail-f.com/ns/tailf-rest-query\">
      <query-handle>12345</query-handle>
      <offset>42</offset>
    </reset-query>
      

Finally, when we are done we stop the query:

    <stop-query xmlns="http://tail-f.com/ns/tailf-rest-query">
      <query-handle>12345</query-handle>
    </stop-query>
      

21.10. Custom Response HTTP Headers

The REST server can be configured to reply with particular HTTP headers in the HTTP response. For example, to support Cross-Origin Resource Sharing (CORS, http://www.w3.org/TR/cors/) there is a need to add a couple of headers to the HTTP Response.

We add the extra configuration parameter in confd.conf

Example 21.49. ConfD configuration for REST

    <rest>
      <enabled>true</enabled>
      <customHeaders>
        <header>
          <name>Access-Control-Allow-Origin</name>
          <value>*</value>
        </header>
      </customHeaders>
    </rest>
        


Example 21.50. 

Send a request with Origin header:

OPTIONS .bob.com

A result can then look like

          
HTTP/1.1 200 OK
Server: 
Allow: GET, HEAD
Cache-Control: private, no-cache, must-revalidate, proxy-revalidate
Content-Length: 0
Content-Type: text/html
Access-Control-Allow-Origin: http://api.bob.com
Pragma: no-cache


        


21.11. HTTP Status Codes

The REST server will return standard HTTP response codes, as described in the list below:

200 OK

The request was successfully completed, and a response body is returned containing a representation of the resource.

201 Created

A resource was created, and the new resource URI is returned in the "Location" header.

204 No Content

The request was successfully completed, but no response body is returned.

400 Bad Request

The request could not be processed because it contains missing or invalid information (such as validation error on an input field, a missing required value, and so on).

401 Unauthorized

The request requires user authentication. The response includes a "WWW-Authenticate" header field for basic authentication.

403 Forbidden

Access to the resource was denied by the server, due to authorization rules.

404 Not Found

The requested resource does not exist.

405 Method Not Allowed

The HTTP method specified in the request (DELETE, GET, HEAD, PATCH, POST, PUT) is not supported for this resource.

406 Not Acceptable

The resource identified by this request is not capable of generating the requested representation, specified in the "Accept" header or in the "format" query parameter.

409 Conflict

This code is used if a request tries to create a resource that already exists.

415 Unsupported Media Type

The format of the request is not supported.

500 Internal Error

The server encountered an unexpected condition which prevented it from fulfilling the request.

501 Not Implemented

The server does not (currently) support the functionality required to fulfill the request.

503 Unavailable

The server is currently unable to handle the request due to the resource being used by someone else, or the server is temporarily overloaded.