With Karate, I'm looking to simulate an end-to-end test structure where I do the following:
Make a GET request to specific data
Store a value as a def variable
Use that information for a separate scenario
This is what I have so far:
Scenario: Search for asset
Given url "https://foo.bar.buzz"
When method get
Then status 200
* def responseItem = $.items[0].id // variable initialized from the response
Scenario: Modify asset found
Given url "https://foo.bar.buzz/" + responseItem
// making request payload
When method put.....
I tried reading the documentation for reusing information, but that seemed to be for more in-depth testing.
Thoughts?
It is highly recommended to model flows like this as one scenario. Please refer to the documentation: https://github.com/intuit/karate#script-structure
Variables set using def in the Background will be re-set before every
Scenario. If you are looking for a way to do something only once per
Feature, take a look at callonce. On the other hand, if you are
expecting a variable in the Background to be modified by one Scenario
so that later ones can see the updated value - that is not how you
should think of them, and you should combine your 'flow' into one
scenario. Keep in mind that you should be able to comment-out a
Scenario or skip some via tags without impacting any others. Note that
the parallel runner will run Scenario-s in parallel, which means they
can run in any order.
That said, maybe the Background or hooks is what you are looking for: https://github.com/intuit/karate#hooks
Related
Right now, my HTTP call has 3 assertions. The reporting options for the results listener only provide a checkbox for "Assertion Results", which lumps all of my assertion results into one value in the CSV output.
The team would like to create a csv output for each assertion. The problem is, you can't add a results listener under an assertion, it must be under the HTTP call. I can't think of a way to create separate reports besides making three separate HTTP calls, each with their own results listener writing a report. That is not ideal.
I tried with jtl with XML.
Below is the config. Use minimum parameter required as it consume a lot of resource.
Below is the output.
But i think if you try to have response time in the same then there will be same entry twice. Similarly, other calculation might get impacted. So, you can use two one this and other simple data writer.
Hope this helps.
I have an object:
Account
{
Id,
Name,
CurrentBalance
}
Id is an immutable key, Name is a mutable string, and CurrentBalance is calculated from all of the transactions associated with the account.
I am stuck on the fact that GET \Accounts\{Id} will not be idempotent because changes to a transaction will cause a change in CurrentBalance. Should I remove this field from the object and make a request like
POST \Accounts\{Id}\CurrentBalance
But now I have to make multiple calls to the server to get the CurrentBalance of all objects:
GET \Accounts
POST \Accounts\{Id1}\CurrentBalance
POST \Accounts\{Id2}\CurrentBalance
POST \Accounts\{Id3}\CurrentBalance
....
I guess I am just looking to see if there is already a standard way to handle this that I am missing?
UPDATE
Part 2 if the original object is ok via GET. My only way to update the Account.Name is via a PATCH as I cannot allow an update to CurrentBalance, correct?
NOTE
I realize I could put this on the client to have to get all transactions and calculate it, but I would prefer to do this on the server for multiple reasons
Idempotency does not mean that you must always get the same response back.
Consider the resource /TodaysWeather. It would be pretty useless if it always returned the same value.
Idempotency simply states that if a client makes the same request multiple times instead of just once, the impact on the system (from the client's perspective) will be the same.
I just re-read the HTTP specs and realized that if I want to be truly RESTful I have to make multiple calls because GET has to be safe.
In particular, the convention has been established that the GET and
HEAD methods SHOULD NOT have the significance of taking an action
other than retrieval.
I am not deleting this question because I think it could help others in the future, but if the majority disagree I will delete it
If it's important that you're able to PUT some data, then immediately retrieve the same data via GET, then you could simply treat it as a different resource entirely, e.g.:
# Change an account name
PUT \Accounts\{id}
# Get accounts/names/balances
GET \AccountDetails
# Get balance of an account
GET \AccountDetails\{id}\CurrentBalance
However, there's really no good reason to go through the trouble of doing that. Your PUT is idempotent as long as making the same request multiple times doesn't change the state of the system. Not changing the system's state if some spurious value is submitted is the correct behavior. In fact, if someone does try a PUT including CurrentBalance, you might want to return a 400 (Bad Request) status explaining that CurrentBalance can't be updated.
When i have a resource, let's say customers/3 which returns the customer object and i want to return this object with different fields, or some other changes (for example let's say i need to have include in customer object also his latest purchase (for the sake of speed i dont want to do 2 different queries)).
As i see it my options are:
customers/3/with-latest-purchase
customers/3?display=with-latest-purchase
In the first option there is distinct URI for the new representation, but is this REALLY needed? Also how do i tell the client that this URI exist?
In the second option there is GET parameter telling the server what kind of representation to return. The URI parameters can be explained through OPTIONS method and it is easier to tell client where to look for the data as all the representations are all in one place.
So my question is which of these is better (more RESTful) and/or is there some better way to do this that i do not know about?
I think what is best is to define atomic, indivisible service objects, e.g. customer and customer-latest-purchase, nice, clean, simple. Then if the client wants a customer with his latest purchases, they invoke both service calls, instead of jamming it all in one with funky parameters.
Different representations of an object is OK in Java through interfaces but I think it is a bad idea for REST because it compromises its simplicity.
There is a misconception that making query parameters look like file paths is more RESTful. The query portion of the address is included when determining a distinct URI so the second option is fine.
Is there much of a performance hit in including the latest purchase data in all customer GET requests? If not, the simplest thing would be to do that so there would neither be weird URL params or double requests. If getting the latest order is a significant hardship (which it probably shouldn't be) there is nothing wrong with adding a flag in the query string to include it.
Thinking about REST, it's relatively easy to map HTTP methods to CRUD actions: POST for create, GET for read, etc. But what about "fire and forget" actions? What HTTP method would best represent a fire and forget action such as triggering a batch job (in which no response is sent back to the caller)?
POST would spring to mind, but I think GET is also an appropriate method because 99% of the time you only supply a bunch of parameters to these types of actions. What do you think?
POST would spring to mind, but I think GET is a more appropriate method because 99% of the time you only supply a bunch of parameters to these types of actions. What do you think?
External State
I think that the number of parameters you use has nothing to do with the verb you use. The key issue is are you changing externally visible state?
BatchJob Resources
In your example, if the batch job does not affect the externally visible state of any object then you could implement it as a batch job. However you could model your batch job as a resource with an associated resource container.
You could use a Post to create a new BatchJob resource and allow the user to do a GET to see the progress of the job so far. You could do a GET on the resource container to list all of the running batch jobs, possibly calling DELETE to kill one.
You should use POST if your request modifies data, and GET if it only reads it.
Since your request is "fire and forget", I guess that it's modifying data, so use POST.
I think in the general case we might well supply various payload parameters, and these plausibly might exceed what's possible with GET, so POST is quite reasonable - the action of starting a job doesn't to me fit well with GET sematics.
One thought, might not the action actually return a response:
a). No, sir, that's an impossible request we can't start your job.
b). Understood, your job reference is 93.
If you're concerned at that level, perhaps HEAD is the HTTP method you want; it's identical to GET, with the stipulation that the response body is empty. That sounds to me spot-on to what you're asking for?
I'm bringing this question back from the dead to offer a different point of view.
Now that CORS is prevalent, the choice between using GET or POST becomes a matter of if you want anyone who knows your API URI to be able to trigger the batch job (GET), or if you want to restrict the origin of the request to prevent any Joe with a computer from triggering the job (POST).
I have a resource that has a counter. For the sake of example, let's call the resource profile, and the counter is the number of views for that profile.
Per the REST wiki, PUT requests should be used for resource creation or modification, and should be idempotent. That combination is fine if I'm updating, say, the profile's name, because I can issue a PUT request which sets the name to something 1000 times and the result does not change.
For these standard PUT requests, I have browsers do something like:
PUT /profiles/123?property=value&property2=value2
For incrementing a counter, one calls the url like so:
PUT /profiles/123/?counter=views
Each call will result in the counter being incremented. Technically it's an update operation but it violates idempotency.
I'm looking for guidance/best practice. Are you just doing this as a POST?
I think the right answer is to use PATCH. I didn't see anyone else recommending it should be used to atomically increment a counter, but I believe RFC 2068 says it all very well:
The PATCH method is similar to PUT except that the entity contains a
list of differences between the original version of the resource
identified by the Request-URI and the desired content of the resource
after the PATCH action has been applied. The list of differences is
in a format defined by the media type of the entity (e.g.,
"application/diff") and MUST include sufficient information to allow
the server to recreate the changes necessary to convert the original
version of the resource to the desired version.
So, to update profile 123's view count, I would:
PATCH /profiles/123 HTTP/1.1
Host: www.example.com
Content-Type: application/x-counters
views + 1
Where the x-counters media type (which I just made up) is made of multiple lines of field operator scalar tuples. views = 500 or views - 1 or views + 3 are all valid syntactically (but may be forbidden semantically).
I can understand some frowning-upon making up yet another media type, but I humbly suggest it's more correct than the POST / PUT alternative. Making up a resource for a field, complete with its own URI and especially its own details (which I don't really keep, all I have is an integer) sounds wrong and cumbersome to me. What if I have 23 different counters to maintain?
An alternative might be to add another resource to the system to track the viewings of a profile. You might call it "Viewing".
To see all Viewings of a profile:
GET /profiles/123/viewings
To add a viewing to a profile:
POST /profiles/123/viewings #here, you'd submit the details using a custom media type in the request body.
To update an existing Viewing:
PUT /viewings/815 # submit revised attributes of the Viewing in the request body using the custom media type you created.
To drill down into the details of a viewing:
GET /viewings/815
To delete a Viewing:
DELETE /viewings/815
Also, because you're asking for best-practice, be sure your RESTful system is hypertext-driven.
For the most part, there's nothing wrong with using query parameters in URIs - just don't give your clients the idea that they can manipulate them.
Instead, create a media type that embodies the concepts the parameters are trying to model. Give this media type a concise, unambiguous, and descriptive name. Then document this media type. The real problem of exposing query parameters in REST is that the practice often leads out-of-band communication, and therefore increased coupling between client and server.
Then give your system a uniform interface. For example, adding a new resource is always a POST. Updating a resource is always a PUT. Deleting is DELETE, and getiing is GET.
The hardest part about REST is understanding how media types figure into system design (it's also the part that Fielding left out of his dissertation because he ran out of time). If you want a specific example of a hypertext-driven system that uses and doucuments media types, see the Sun Cloud API.
After evaluating the previous answers I decided PATCH was inappropriate and, for my purposes, fiddling around with Content-Type for a trivial task was a violation of the KISS principle. I only needed to increment n+1 so I just did this:
PUT /profiles/123$views
++
Where ++ is the message body and is interpreted by the controller as an instruction to increment the resource by one.
I chose $ to deliminate the field/property of the resource as it is a legal sub-delimiter and, for my purposes, seemed more intuitive than / which, in my opinion, has the vibe of traversability.
I think both approaches of Yanic and Rich are interresting. A PATCH does not need to be safe or indempotent but can be in order to be more robust against concurrency. Rich's solution is certainly easier to use in a "standard" REST API.
See RFC5789:
PATCH is neither safe nor idempotent as defined by [RFC2616], Section
9.1.
A PATCH request can be issued in such a way as to be idempotent,
which also helps prevent bad outcomes from collisions between two
PATCH requests on the same resource in a similar time frame.
Collisions from multiple PATCH requests may be more dangerous than
PUT collisions because some patch formats need to operate from a
known base-point or else they will corrupt the resource.