{"id":10925,"date":"2013-01-14T22:33:00","date_gmt":"2013-01-14T21:33:00","guid":{"rendered":"http:\/\/touk.pl\/blog\/?guid=124800f40551c09902c27d14163551dd"},"modified":"2022-08-01T11:38:06","modified_gmt":"2022-08-01T09:38:06","slug":"how-to-keep-session-in-httpbuilder-with-cookies","status":"publish","type":"post","link":"https:\/\/touk.pl\/blog\/2013\/01\/14\/how-to-keep-session-in-httpbuilder-with-cookies\/","title":{"rendered":"How to keep session in HttpBuilder with cookies"},"content":{"rendered":"<p>In my real-world scenario I have a REST service for AJAX purposes. It renders data series for graphs. I want to test it with groovy&#8217;s excellent <a href=\"http:\/\/groovy.codehaus.org\/modules\/http-builder\/\">HttpBuilder<\/a>. There is a problem though &#8211; these requests are only available for already logged in users.<\/p>\n<p>In this post I present a complete solution to maintain a session state between <a href=\"http:\/\/groovy.codehaus.org\/modules\/http-builder\/\">HttpBuilder<\/a>&#8216;s requests.<\/p>\n<h3 id=\"session-in-httpbuilder\">Session in HttpBuilder<\/h3>\n<p>First of all a quick reminder about session. Session is a simulation of state for HTTP requests, which are stateless by its nature. Once you log in you receive a unique cookie (one or more) that identifies you for sequential requests. Every time you send request you send this cookie along. This way server recognizes you and matches you to your session, which is kept on server. Cookie gets invlid once you log out or it times out, for example after 20 minutes of inactivity. Next time you visit a page you get a new, unique cookie.<\/p>\n<p>In order to keep session alive in HttpBuilder I need to:<\/p>\n<ol>\n<li>log in to my Grails application<\/li>\n<li>receive a JSESSIONID cookie in response<\/li>\n<li>store that cookie and send it along with every subsenquential request<\/li>\n<\/ol>\n<p>I&#8217;ve created <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">RestConnector<\/code>class that wraps up HttpBuilder. It&#8217;s main improvement is that it keeps received cookie in a list.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">package eu.spoonman.connectors.RestConnector\r\n\r\nimport groovyx.net.http.Method\r\nimport groovyx.net.http.ContentType\r\nimport groovyx.net.http.HTTPBuilder\r\nimport groovyx.net.http.HttpResponseDecorator\r\n\r\nclass RestConnector {\r\n    private String baseUrl\r\n    private HTTPBuilder httpBuilder\r\n    private List &lt; String &gt; cookies\r\n\r\n    RestConnector(String url) {\r\n        this.baseUrl = url\r\n        this.httpBuilder = initializeHttpBuilder()\r\n        this.cookies = []\r\n    }\r\n\r\n    public def request(Method method, ContentType contentType, String url, Map &lt; String, Serializable &gt; params) {\r\n        debug(\"Send $method request to ${this.baseUrl}$url: $params\")\r\n        httpBuilder.request(method, contentType) {\r\n            request -&gt;\r\n                uri.path = url\r\n            uri.query = params\r\n            headers['Cookie'] = cookies.join(';')\r\n        }\r\n    }\r\n\r\n    private HTTPBuilder initializeHttpBuilder() {\r\n        def httpBuilder = new HTTPBuilder(baseUrl)\r\n\r\n        httpBuilder.handler.success = {\r\n            HttpResponseDecorator resp,\r\n            reader -&gt;\r\n            resp.getHeaders('Set-Cookie').each {\r\n                \/\/[Set-Cookie: JSESSIONID=E68D4799D4D6282F0348FDB7E8B88AE9; Path=\/frontoffice\/; HttpOnly]\r\n                String cookie = it.value.split(';')[0]\r\n                debug(\"Adding cookie to collection: $cookie\")\r\n                cookies.add(cookie)\r\n            }\r\n            debug(\"Response: ${reader}\")\r\n            return reader\r\n        }\r\n        return httpBuilder\r\n    }\r\n\r\n    private debug(String message) {\r\n        System.out.println(message) \/\/for Gradle\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>A few things to notice in a class above. Constructor sets base URL and creates HttpBuilder instance that can be reused. Next, there is a handler on successful request that checks if I receive any cookie. It adds received cookies to list. Finally, there is a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">request<\/code> method that calls <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">HttpBuilder#request<\/code>but it adds cookies to HTTP headers so server can recognize me as a logged in user.<\/p>\n<p>Sending cookies with every request is a core component in here. It simulates browser&#8217;s behavior and maintains session.<\/p>\n<h3 id=\"how-to-use-it\">How to use it?<\/h3>\n<p>I will show you how to use this utility class it in Spock test below. It is fairly simple.<\/p>\n<p>First I login to my application and I ensure that I receive a cookie in return, which is equivalent to being logged in. Then I send a request with that cookie sent in HTTP header. This is a Spock test that implements it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"groovy\">package eu.spoonman.specs.rest\r\n\r\nimport eu.spoonman.connectors.RestConnector.RestConnector\r\nimport groovyx.net.http.ContentType\r\nimport groovyx.net.http.Method\r\nimport spock.lang.Shared\r\nimport spock.lang.Specification\r\nimport spock.lang.Stepwise\r\n\r\n@Stepwise\r\nclass RestChartSpec extends Specification {\r\n    @Shared\r\n    RestConnector restConnector\r\n\r\n    def setupSpec() {\r\n        restConnector = new RestConnector('http:\/\/localhost:8080')\r\n    }\r\n\r\n    def \"should login as test\"() {\r\n        given: Map params = [j_username: 'test', j_password: 'test']\r\n        when: restConnector.request(Method.POST, ContentType.ANY, '\/frontoffice\/j_spring_security_check', params)\r\n        then:\r\n            !(restConnector.cookies.empty)\r\n    }\r\n\r\n    def \"should allow access to chart data series\"() {\r\n        given: Map params = [days: 14]\r\n        when: Map result = restConnector.request(Method.POST, ContentType.JSON, \"frontoffice\/chart\/series\", params)\r\n        then: result != null\r\n        result.series.size() &gt; 0\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p>I create a new <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">RestConnector<\/code> instance in\u00a0<code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">setupSpec<\/code>with my application&#8217;s base URL. Please notice that it has <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">@Shared<\/code>annotation so it&#8217;s shared between tests.<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">@Stepwise<\/code> is crucial annotation for this specification. It means that Spock executes tests exactly in order they&#8217;re defined. I need to ensure that login is executed first. I also need to assert that I receive a cookie and list is not empty. I could move this step into <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">setupSpec<\/code> method too, but I prefer it to be a first test in a specification.<\/p>\n<p>Second test is always executed after login thus it sends cookies within request headers. This is exactly what I wanted to achieve.<\/p>\n","protected":false},"excerpt":{"rendered":"In my real-world scenario I have a REST service for AJAX purposes. It renders data series for graphs. I want to test it with groovy&#8217;s excellent HttpBuilder. There is a problem though &#8211; these requests are only available for already logged in users. In t&#8230;\n","protected":false},"author":37,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[594,71,50,283,402,411,30],"class_list":{"0":"post-10925","1":"post","2":"type-post","3":"status-publish","4":"format-standard","6":"category-development-design","7":"tag-api","8":"tag-frontend","9":"tag-groovy","10":"tag-json","11":"tag-rest","12":"tag-spock","13":"tag-testing"},"_links":{"self":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/10925","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/users\/37"}],"replies":[{"embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/comments?post=10925"}],"version-history":[{"count":5,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/10925\/revisions"}],"predecessor-version":[{"id":14748,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/posts\/10925\/revisions\/14748"}],"wp:attachment":[{"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/media?parent=10925"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/categories?post=10925"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/touk.pl\/blog\/wp-json\/wp\/v2\/tags?post=10925"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}