WHAT IS AN API REQUEST?

REST API request is an HTTP method. It lets you send a request from an endpoint to your server (controller). You can use it if you want to retrieve some information from the server or connected device, or if you want to do some changes (for example to datastore, topology, device, etc..). The most common HTTP methods are GET, PUT, POST or DELETE.

  • GET – used to read data from a server or connected device, when GET is successful you will get 200 OK response
  • PUT – used to create/update data in a server or connected device, when PUT is successful you should get either 201 Created(if something new was created) or 204 No content(if something was just modified) response
  • POST – used to send data to a server or connected device ( file upload, customer information, calling RPC, etc… ), when POST is successful you will get 200 OK response
  • DELETE – used to remove (delete) data from a server or connected device, when DELETE is successful you will get 204 No content response

PARTS OF REQUESTS

Default settings for the http://<ip_address>:<port>/ are http://localhost:8888/, but for the purpose of this example, we will use <ip_address>:<port> where ip_address and port are dependent on your running configuration.

The four parts are:

  • IP Adress & Port Nr.
  • Adding RESTCONF/Identifier
  • RESTCONF API Path
  • Controller Module Path

1. Part of every RESTCONF API request is an IP address and port number, on which our requested server is running:

  • http://<ip_address>:<port>/ip_address, in this case, is IP address of the server we are sending a request to. port is the port number on which the RESTCONF plugin is running.

2. Add RESTCONF/identifier, because we are making requests to it (as described in the RFC 8040):

  • restconf/ – is the identifier that we are making a request to via the RESTCONF API

3. Path to either data or operations available through RESTCONF API

  • data (restconf/data/) – this leads to all data that can be requested, updated or deleted(if those are config data) from the controller datastore
  • operations (restconf/operations) – this contains all operations(called RPCs – Remote Procedure Calls) that can be invoked by the user via the RESTCONF interface

4. A path into the desired module in the controller:

  • unified path – restconf/data/module_name:container/ – where module_name is the name of the YANG module and container is the container in the particular YANG module
  • For example, we can make a request – restconf/data/network-topology:network-topology/ – which leads to a subtree of data store that is specified as network-topology. It basically returns a network-topology container with all its content
  • query parameters (network-topology:network-topology?content=nonconfig)  –  this is the query that returns data from path into module and container and in this case with query parameter content with value nonconfig that indicates it will return data from path stored only in nonconfig datastore(operational)

You can use zero or more query parameters in the request URI. For example:

  • content (in GET) – to select config or non-config data(stored in configurational or operational data store)
  • depth (in GET) – limited subtree depth in the reply content
  • fields (in GET) – a request for a subset of target
  • filter (in GET) – boolean notification filter for event stream
  • insert (in POST & PUT) – insertion mode for data resources
  • with-defaults (in GET) – control the retrieval of default values

If you need more information, take a look at RFC 8040.

RESPONSE VALUES OF REQUESTS:

Every request that was made via the REST API, returns a value with return code that indicates success or various types of errors for the request.

There are 5 return code classes:

  • 1xx – informational character and indicates for example that request was received and the user should wait for the process, etc.
  • 2xx – indicates that request was received, understood and accepted, for example, 200 OK or 201 Created, etc.
  • 3xx – indicates that additional action has to be performed to finish the request, used mostly in redirections
  • 4xx – indicates an error that might be caused on the client-side, for example, 400 Bad Request, 403 Forbidden, 404 Not Found, etc.
  • 5xx – indicates an error that occurred on the server or that server cannot complete the request for some reason, for example, 500 Internal Server Error, 503 Service Unavailable, etc.

If these codes are insufficient because, for example, the error needs to be described more specifically, then the error message is usually more described and expanded in the return value of the request for example like this:

//Error Response Body
{
    "error": "err-login-01",
    "message": "Login failed",
    "detail": "Check your username and password"
}

EXAMPLES OF SOME REQUESTS FOR POSTMAN:

Default settings for the http://<ip_address>:<port>/ are http://localhost:8888/, but for example purposes we will use <ip_address>:<port> where ip_address and port are dependent on your running configuration.

Here are models that are used in this example, custom-yang-rpcs for simple-sum-rpc and network-topology for operations with network topologies and nodes.

custom-yang-rpcs@2019-11-14.yang

network-topology@2013-10-21.yang

To try some requests you can start our lighty.io example application and example topology (in mininet). An easy way to connect a controller via an HTTP request is using Postman. Here we show you some examples of how to get information from the controller:

  • to receive the operations(RPCs) that are available in the RESTCONF:
//GET
http://<ip_address>:<port>/restconf/operations
  • here is the example of the part of the received list of available RESTCONF operations(RPCs) in JSON format :
//GET Response Body
{
    "ietf-restconf:operations": {
        "custom-yang-rpcs:simple-sum-rpc": [
            null
        ],
        "custom-yang-rpcs:custom-netconf-dev-connect": [
            null
        ],
...
  • To receive a list of available YANG models loaded into the controller
//GET
http://<ip_address>:<port>/restconf/data/ietf-yang-library:modules-state
  • Here is the example of the part of the received list of YANG models loaded into the controller with its attributes like name, revision, namespace etc.
//GET Response Body
{
    "ietf-yang-library:modules-state": {
        "module": [
            {
                "name": "custom-yang-rpcs",
                "revision": "2019-11-14",
                "namespace": "tag:lighty.io.2019:lighty:custom:yang:rpcs",
                "conformance-type": "import",
                "schema": "/modules/custom-yang-rpcs/2019-11-14"
            },
...
  • To receive information about our topology
//GET
http://<ip_address>:<port>/restconf/data/network-topology:network-topology?content=nonconfig

If you want to add new topology or node:

  • To create a new topology with topology-id test-topology. You need to write a body for this method. It is a JSON format with information about a list of network-topology container (topology) and key for this list (test-topology) that has to be unique:
//PUT
http://<ip_address>:<port>/restconf/data/network-topology:network-topology/topology=test-topology
  • JSON body to PUT network-topology with id test-topology
//PUT Body
{
    "topology":
    {
        "topology-id: "test-topology"
    }
}
  • Here is the network-topology container in the datastore after a successful PUT request:
//GET Response Body
"network-topology:network-topology": {
    "topology": [
        {
            "topology-id: "test-topology"
        }
    ]
}
  • Alternatively, we can create the topologies by inserting whole list of topologies as JSON array in the network-topology container, like this(there can be more then three topologies), but it will rewrite whole container, that means every topology that was in there will be erased, so its best for complete lists or empty topologies:
//PUT
http://<ip_address>:<port>/restconf/data/network-topology:network-topology
  • JSON body to PUT list of topologies
//PUT Body
{
    "network-topology:network-topology": {
        "topology": [
            {
                "topology-id": "test-topology-element1"
            },
            {
                "topology-id": "test-topology-element2"
            },
            {
                "topology-id": "test-topology-element3"
            }
        ]
    }
}
  • Here is the network-topology container in the datastore after successful PUT request:
//GET Response Body
"network-topology:network-topology": {
    "topology": [
        {
            "topology-id": "test-topology-element1"
        },
        {
            "topology-id": "test-topology-element2"
        },
        {
            "topology-id": "test-topology-element3"
        }
    ]
}
  • To create a new node in test-topology, you need to write a body for this method. Similarly to the method before, it is a JSON format with information about a topology list (node) and key for this list (test-node):
//PUT
http://<ip_address>:<port>/restconf/data/network-topology:network-topology/topology=test-topology/node=test-node
  • JSON body to PUT node test-node into network-topology test-topology (or we can do it with the array of nodes just like in the previous example with the topologies )
//PUT Body
{
    "node": {
        "node-id": "test-node"
    }
}

If you want to delete a topology or node (like before it needs to specify the path to the particular node we want to delete):

//DELETE
http://<ip_address>:<port>/restconf/data/network-topology:network-topology/topology=test-topology/node=test-node
  • And almost the same as with node, we just specify the path to the topology for deleting:
//DELETE
http://<ip_address>:<port>/restconf/data/network-topology:network-topology/topology=test-topology

You might also invoke RPC that is implemented or you have implemented so when you will register it to lighty controller it will appear in the RESTCONF operations and you can invoke it like this:

  • I will make an example on custom RPC that takes two input values, sums them up and returns summed value, which is also stored in datastore. You can invoke RPC via POST request like this, you need to specify a path to RPC:
//POST
http://<ip_address>:<port>/restconf/operations/custom-yang-rpcs:simple-sum-rpc
  • and also JSON body, if RPC has some input values:
//POST RPC Body
{   
    "input": {
        "input-a": 100,
        "input-b": 200
    }
}

It returns output value:

//POST RPC Output Body
{
    "custom-yang-rpcs:output": {
        "output-c": 300
    }
}

SUMMARY

In this blog post, we covered what are RESTCONF API requests and their basic principles, with a few examples of how to use them. Let’s do a quick summary:

  • what is RESTCONF API request and what is it used for(to retrieve or write information from/to server)
  • what types of requests RESTCONF API offers and what are the most common ones(GET, PUT, POST, DELETE)
  • how can we put together requests based on the models we use(IP address, port, path, query parameters, etc…)
  • that requests have response values which indicate a type of success or failure of request(server fault, user fault, informational character, etc…)
  • examples of GET requests and how GET request return value body can look like
  • examples of PUT request, how can we write data to the server with it and how it’s using JSON as input to particular requests(container, list, etc…)
  • examples of DELETE, how can we delete something from a server(in the example – topologies, nodes, etc…)
  • example of how can we invoke RPC via a request with input parameters and then what does the output from RPC look like

Those are the basic information that should help you to be able to start using RESTCONF API requests on your own – basic understanding of how it works, what are they used for and how you can put together your own requests along with where to look for troubleshooting in case of failure.

Categories: lighty.io