How to prevent nested models with OpenAPI Codegen? - json

Input JSON
I have huge JSON. This is an excerpt of it.
{
"base.get.v1.Input": {
"properties": {
"request": {
"$ref": "#/components/schemas/base.get.v1.Input.Request"
},
"id": {
"maxLength": 128,
"type": "string"
}
},
"required": ["id"],
"type": "object"
}
}
Output interface
Using OpenApi-generator-cli-3.0.0.jar i get the following typescript file (relative to che part of JSON showed before):
import { BaseGetV1InputRequest } from './baseGetV1InputRequest';
export interface BaseGetV1Input {
request?: BaseGetV1InputRequest;
trid: string;
}
Desired result
Is there a way to have the request object (and subsequent objects) be expanded (solver or exploded, whatever term you prefer). I would like the final interface to be like that:
import { BaseGetV1InputRequest } from './baseGetV1InputRequest';
export interface BaseGetV1Input {
request?: {
entity?: {
code?: 0,
id?: string
},
procedure?: string,
search?: {
type?: "starts" | "contains",
value?: string
}
},
trid: string
}
Tested solutions that don't work
I have tried to solve the $ref myself using json-schema-ref-parser but i think the codegen creates a sub-model when it finds properties inside of the input JSON.
I have also tried w/ and w/o mustache templates (that someone else got me). But the output didn't change.
I'm fairly new to OpenAPI, hope you can help me.

Related

JSON schema reference key value as the type of the field [duplicate]

I'm trying to validate json files which have an element that has a property which contains a value that should exist in another part of the json. I'm using jsonschema Draft 07.
This is a simple little example that shows the scenario I'm trying to validate in my data.
{
"objects": {
"object1": {
"colorKey": "orange"
}
},
"colors": {
"orange": {
"red": "FF",
"green": "AF",
"blue": "00"
}
}
}
How can I validate that the 'value' of colorKey (in this case 'orange') actually exists as a property of the 'colors' object? The data isn't stored in arrays, just defined properties.
For official JSON Schema...
You cannot check that a key in the data is the same as a value of the data.
You cannot extract the value of data from your JSON instance to use in your JSON Schema.
That being said, ajv, the most popular validator, implements some unofficial extensions. One of which is $data.
Example taken from: https://github.com/epoberezkin/ajv#data-reference
var ajv = new Ajv({$data: true});
var schema = {
"properties": {
"smaller": {
"type": "number",
"maximum": { "$data": "1/larger" }
},
"larger": { "type": "number" }
}
};
var validData = {
smaller: 5,
larger: 7
};
ajv.validate(schema, validData); // true
This would not work for anyone else using your schemas.

How to use Rest Template to step into a JSON object?

I have learned how to use a rest template to access a JSON array like this:
[
{
"ID": "0ae6496f-bb0b-4ebd-a094-ca766e82f3e7",
"Confirmed": 0,
}
{
"ID": "e010ced5-c7cb-4090-a7ed-206f4c482a5b",
"Confirmed": 0,
}
]
I accessed the Confirmed for example with
public Model[] getModel() {
ResponseEntity<Model[]> response = restTemplate.getForEntity(apiUrl, Model[].class);
return response.getBody();
}
but now I have to access data in another Json from another API. The data looks like this
{
"prefixes": [
{
"region": "ap-northeast-2",
"service": "AMAZON",
},
{
"region": "eu-west-3",
"service": "AMAZON",
}
]
}
How can I access region or service inside, and what would be the proper name for this?
The first is a JSON array, the second a JSON object?
The first API is simply
https://example.com
Whereas the second is
https://example.com/data.json.
You have to create the POJO for return type:
List<RegionServiceObject> items;
Where RegionServiceObject looks:
public class RegionServiceObject {
private String region;
private String service;
// constructors, getters/setters, toString()....
}
The way of deseariliseing to object is similar to which you already wrote:
RegionServiceObject[] items = restTemplate.getForObject(url, RegionServiceObject[].class);
and access for specific item will be as usual for specific item:
for (RegionServiceObject item : items) {
item.getRegion();
item.getService();
// use them here
}

convert a JSON to another w/ circe

I would like to convert this JSON
{
"l1k1": {
"l2k1": "l2v1",
"l2k2": 1
},
"l1k2": [
{
"e1l1": "e1v1",
"e1l2": "e1v2"
},
{
"e2l1": "e2v1",
"e2l2": "e2v2"
}
]
}
to this one
{
"papa": {
"l1k1c": {
"l2k1c": {
"string": "l2v1"
},
"l2k2c": {
"int": 1
}
},
"l1k2c": {
"array": [
{
"e1l1": "e1v1",
"e1l2": "e1v2"
},
{
"e2l1": "e2v1",
"e2l2": "e2v2"
}
]
}
}
}
where:
"l" stands for level
"k" for key, "v" for value
"e" for element
"c" for copy (where "*" maps to "*c")
I'm using circe's Json but having a hard time renaming the keys or creating parents or children with it. As I'm writing this, I'm thinking I may need to use its ACursor instead. As you may have guessed, I'm trying to generate an AVRO doc from an input JSON. I'm open to help w/ my approach or any suggestions about how to go about it in a cleaner way.

map json response into nested typescript object with rxjs

In my Angular2-App I´m receiving a JSON-Response via http-Request that kind of looks like that:
{
"documents": [
{
"title": "Example-Doc 1",
"versions": [
{
"fileSize": 15360
},
{
"fileSize": 2048
}
]
},
{
"title": "Example-Doc 2",
"versions": [
{
"fileSize": 15360
},
{
"fileSize": 2048
}
]
}
],
"meta": {
"total": [2]
}
}
Now i wonder how to map this structure into my TypeScript-Classes, i checked different approaches, but it never worked. I actually need the constructor of the Version class to be called.
export class Document {
title: string; // Titel des Dokuments
versions: Version[];
}
If you have complex classes that need to be serialized and deserialized, I suggest that you implement static methods to your classes like fromJson and toJson - however without knowing your classes the rest of the answer will be kind of a guess-work:
Assuming you have a fromJson in place, then you can map your data like the following:
const myDocuments: Document[] = myJson.documents.map(Document.fromJson);
And the fromJson-method could look like this:
class Document {
constructor(public title: string, public versions: Version[])
public static fromJson(json: any): Document {
return new Document(
json.title,
json.versions.map(Version.fromJson)
);
}
}
class Version {
constructor(public fileSize: number) {}
public static fromJson(json: any): Version {
return new Version(json.fileSize);
}
}

Using *ngFor with a JSON object in Angular 2

I'm trying to implement a decoupled wordpress solution and I'm having a bit of confusion displaying the JSON object properties in my template. I'm able to return JSON objects for the WP API but not sure how to handle them. The only way I can get a property to display it's value in a template is if I add a [0] to the interpolated property, which won't work in an ngFor loop. I've read the solution by #Thierry here access key and value of object using *ngFor
but this doesn't seem to be how Google handles the Tour of Heroes app http://plnkr.co/edit/WkY2YE54ShYZfzJLSkMX?p=preview
Google uses this data set:
{
"data": [
{ "id": "1", "name": "Windstorm" },
{ "id": "2", "name": "Bombasto" },
{ "id": "3", "name": "Magneta" },
{ "id": "4", "name": "Tornado" }
]
}
which looks like a JSON object to me, so how is the app able to handle something like this:
<ul>
<li *ngFor="let hero of heroes">
{{hero.name}}
</li>
</ul>
I'm just unclear if there's been a change in RC5 that allows iteration over an object, or do I still need to transform this somehow. I'm very new to Angular and could use a little guidance on this matter. Thanks!!
An update based on the comments, if I want to transform an api request like http://localhost:8888/wp-json/wp/v2/posts, what's the best method for that? My return code would look something like:
[
{
"id": 4,
"date": "2016-08-09T00:09:55",
"date_gmt": "2016-08-09T00:09:55",
"guid": {
"rendered": “http://localhost:8888/?p=4"
},
"modified": "2016-08-09T00:11:05",
"modified_gmt": "2016-08-09T00:11:05",
"slug": “wp-api-test”,
"type": "post",
"link": "http://localhost:8888/2016/08/wp-api-test”,
"title": {
"rendered": "testing the wp api"
},
"content": {
"rendered": "<p>loreum ipsum</p>\n"
},
"excerpt": {
"rendered": "<p>loreum ipsum</p>\n"
},
"author": 1,
"featured_media": 0,
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"format": "standard",
"categories": [
1
],
}
]
Without writing all the code for you, there is no short answer to what you are asking, but here are some tips:
You have to take the JSON response you are getting back and create either an interface or class in TypeScript so when you perform the POST, Angular 2 can take the JSON and convert it to an object using your classes.
JSON to TS generator: http://json2ts.com/
Ninja Tips 2 - Make your JSON typed with TypeScript - http://blog.ninja-squad.com/2016/03/15/ninja-tips-2-type-your-json-with-typescript/
TypeScript Json Mapper - http://cloudmark.github.io/Json-Mapping/
How are you defining your services?
Here's an example:
export interface IPost {
id: number;
date: Date;
date_gmt: Date;
... // rest of your defintion
}
#Injectable()
export class BlogPostService {
private http: Http;
constructor(http: Http) {
this.http = http;
}
private apiUrl: string = 'api/blog/posts.json';
getPosts(): Observable<IPost[]> {
return (this.http.get(this.apiUrl)
.map((response: Response) => <IPost[]>response.json())
.do(data => console.log('All: ' + JSON.stringify(data)))
.catch(this.handleError)) as any;
}
private handleError(error: Response) {
console.error(error);
return Observable.throw(error.json().error || "Server error");
}
}
This line should transform your json object to array[] of IPosts
.map((response: Response) => <IPost[]>response.json())
Hope that helps.
Thanks so much for the answers. They helped lead me to the solution. I was able to solve this rather simply by creating a posts array and making it equal to the Observable return. The component looks like this:
posts: {};
constructor (private _wpService: WpApiService) {}
ngOnInit() { this.getPosts() }
getPosts() {
this._wpService.getPosts()
.subscribe(
data => {
this.posts = data;
});
}
The template looks like:
<li *ngFor="let post of posts">
<h3>{{post.title.rendered}}</h3>
</li>
Just replace {{hero.name}} by {{hero.data.name}}
The best way to handle the JSON object by creating an interface class to access the data easily