How to generate dynamic PactDslJsonBody using json value?
Is it possible Pact team can provide the auto builder to assign body dynamically?
Pact Body:
body(new PactDslJsonBody()
.object("testsuite")
.stringType("webId","24255")
.closeObject());
Assert Response:
"{\"testsuite\":{\"webId\":\"24255\"}}";
Based on Assert Response(as input) and create the dslbody like
String json = "{\"testsuite\":{\"webId\":\"24255\"}}"
//body(json);
body(generatePactDSLJsonBody(json));
Assert Response:
assertEqual("{\"testsuite\":{\"webId\":\"24255\"}}",json);
I know in body we can provide json itself. but i need to generate the PactDSLJson body using Json.
It is technically possible to auto-generate the DSL classes from a JSON document, but I do not see the benefit of your example. Most of the time the matchers are defined based on the semantics of the JSON payload, not the syntax.
For example, from your sample JSON, it would see the webId attribute as a string, and generate a string type matcher. However, it is clearly a number, not a string.
The auto-generated DSL body would accept the following JSON:
{"testsuite":{"webId":"This is not a web ID &^*&^%"}}
However, an auto-generation tool used to create a skeleton consumer test from a JSON document which could then be changed based on the semantics of the JSON would be really useful.
We build a library to generate the PactDslJsonBody from a Java Bean. That's not directly your use-case since you want to use JSON as input, but maybe you designed your endpoints to expose Java Beans, so you can use them for your Pacts.
You might want to have a look at https://github.com/remondis-it/pact-consumer-builder.
With this library you're able to define PactDslJsonBody mappings on a per-field or a per-type basis. In our case this reduces the boilerplate code to nearly a one-liner:
PactDslJsonBody jsonBody = ConsumerExpects.type(YOUR_BEAN_TYPE.class)
.useTypeMapping(...)
// Other field or type configurations
.build(new PactDslJsonBody(), YOUR_BEAN_SAMPLE_INSTANCE);
This performs the necessary calls on the PactDslJsonBody and you can use the result for your Pact test.
Btw: The Pact Consumer Builder library works well in conjunction with a fixture generator that produces test data instances for you Java Beans. You can use our fixture generator (https://github.com/remondis-it/resample) but every other Java Bean instance generator should work, too.
Related
There are 2 styles of writing contracts used in our project.
First is to save both request and response as json files and use them to define a contract:
request {
body(file("request.json"))
}
response {
body(file("response.json"))
}
It creates stubs, that don't work unless your request is filled exactly like request.json, which makes it difficult to write unit tests with stubs for the consumer. However, using concrete values might be better for testing integration.
The second approach is to use regular expressions as much as possible:
request {
body([
clientName: $(anyNonBlankString()),
accountNumber: $(consumer(regex("[0-9]{20}")), producer("12345678901234567890")),
amount: $(anyNumber())
])
}
Stubs defined this way will be flexible, but we end up testing only presence of fields in the request and their format.
Which is the right way to write a contract?
It depends only on what you prefer. If you use the first option you can still use the bodyMatchers section where you can, using xpath or jspath, to define which parts of the body should be dynamic. It's all matter of preference.
I have a PASOE Business Class Entity setup as a Web Service. I'm trying to determine how to create a custom header that will allow me to pass in a hashed token. Is this something that I need to upgrade to 11.7.4 for DOH(OpenEdge.Web.DataObject.DataObjectHandler)? Or is this something that I simply add into a method that's defined in the class? Apologies, for the lack of code to illustrate my situation, but I'm not sure where to begin.
If you're using a Business Entity with the web transport then you're using the DOH, and the below applies. If you're using the rest transport then you are not using the DOH, and are more limited in your choices.
There is doc available on the DOH at https://documentation.progress.com/output/oe117sp/index.html#page/gssp4/openedge-data-object-handler.html - it's for 11.7.4 but largely applies to all versions (that is, from 11.6.3+). This describes the JSON mapping file, which you'll need to create an override to the default, generated one.
If you want to use the header's value for all operations, then you may want to use one of the DOH's events. There's an example of event handlers at https://github.com/PeterJudge-PSC/http_samples/blob/master/web_handler/data_object_handler/DOHEventHandler.cls ; you will need to start that handler in a session startup procedure using new DOHEventHandler() (the way that code is written is that it makes itself a singleton).
You can now add handling code for the Invoking event which fires before the business logic is run.
If you want to pass the header value into the business logic you will need to
Copy the generated mapping file <service>.gen to a <service.map> , in the same folder. "gen" files are generated and will be overwritten by the tooling
In the .map file, add a new arg entry. This must be in the same order as the parameters to the BE's method.
The JSON should look something like the below. this will read the value of the header and pass it as an input parameter into the method.
{ "ablName": "<parameter_name>",
"ablType": "CHARACTER",
"ioMode": "INPUT",
"msgElem": {"type": "HEADER", "name": "<http-header-name>"}
}
I'm using Symfony\Component\Serializer\Serializer, and I'm not sure what the difference between the serialize and encode methods is. They have identical signatures, and in practice they seem to give identical output.
Based on the official docs, serializing involves two phases: normalizing and encoding. Normalizing converts input data into array, while encoding crunches that array down to desirable format (be it JSON, XML or something else).
The serialize method of the Symfony Serializer is a wrapper on its encode method. Note that you can call the encode method separately. The serialize method can call the normalize method before the encode method depending on the fact that the requested encoder (eg: json) needs normalization or not.
If you intend to do a JSON serialization, the encode method of the serializer will eventually call json_encode PHP native method. And this method performs a serialization in fact...
For example, if you look into the jsonSerialize method of the jsonSerializable native class of PHP, you can read in the description:
Serializes the object to a value that can be serialized natively by json_encode().
So, at least, in the case of the JSON format, we can say that encoding is serializing in fact but in lower level.
If you call the encode method directly without using the serialize method, you will serialize your data into the expected format but will not take benefits of the normalize process if needed.
I faced the problem with generating React components with api-platform-generate-crud.
Model has property that is object email.
I have serializer that make my email object a string.
API endpoint is serving string.
It works for GET & POST.
When I try to generate React components error message is
TypeError: Cannot read property '0' of undefined
Looking deeper into it, looks like that generator still see my email as object not a string.
Any idea how I can force API to 'see' email property as string not object ?
The data model you define is authoritative. Types in the Hydra documentation reflect the ones in PHP classes.
Here, the email property is of type object. If you set the related data as a string somewhere, you don't respect this contract anymore. The Hydra documentation is not in sync with the returned data.
You can change the type of the email property in the Hydra documentation by decorating the api_platform.hydra.normalizer.documentation service.
But I would recommend to keep the PHP classes' structure of your entities as close as possible of the structure exposed through the API.
Your classes should reflect the output of the API. You can use custom data providers to deal with more complex data structure (ex: ORM entities) before hydrating the structure to expose.
Here's my problem.
I'm using SOAP to retrieve information from a third-party web service.
Response time is too high, so I was planning on using JSON instead, at least in a couple of methods.
For this I'm using DataContractJsonSerializer, but I seem to be having some trouble.
For example, in SOAP there's a method called getAvailablePublic with returns an object of type getAvailablePublicResponse.
There's an equivalent for this method in JSON, which also returns a an object of type getAvailablePublicResponse.
In order to deserialize the information I needed to create a couple of data contracts, and here are my concerns:
Do I really need to create a DataContract? Why can't I use getAvailablePublicResponse object from asmx?
The problem is that if I create a DataContract, I need to use a different name other than getAvailablePublicResponse, as I would have two objects with the same name (the one created by me, and the one from SOAP), and this would require making several changes in my solution.
Hope this makes sense.
Thanks.
Can you post your client code that is making the call to the web service? I don't know what you are using now, but I'm a fan of RestSharp for making remote calls and serializing JSON to C# classes. Something like this:
RestClient client = new RestClient("http://some.domain.com/someservice?someparam=yes");
var results = client.Execute<MyGreatDTOClass>(new RestRequest(Method.GET));