hurl
hurl copied to clipboard
Websocket support and documentation?
Problem to solve
I am trying to see if hurl
can test websocket requests.
Proposal
I'd like to know if hurl
can test websocket requests and, if yes, can we add some documentation on how to do so?
Additional context and resources
N/A
Tasks to complete
N/A
Hi @nahuakang, we haven't done it so far. We have only used Hurl with the http/https protocols. Not sure whether it's easy or not to add Websocket support. We can have a look at it. How would you write the Hurl file? It's also useful to have a concrete example.
@fabricereix Thanks so much for your response. While I have a concrete use case (which is currently done in Postman), I don't have a concrete example on how to write it in Hurl style. If it helps, I can think about it for a bit.
I've got an example, though I'm not sure how I'd want to write it in Hurl style. Basically, I'm writing a graphql API, where I can submit jobs and track their progress with a subscription, which uses websockets.
I haven't quite settled on what API I want yet, but traffic looks something like this atm (>
for sent and <
for received items):
> {"type":"connection_init","payload":{}}
< {"type":"connection_ack"}
> {"id":"4b8d2a04-0a56-4565-8f34-41067e2b3cb6","type":"subscribe","payload":{"query":"jobUpdate(jobId: \"lU1TG2v79Q0ynYMv1FsZs\") {\n state\n progress {\n current total\n }\n }\n}"}}
< {"type":"next","id":"4b8d2a04-0a56-4565-8f34-41067e2b3cb6","payload":{"data":{"jobUpdate":{"state":"STARTED","progress":{"current":1,"total":3}}}}}
< {"type":"next","id":"4b8d2a04-0a56-4565-8f34-41067e2b3cb6","payload":{"data":{"jobUpdate":{"state":"STARTED","progress":{"current":2,"total":3}}}}}
< {"type":"next","id":"4b8d2a04-0a56-4565-8f34-41067e2b3cb6","payload":{"data":{"jobUpdate":{"state":"DONE","progress":null}}}}
< {"type":"complete","id":"4b8d2a04-0a56-4565-8f34-41067e2b3cb6"}
There can also be failure updates, so I guess what I'd be interested in would be a way to write a graphql subscription request like any other request and then assert that at some point a packet with a specific payload returns and that the connection completes within a certain time frame.
Maybe something along these lines? Very rough sketch, I haven't thought about this much, and it would be nice if we could check that a specific subsequence of updates appeared in order, though getting that right is probably very difficult.
WS http://localhost:8000/ws
```graphql
subscription {
jobUpdate(
jobId: "{{job_id}}"
) {
state
progress { current total }
}
}
```
HTTP 200
[Asserts]
any jsonpath "$.data.jobUpdate.state" == "DONE"
any jsonpath "$.data.jobUpdate.progress.current" == 2
With JetBrains HTTP client, the WebSocket syntax is something like:
WEBSOCKET ws://localhost:8080/websocket
Content-Type: application-json // Used for content highlighting only
// Request body, for example:
{
"message": "First message sent on connection"
}
=== // message separator
{
"message": "Second message" // will be sent right after the previous one
}
=== wait-for-server // keyword used to wait for the server response
{
"message": "Send this after the server response"
}
With === // message separator
as a sent message seperator, and === wait-for-server
as a wait message from server
My 2 cents:
HTTP http://example.com/ws
Connection: upgrade
Upgrade: websocket
[Options]
connection-close: false
HTTP 101
[Asserts]
# typical response assertions
[SendData]
> {
> "action": "send-me-cats",
> "#comment": "the > is for multiline, like a blockquote in markdown"
> }
[AssertReceiveData]
jsonpath "$.cats" count == 49
[SendData]
> {
> "action": "send-me-cats",
> "#comment": "the > is for multiline, like a blockquote in markdown"
> }
[AssertReceiveData]
jsonpath "$.cats" count == 49
[ConnectionClose]
Basically, a websocket is "just" an HTTP connection that is not closed.
Upon receiving the status code 101 Switching Protocol
we are in "websocket mode".
We could then have a series of section [SendData]
and/or [AssertReceiveData]
, ended by a [ConnectionClose]
.
This would be more in line with the actual hurl file syntax AND the actual flow of the data on the socket.
Note that this syntax would work the same for Server-Sent-Events:
GET http://example.com/sse
[Options]
connection-close: false
HTTP 200
[Asserts]
header "Content-Type" == "text/event-stream"
[AssertReceiveData]
# ...
[AssertReceiveData]
# ...
[AssertReceiveData]
# ...
[ConnectionClose]
Good ideas, I also like JetBrains's HTTP Client format for web socket:
WEBSOCKET ws://localhost:8080/websocket
Content-Type: application-json // Used for content highlighting only
// Request body, for example:
{
"message": "First message sent on connection"
}
=== // message separator
{
"message": "Second message" // will be sent right after the previous one
}
=== wait-for-server // keyword used to wait for the server response
{
"message": "Send this after the server response"
}
https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html#multiple_messages