RestAssured - Get values from nested object using Groovy gson path - rest-assured

How to use rest assured to get the list of all the zips from the below below structure?
{
"persons":[
{
"name": "",
"age":"",
"addresses": [
{
"city": "..",
"zip": ".."
}
]
}
]
}
Expected result is List<String> which contains zip codes only using groovy gson path.

You could use flatten() method to get the zip code:
List<String> zips =JsonPath.from(res).getList("persons.addresses.flatten().zip")

This would work:
import io.restassured.path.json.JsonPath;
...
List<List<String>> temp = JsonPath.from(res).getList("persons.addresses.zip");
List<String> zips = temp.stream().flatMap(List::stream).collect(Collectors.toList());
System.out.println(zips);
//[..]

Related

Displaying enum values together with a referenced class in Swagger using Swashbuckle

I am using Swashbuckle to generate Swagger output. On my model I the following property:
public FieldValue? MyProperty { get; set; }
FieldValue is a simple class that can hold an ID and a name:
public class FieldValue
{
/// <summary>
/// The numerical represenation of the value.
/// </summary>
/// <example>1</example>
public string Id { get; set; }
/// <summary>
/// The textual represenation of the value.
/// </summary>
/// <example>SomeValue</example>
public string Name { get; set; }
}
Via some business logic in our code, a set of possible key-value pairs (ID and name) are mapped to this property.
Now, I would like to show all the possible values for MyProperty in the enum tag in my Swagger output. Using an implementation of ISchemaFilter, a custom attribute on the MyProperty property and using allOf instead of a simple ref, I have managed to add the values in my JSON output, see below. The reason for using allOf instead of just ref is that ref will overwrite all properties on the referencing schema. So, when I use allOf it keeps my description and enum fields in the document.
{
"components": {
"schemas": {
"FieldValue": {
"type": "object",
"properties": {
"Id": {
"type": "string",
"description": "The numerical represenation of the value.",
"nullable": true,
},
"Name": {
"type": "string",
"description": "The textual represenation of the value.",
"nullable": true,
}
}
},
"MyProperty": {
"enum": [
"1: EnumValue1",
"2: EnumValue2",
"3: EnumValue3"
],
"allOf": [{
"$ref": "#/components/schemas/FieldValue"
}
],
"description": "Some description",
"nullable": true
}
}
}
This does not show the enum-values in the Swagger UI, though. It does show the description.
Is this Swagger doc valid? If not, how can I make it valid and display the enums for MyProperty?
The correct representation of your use case is:
"MyProperty": {
"enum": [
{"Id": "1", "Name": "EnumValue1"},
{"Id": "2", "Name": "EnumValue2"},
{"Id": "3", "Name": "EnumValue3"}
],
"allOf": [
{ "$ref": "#/components/schemas/FieldValue" }
],
"description": "Some description",
"nullable": true
}
However, there's little to no tooling support for enums containing object literals. I suggest mentioning the possible Id and Name values in the description of the MyProperty property.

How can I get OpenApi-Generator to produce nullable DateTimeOffset?

My API exposes some endpoints with DateTime? and others with DateTimeOffset?.
I want to generate an API Client using OpenApi-Generator, that will create client code for each endpoint, respecting the differences between the types.
OpenApi-Generator offers the option to useDateTimeOffset=true, which will generate the client using DateTimeOffset everywhere regardless of whether the API was exposing DateTime or DateTimeOffset. As such, I don't want to use that.
So to resolve the requirement without that, I'm attempting to create a Filter in which I will specify that in the case of DateTimeOffset? the generator should use the type DateTimeOffset and make it nullable.
This is the Filter:
public class FixDateTimeOffsetTypeSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema model, SchemaFilterContext context)
{
if (context.Type == typeof(DateTimeOffset?))
{
model.Format = "date-time-offset-nullable";
model.Type = "DateTimeOffset";
model.Nullable = true;
}
}
}
and this is an example of the output from that:
"/Api/MyApiEndpoint": {
"get": {
"tags": [
"General"
],
"operationId": "General_MyApiEndpoint",
"parameters": [
{
"name": "startDatetime",
"in": "query",
"schema": {
"type": "DateTimeOffset",
"format": "date-time-offset-nullable",
"nullable": true
}
},
When I run this and generate the client from that JSON, the the DateTimeOffset objects are never nullable. It doesn't seem to respect that instruction.
What do I need to change to make it work, so that when I specify DateTimeOffset should be nullable, it appears as nullable in the code?
It looks like this is a known problem:
https://github.com/OpenAPITools/openapi-generator/pull/3530
And here is the pull request that solves it: https://github.com/OpenAPITools/openapi-generator/pull/3530/commits/89fd5d70e9f15a5be9ffe26c2beddc07770043c0
Also check this link: https://jane.readthedocs.io/en/latest/tips/nullable.html

Adding Example RequestBody in swagger micronaut

I generated swagger for micronaut using the instructions provided in https://micronaut-projects.github.io/micronaut-openapi/latest/guide/index.html
So I have a controller method like:
#Consumes("application/vnd.api+json")
#Produces("application/vnd.api+json")
#Post("/{id}/users")
#RequestBody
public HttpResponse addAndAssignTarget(#PathVariable("id") Long projectId, #Body #Parameter() JsonNode user) {
I am not using a POJO for adding users for another reason which is out of context for this question. Thus, the generated swagger ui shows {} as example for request body. I would like to change this to something like. How can I do this?
{
"data" : {
"type": "projects",
"attributes": {
"name": "some-name1",
"description": "some-description",
"partner_company": "some-compnay"
}
}
}
It looks much better if you use POJO. However, you can add an example as string, but the problem with that if you have any nested objects the quotation marks won't look nice (will be escaped "):
#Consumes("application/vnd.api+json")
#Produces("application/vnd.api+json")
#Post("/{id}/users")
#RequestBody
public HttpResponse addAndAssignTarget(#PathVariable("id") Long projectId,
#Body #RequestBody(content = #Content(schema = #Schema(example = "[0, 2, 3]"))) JsonNode user){
}
Also it is not a Paramater, but a #Body and #RequestBody for annotation purposes.
Output will be:
"[0, 2, 3]"

Rendering JSON in a RAZOR view in ASP.NET MVC

I'm working on an ASP.NET MVC app. My app is interacting with a third-party REST service. That service is getting called in the controller of my MVC app. The results from the service look like this:
{
"group#odata.type": "#Collection",
"group": [],
"class#odata.type": "#Collection",
"class":[
{ "total": 111, "value": "A" },
{ "total": 222, "value": "B" },
{ "total": 333, "value": "C" }
],
"status#odata.type": "#Collection",
"status": [
{ "total": 1, "value": "Open" },
{ "total": 20, "value": "Closed" },
{ "total": 51, "value": "Unknown" }
]
}
The results of the service are stored in a JObject property in my model called Results. For every array, I am trying to print out its key name. Then, I want to look through and print out each value and total in the array. In other words, the JSON above would look like this:
group
class
A - 111
B - 222
C - 333
status
Open - 1
Closed - 20
Unknown - 51
In an attempt to do this, I have the following in my View.
foreach (var result in Model.Results)
{
<div></div>
<ul>
#foreach (var subResult in result.?)
{
<li style="padding-left:8px;">#(subResult["value"] + " - " + subResult["total"])</li>
}
</ul>
}
Clearly the above doesn't work. My challenge is, I do not understand how to:
Loop through the key/value pairs in a JObject.
Identify if the value is a JArray or another JObject.
If I use result.Children(), I do not get each key/value pair like I'm expecting. At the same time, result does not have a Keys property like I would expect. I feel very stuck at the moment.
Thank you for any help you can provide. Happy holidays!
According to the documentation on JObject, it should implement IDictionary<string, JToken>. They might have done an explicit implementation of the interface, so you'd need to cast your JObject instance to IDictionary<string, JToken> first.
First of all define some classes that correspond to your Json response:
public class ServiceResponce
{
public IList<Row> Group{get;set;}
public IList<Row> Class{get;set;}
public IList<Row> Status{get;set;}
}
public class Row
{
public int Total {get;set;}
public string Value {get;set;}
}
Than you can use Json.Net or some other library to deserialize your Json in to an object:
JsonConvert.DeserializeObject<ServiceResponce>(json);
So your model will finally have ServiceResponce property:
public ServiceResponce Result{get;set;}
Than you can easily navigate through ServiceResponce properies:
<div></div>
<ul>
foreach (var result in Model.Result.Group)
{
<li style="padding-left:8px;">#(result.Value + " - " + result.Total)</li>
}
<ul>
To make it cleaner write an HtmlHelper that receives a IList<Row> as a parameter and renders it in a required format, so at the end you will end with something like:
#YourHelper(Model.Result.Group)
#YourHelper(Model.Result.Class)
#YourHelper(Model.Result.Status)

Custom Web API Formatting

I've been playing around with asp.net web api, and I noticed that default generated returned json doesn't include the object level key. I was also wondering how to customize the output of the json string. For example:
Getting a User usually returns
{
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male"
}
I was hoping I could return something like:
{
"data": {
"Name": "ChaoticLoki",
"Age": 22,
"Sex": "Male",
},
"success": true
}
You can then create a class wrapping the data and status like this
public class JsonResult{
public object data { get; set;}
public boolean success { get; set;}
}
And then in your Web Api methods, you can do
var data = ... //getting from repo
return Json(new JsonResult{data = data, success = true});

Resources