Robot Framework, REST and JSON

The software I am testing with Robot Framework offers a REST API as main entry point. So the question arose of what library to use to write my Robot tests.

First one I tried was the robotframework-restlibrary.

  • Pro: it is test-oriented and works well with Robot
  • Con: some features are missing (inspecting returned headers for example) and there is no community/activity around it (no commit since 2009)

I used it for a couple of weeks for my first tests but once I reached the limitations of the library, I quickly looked for another one.

I bumped into 2 others libraries tagged as “REST” and “Robot Framework”

but none of them seemed to be a good fit for me (not much documentation, not the right level of keywords, not very active…). Though, the second one was built on “requests library” which seemed to be worth looking at.

Requests Python Library is not Robot or Test oriented but the feature support is very wide, the use guide is very detailed and the community looks very active.

Here is a simple example of how to use it with Robot Framework:
(we use jstontest.com that sends back a json object when we do a get)

*** settings ***
Library  Collections
Library  requests
*** test cases ***
simpleRequest
    ${result} =  get  http://echo.jsontest.com/framework/robot-framework/api/rest
    Should Be Equal  ${result.status_code}  ${200}
    ${json} =  Set Variable  ${result.json()}
    ${framework} =  Get From Dictionary  ${json}  framework
    Should Be Equal  ${framework}  robot-framework
    ${api} =  Get From Dictionary  ${json}  api
    Should Be Equal  ${api}  rest

The trick then is to create appropriate keywords for often-used command.
For example, to check the value of a property in a one-level json object, we could have this keyword:

json_property_should_equal    
    [Arguments]  ${json}  ${property}  ${value_expected}
    ${value_found} =    Get From Dictionary  ${json}  ${property}
    ${error_message} =  Catenate  SEPARATOR=  Expected value for property "  ${property}  " was "  ${value_expected}  " but found "  ${value_found}  "
    Should Be Equal As Strings  ${value_found}  ${value_expected}  ${error_message}    values=false

I am still looking for a good json lib to create/read/update my json objects.
In the meantime I built a collection of keywords like the one mentioned here.

Hope this help some people facing the same kind of starting point (robot + rest + json).
Ping me if you want some more details.

36 thoughts on “Robot Framework, REST and JSON

  1. Laurent,

    Did you create a library for this? I created a Java-based JSON library for RobotFramework in the summer last year, but I’d like one that is python based. Let me know if you have a repo somewhere with a library for this.

    Also, I’m looking at just trying to use the python json library, but it looks like it’s not as tester-friendly as I’d like. So I’d need to wrap it with helper methods.

    Thanks,
    Paul

  2. Follow-up:

    I ended up using a combination of the built-in Collections Library and the python json library. The json and json.JSONDecoder libraries, (when imported into the test with the Library keyword) provides keywords like “decode” which returns a dictionary. The collections library will allow you to get values out of the dictionary returned by decode.

    A snippit:

    ${decodedJson} decode ${json}
    ${foo}= Get From Dictionary ${decodedJson} foo

    Thanks!

  3. Thanks for your comments Paul.
    I also ended up writing my own library which is split in 2 parts:
    – some keywords are written directly in Robot DSL
    – some keywords are written in Python (when Robot was not enough)
    Like you, this is a mix of the JSON Python Lib and Collection Lib of Robot. Basically I tranform json string/files into dictionary and then manipulate the dic.

    This is not nice enough to be shared but I guess that would be interesting to refactor it a bit and share it because there is not much around.

    A question about your example : what is the difference (in Python) between loads() and decode(). Both seem to take a string as input and return a dictionary. No?

    • Well, I’m a n00b with regard to Python, so I have no idea what the difference is. Yes, looks like both take a string and return a dictionary. The documentation for each method looks the same to me, although admittedly, I didn’t spend a lot of time comparing. Looks like JSONDecoder takes in the same parameters in the constructor as loads(), but then decode only takes the json string s. Short answer – not sure. For me, “decode” will be easier to read/understand later because decode means something different to me than loads.

  4. Hi there,

    Nice write up. I am the developer of robotframework-requests [1]. Even though there hasn’t been commits recently it is still maintained. I can add any keywords that you think might be useful all you need to is even send a pull request or create an issue.

    On the documentation side [2] I’m open to feedback in what I could add to help you out.

    Cheers

    1 – https://github.com/bulkan/robotframework-requests
    2 – http://bulkan.github.io/robotframework-requests/

    • I have no real good lib to share. Which part are you interested about? The JSON or the REST part? For the REST, robotframework-requests is a good start.

  5. For JSON conversion, just put Library json in the *** Settings *** section at the top of your RF script, then use ${string_json} = json.dumps ${dict} when you want to convert a dictionary to json-encoded string, and json.loads {“your”:”json”,”encoded”:”string”} to go the other way.

    For manipulation, the Collections lib is handy for its higher-level functions like “Should Contain” but for simple object retrieval I just go straight to the pythonic auto-eval like this: ${ad_tag} = Set Variable ${response[“bids”][0][“ad_tag”]}

  6. HI Guys
    I am also trying to use RobotFramework with the request slibrary.
    Im having issues trying to encode a Dictionary into a json string to send.

    Im not getting the syntax right any help would be appriciated.

    [Tags] explore1
    ${account_data}= Create Dictionary AccountName AutoMata Address1 123 Main St City
    … CA city ProvinceId 1 CountryId US Zipcode
    … 30309 ContactEmail a@a.com
    Log To Console ${account_data}
    ${apple}= json.dumps ${account_data}
    Log To Console ${apple}

    Error displayed in Console
    No keyword with name ‘${apple}= json.dumps ${account_data}’ found.

  7. Thank you for posting. I have tried using Robot Framework with json library but the following errors displayed in the console even before executing my actual code.
    I also have placed json library in the *** Settings *** section
    Traceback (most recent call last):
    File “C:\Python27\Lib\site-packages\robot\runner.py”, line 317, in
    import robot
    File “C:\Python27\lib\site-packages\robot\__init__.py”, line 46, in
    from running import TestSuite, STOP_SIGNAL_MONITOR
    File “C:\Python27\lib\site-packages\robot\running\__init__.py”, line 16, in
    from model import TestSuite
    File “C:\Python27\lib\site-packages\robot\running\model.py”, line 27, in
    from namespace import Namespace
    File “C:\Python27\lib\site-packages\robot\running\namespace.py”, line 27, in
    from userkeyword import UserLibrary
    File “C:\Python27\lib\site-packages\robot\running\userkeyword.py”, line 27, in

    from arguments import UserKeywordArguments
    File “C:\Python27\lib\site-packages\robot\running\arguments\__init__.py”, line
    20, in
    from .argumentresolver import ArgumentResolver
    File “C:\Python27\lib\site-packages\robot\running\arguments\argumentresolver.p
    y”, line 16, in
    from robot.utils import is_dict_like
    ImportError: cannot import name is_dict_like

  8. Hi Guys,

    I am stuck with some issue.

    Here is my code.

    *** Settings ***
    Library Selenium2Library
    Library Collections
    Library OperatingSystem
    Library json
    Library HttpLibrary.HTTP
    Library String
    Library RequestsLibrary

    *** Test Cases ***

    Test2
    [Tags] Post Request
    Create Session alias http://xx.xx.xx.xxx
    ${data}= Create Dictionary email=xyz@domain.com password=admin subdomain=abcd
    ${string_json}= json.Dumps ${data}
    Log To Console ${string_json}
    ${header}= Create Dictionary Content-Type=application/json Authorization=Bearer
    ${string_headers} json.Dumps ${header}
    Log To Console ${string_headers}
    ${resp}= Post Request alias /auth/local?subdomain=abcd data={string_json} headers=${string_headers}
    Log To Console ${resp.json()}

    This API is working fine when i ran in postman but here it is not returning me any response. It supposed to return auth token.
    Currently i am getting AttributeError: ‘str’ object has no attribute ‘items’ error.

    I want to know how to post request with REST API along with parameters like username,password etc. I have searched a lot on google but not helpful.

    Any help would be much appreciated.

    • could you change
      Log To Console ${resp.json()}
      into
      Log To Console ${resp.text}
      so that we see what the server is responding? It seems you get an error which is not a JSON, so it can not be decoded by json()

      > This API is working fine when i ran in postman
      are you sure the parameters are sent via the data body of the request? Could you share a link to a screenshot of your postman or give us the CURL request that would work?

  9. Hi Laurent,

    I’m looking to do some JSON maniupulation with some REST request fun thrown in. HTTP Library or Requests Library should be enough for REST component, however I wonder if you’ve done similar to what I’m looking to do and therefore whether I’m wasting my time or not..

    Pull back a JSON doc via a request. Parse this doc for a certain node. If the node doesn’t exist, add the node containing values I want (without breaking structure.) If the node does exist, I want to remove it and re-add it with values I dictate.

    Seems sensible enough to me but I haven’t played in depth with this like you have so wouldn’t mind an educated opinion?

    regards,

    Nick

  10. Hi Laurent:
    I’m actively using this blog to learn about Robot Framework, REST and the requests library. I noticed in your snippet of code “${result} = get http://echo.jsontest.com/framework/robot-framework/api/rest” when I run that test multiple times it eventually gives me an error code 503 and it says that service is unavailable.

    “Over Quota
    This application is temporarily over its serving quota. Please try again later. ”

    Is there anyway you can fix it to allow a user to run that Robot testcase multiple times? Feel free to contact me through my email.

    Thanks,
    Michael

    • http://echo.jsontest.com is not my web site so I don’t control the way the put quota on requests. Are you doing many requests (like stress tests) and the quota limit would be caused by you? If so, I suppose you should not use this web site for that.

      Anyway, I also saw that this web was occasionally returning 503 but it does not happen often, so I am still using it for some of my tests (launched one a day or something like that)

  11. Hi!

    What´s the state for today (2016)?
    Is robotframework-requests the library to go with for REST API testing?

    Cheers
    Tset

  12. Hi laurent
    I am new to robot framework and trying to do Webservice testing which is having post method.
    While running the script in robotframe work(HttpLibrary.http), i am getting error as “404 bad request” but same request body is working in soapUI.
    Looks like issue related to my json format which is not according to robotframework.

    Could you please help me make some changes in my request
    JSON Request is
    {“TestID”:15}

    • You are not sharing the request itself, so I can’t really help.
      I am surprised that 404 would be about the payload though. Usually this means the URL is not correct.
      And your JSON looks valid one.

      • Hi Laurent,
        I am sorry, due to security issue i will not be in position to share request with you.

        By using the same request i am getting response in SOAP UI. But it is not working for me in Robot FRameWork.

        CAn you please create one small sample project for me if possible and share with me.

        Thanks in advance it would be great help for me.

  13. Dear Friend,

    I have a JAVA api which displays the Alarms of our product.
    I need to read those alarms from Java API to validate whether it is displaying correctly or not.

    Above task i wanted to do from ROBOT framework.
    Any help regarding this i highly appreciated.

  14. Hi Laurent,

    Do you have a suggestion on comparison of 2 Json objects or strings in Robot Framework, down to finding what the differences are?
    I have 2 Json with exact same structure, name/value pairs, etc., and the differences are with 1 or more values stored in each. The first Json represents the initial state of a record, before any changes. The 2nd Json is the new state stored in a record, after 1 or more changes following execution of a test run.
    I have put together a Robot Framework keyword that runs a GET call to retrieve the initial record from the ‘database’ and result is returned as a JSON object.

    ${json_obj} | GET Data Record JSON | ${record_id} | ${auth_text}
    I can also convert to a JSON string, and write it out to a file if needed:
    ${json_string} | evaluate | json.dumps(${json_obj}) | json
    Create File | ${EXECDIR}/${record_id}.json | ${json_string} | encoding=UTF-8

    The 2nd Json is generated with the same GET call to retrieve record again, after the test completes. Now – how to compare the 2 Json?
    Its expected there will be different values after each test run, and doing a simple Json comparison is not sufficient.
    As Json can be viewed as a dictionary, this data has only 4 top-level keys, with 1 main key holding 90% of the data, nested several levels deep in name/value pairs and also as array elements.
    I would like to setup a comparison that returns the low-level name/value pairs that changed, which will help validate a good test run or not. I have thought of converting to dictionary key/value data, and run comparison by the value of each key. However, there is a large amount of nested data, and the top level and intermediate keys are going to be flagged frequently and those are really not of direct interest. Also it seems an inefficient way to compare this data.
    I have searched through many sites and discussions, but most are rather simple comparisons and not much detail on parsing out the differences between 2 Json such as this.
    Any recommendations?
    Json EXAMPLE:
    {
    status: “Success”,
    messages: [ ],
    data: {
    lot_code: “W3B3-5WF2-CWI3”,
    transit_letter: [
    {
    acq_title: null,
    name: “Auto Utility”
    contact_uuid: {
    id:”691851″,
    value: “”
    },
    custrecord: “”,
    lot_state: {
    id: “9”
    value: “Colorado”
    },

    language: “en”,
    edition: “3”,
    mgr_id: “H1”
    }
    ],
    acq_holder: “N[Test]”,
    exrex_de1: “”,
    legal_text: “t”,
    lot1: “134”,
    lot2: “”,
    deal_uuid: {
    id:”7852″
    value: “false”
    },
    insert_after: “2”
    custrecord_class: “A”



    },
    execution: [
    {
    action: “start:Web”,
    time: “55”
    }
    {
    action: “load”,
    time: “353”
    }
    {
    action: “auth”
    time: “359”
    }


    ]
    }

  15. ow to count no of element from json response. I would like to count number of id occurrence from below response :

    {
    “scores”: [
    {
    “id”: 1,
    “value”: “100”
    },
    {
    “id”: 2,
    “value”: “77”
    },
    {
    “id”: 3,
    “value”: “96”
    }
    ]
    }

  16. Hi,

    I am trying to send SMS by using the API /sms/send. Below is the code I have written. Need to know what should I put for the uri. Also Can you check the syntax and let me know If I need to make any changes

    POST SMS Requests2
    Create Session test https://${IP}:443/api/sms/send disable_warnings=1
    &{headers}= Create Dictionary Content-Type=application/json Authorization=Bearer 0552a1fa7d72c2e6ce4d2af72df6d3c26aee0d
    Post Request test /post data={ “handler”: 0,”recipient”: “”, “carrier”: “”, “message”: “test” } headers=${headers}

    Thanks,
    Rajeev

  17. Hi Laurent,

    Can you please help me in Extended Request Library. Actually i have a requirement to test the rest api with auth2 authorization thats y i am using Extended Request Library.

    But when i tried, it gives me an error of missingTokenParameter.

    Please help me.

  18. Hi,

    Really a simple example to start exploring Robotframework and REST. I am a Student and just tried doing a project with Robot framework and REST. I am stuck with an error after running your sample.

    ConnectionError: HTTPSConnectionPool(host=’www.google.com’, port=443): Max retries exceeded with url: / (Caused by NewConnectionError(‘: Failed to establish a new connection: [Errno 11004] getaddrinfo failed’,))

    After doing an online research about the error I found that I have to change proxy settings. Could you please let meknow where could I change the Proxy settings to make the calls work.

    Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *