Programmatically set an url parameter in gin context for testing purpose - go

I am writing some test suites for gin middlewares. I found a solution to test them without having to run a full router engine, by creating a gin context like this :
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
The goal is to test my function by calling :
MyMiddleware(c)
// Then I use c.MustGet() to check if every expected parameter has been transmitted to gin
// context, with correct values.
One of my middlewares relies on c.Param(). Is it possible to programatically set an Url param in gin (something like c.SetParam(key, value)) before calling the middleware ? This is only for test purpose so I don't mind non-optimized solutions.

Finally figured it out by using IntelliJ to inspect the structure, I can just set it the raw way :
c.Params = []gin.Param{
{
Key: "id",
Value: "first document",
},
}

I was not able to get the accepted answer to work due to the c.Request.URL being nil in some of my tests.
Instead, you can set the query like this:
c.Request.URL, _ = url.Parse("?id=mock")

Related

Can't we include vars in gorilla subrouter pathprefix?

I'm trying to add a subrouter to my router code :
router := mux.NewRouter()
baseRouter := router.PathPrefix("/api/v1").Subrouter()
managementRouter := baseRouter.PathPrefix("/managing/{id}").Subrouter()
managementRouter.Use(auth.ManagingMiddleware)
managementRouter.HandleFunc("/add-employees", management.AddEmployeesToOrganization).Methods("POST")
The goal is to force the client to give an id variable on each call to managementRouter
functions.
Although, when i send a request like this :
/api/v1/managing/627e6f7e05db3552970e1164/add-employees
... I get a 404. Am I missing something or is it just not possible ?
Ok so I found a solution in my dream last night haha
Basically the problem with the following prefix :
managementRouter := baseRouter.PathPrefix("/managing/{id}").Subrouter()
Is that the router has no way of knowing where the id field stops. So when we access an endpoint with for example this url : /api/v1/managing/627e6f7e05db3552970e1164/add-employees, the router believes that the {id} variable is literally 627e6f7e05db3552970e1164/add-employees and doesn't match any route after it.
So the solution I found is to tell the router what comes after the variable. For that, you just add a slash after the variable :
managementRouter := baseRouter.PathPrefix("/managing/{id}/").Subrouter()

Non-escaped query parameters for URL

I want to create a query parameter without escaping the query string.
For example, I need to create a query parameter q with the content
"before:{2019-12-24 19:57:34}"
so that the URL is
https://android-review.googlesource.com/changes/?q=before:{2019-12-24 19:57:34}
If I use this code (Golang Playground)
url, _ := url.Parse("https://android-review.googlesource.com/changes/")
q := url.Query()
q.Set("q", "before:{2019-12-24 19:57:34}")
url.RawQuery = q.Encode()
fmt.Println(url)
url is escaping the special characters, spaces, and brackets:
https://android-review.googlesource.com/changes/?q=before%3A%7B2019-12-24+19%3A57%3A34%7D
How can I solve this issue except manually creating the URL (without query parameters then)?
If you don't want your URL query to be encoded, then don't use the Encode() method. Instead, set the RawQuery value directly, yourself:
url, _ := url.Parse("https://android-review.googlesource.com/changes/")
url.RawQuery = "q=before:{2019-12-24 19:57:34}"
fmt.Println(url)
Output:
https://android-review.googlesource.com/changes/?q=before:{2019-12-24 19:57:34}
playground
Keep in mind, however, that this is a recipe for potential disaster, depending on how that url is eventually used. In particular, the space in that URL should be escaped, according to RFC. See more here.
Perhaps you'll want to implement your own minimal escaping, if that's compatible with your use-case.

Variables and data files in Postman Collection Runner

I have an API get requests in Postman that uses a data file of voucher codes to look up other information about the code, such as the name of the product the code is for. When using collection runner the voucher codes are passed incorrectly and the data is returned about the product.
For some reason, I'm unable to capture the data from the response body and link this into the next request.
1st get request has this in the body section:
{
"dealId": 6490121,
"voucherCode": "J87CM9-5PV33M",
"productId": 520846,
"productTitle": "A Book",
"orderNumber": 23586548,
"paymentMethod": "Braintree",
"deliveryNotificationAvailable": true
}
I have this in the tests section to capture the values:
var jsonData = pm.response.json()
pm.environment.set("dealId", jsonData.dealId);
pm.globals.set("productId", jsonData.productId);
when posting the next request in the body:
{
"dealId":{{dealId}},
"dealVoucherProductId": {{productId}},
"voucherCode":"{{VoucherCode}}",
}
and pre-request scripts:
pm.environment.set("productId", "productId");
pm.globals.set("dealId", "dealId");
As you can see I've tried to use global and environmental variables both are not populating the next request body.
What am I missing?
This wouldn't set anything in those variables apart from the strings that you've added.
pm.environment.set("dealId", "dealId");
pm.globals.set("productId", "productId");
In order to capture the response data and set it in the variable you will need to add something like this to the first requests Tests tab:
var jsonData = pm.response.json()
pm.environment.set("dealId", jsonData.dealId);
pm.globals.set("productId", jsonData.productId);
Depending on the response schema of the first request - This should set those values as the variables.
You can just use the {{dealId}} and {{productId}} where ever you need them after that.
If you're using a environment variable, ensure that you have created an file for those values to be set.

How do I pass connection-time websocket parameters to Phoenix from Elm?

I was following along Programming Phoenix but using Elm for my front end, rather than Javascript. The second part of that book describes how to use websockets. The book's running example has you create an authentication token for the client side to pass to Phoenix at connection creation time. The Javascript Socket class provided with Phoenix allows that, but there's no obvious way to do it in Elm (as of 0.17 and the date of this question).
As in the book, make the token visible to Javascript by attaching it to window.
<script>window.auth_token = "<%= assigns[:auth_token] %>"</script>
In web/static/js/app.js, you'll have code that starts Elm. Pass the token there.
const c4uDiv = document.querySelector('#c4u-target');
if (c4uDiv) {
Elm.C4u.embed(c4uDiv, {authToken: window.auth_token});
}
On the Elm side, you'll use programWithFlags instead of program.
Your init function will take a flags argument. (I'm using the Navigation library for a single-page app, which is why there's a PageChoice argument as well.)
type alias Flags =
{ authToken : String
}
init : Flags -> MyNav.PageChoice -> ( Model, Cmd Msg )
Within init, tack on the token as a URI query pair. Note that you have to uri-encode because the token contains odd characters. Here's the crude way to do that. Note: I am using the elm-phoenix-socket library below, but the same hackery would be required with others.
let
uri = "ws://localhost:4000/socket/websocket?auth_token=" ++
(Http.uriEncode flags.authToken)
in
uri
|> Phoenix.Socket.init
|> Phoenix.Socket.withDebug
|> Phoenix.Socket.on "ping" "c4u" ReceiveMessage
I got here by a Tweet by Brian, about encoding from Elm.
In this case I like to handle it from the JavaScript side.
I tried to replicate the way the Phoenix client sets it up.
Instead of passing the token I passed the complete endpoint...
I've put the token in JSON a hash
<script id="app-json" type="application/json"><%= raw #json %></script>
Which I read on the client, and pass to the Elm embed
var data = JSON.parse(document.getElementById("app-json").innerHTML)
var token = encodeURIComponent(data.token)
var elm = window.Elm.App.embed(document.getElementById("elm-container"), {
socketEndpoint: "ws://" + window.location.host + "/socket/websocket?token=" + token
})

GoREST endpoint path

I'm writting a web service with Go and I'd like to have url like :
http://example.com/WEB/service.wfs?param1=2&param2=test.....
I'm using GoREST and my Endpoint url is :
method:"GET" path:"/WEB/service.wfs?{param:string}" output:"string"
My problem is that it never return the "param" but it does if I use the endpoint :
method:"GET" path:"/WEB/service.wfs/{param:string}" output:"string"
Is there a way to handle the "?" ?
You can do this in gorest though it's not as nice as gorest's preferred mechanism.
Don't include your query parameters in your endpoint definition
method:"GET" path:"/WEB/service.wfs" output:"string"
Instead, you can get at the context from your registered end point and get the query parameters using something like
func (serv MyService) HelloWorld() (result string) {
r := serv.Context.Request()
u, _ := url.Parse(r.URL.String())
q := u.Query()
result = "Buono estente " + q["hi"][0]
return
}
I have had a look at the GoREST package you are using and can not see any way of doing this.
I have always used gorillatoolkit pat package.
gorillatoolkit
There is an example of what you want to do about half way down.
category := req.URL.Query().Get(":category")
This way you can get the query parameters on the request URL by the key.
Hope this helps.

Resources