MediaWiki API Extension JSON - json

I have developed a MediaWiki extension that gets a (JSON) string from an external service using cURL.
Now I'm looking for a way to retrieve just that string from the MediaWiki system. (This URL will be used for AJAX calls.)
First, I thought that MediaWiki API was the way to do that. However, I can't seem to be able to output just that string.
What would be the right way to achieve this?
UPDATE
Thank you, that did the trick. For your information, here's how far I got:
$this->getResult()->addValue(null, null, array( 'autocomplete' => array( 'server', 'servers' ) ) );
returns [{"autocomplete":["server","servers"]}] when appending format=json to the API URL. Instead of the above JSON string, the JavaScript client I'm working with needs {"autocomplete":["server","servers"]} in order to work correctly. In other words, I needed to get rid of [ and ].
Just out of curiosity, is a custom printer still the way to go?

In your API module, override getCustomPrinter():
public function getCustomPrinter() {
return new ApiFormatRaw(
$this->getMain(),
$this->getMain()->createPrinterByName( 'json' )
);
}
(the nested createPrinterByName() call is for fallback format in case of errors, you can change it to some other format)
Then, in your execute() method or wherever you need to return the value:
$this->getResult()->addValue( null, 'text', $data_you_want_to_return );
$this->getResult()->addValue( null, 'mime', 'application/json' );

Related

Error retrieving data from api call as attribute is different

Hi there I'm using a api which returns as follows
{"secret-finance":{"usd":0.04883396}}
Problem is I'm using vue and retrieving data like this
async getCurrentSefiPrice() {
await axios
.get(
"https://api.coingecko.com/api/v3/simple/price?ids=secret-finance&vs_currencies=usd"
)
.then(
(response) =>
(this.sefi_token_current_price = response.secret-finance.usd)
// console.log(response)
);
console.log(this.sefi_token_current_price);
}
But when I use secret-finance to get usd value I get an error.
Thanks in advance.
#haseebsaeed
You'll need to reference it as
response["secret-finance"].usd
You need to use key notation rather then dot notion when a key has a hyphen in it. Any key that contains characters that are not allowed in JavaScript variables you'll need to reference them as above.
A further example,
If the secret-finance object has a property key of us-dollars rather than the current one of usd, you would then access it by doing,
response["secret-finance"]["us-dollars"]

Convert data from XML to JSON React.js

Im trying to build an application that fetches data from an web API that returns XML. I want this data in JSON instead, but the API does not support that.
How do i fetch the data and convert it to JSON?
I tried to use xml2js and it seems to work, but i dont understand how to save it as an object so i can use it in my app.
async componentDidMount(){
const url = "this is where the APIurl are";
fetch(url)
.then(res => res.text())
.then(body => parseString(body, function (err, result) {
console.log(result);
})
);
}
result seems to return the data as json, but i cant figure out how to use the data as an object later.
Your best option is to use an external lib to do that. A quick search in google and I found this one https://www.npmjs.com/package/xml-js.
You should also check this question: Convert XML to JSON (and back) using Javascript
To store it on your app you should grab what you need from the parsed XML and put it on the state.

Deleting a file from a bucket

I'm trying to delete an object from a bucket. Reading the docs it all sounds super simple, but I just can't seem to get it working.
I'm following the instructions here to try and delete this object, which I can see using https://developer.api.autodesk.com/oss/v2/buckets/my-persistent-bucket/objects:
bucketKey => 'my-persistent-bucket'
objectKey => '--test2.dwg'
objectId => 'urn:adsk.objects:os.object:my-persistent-bucket/--test2.dwg'
sha1 => '477085439a60779064d91fd1971d53c77c7a163a'
size => (int) 188600
location => 'https://developer.api.autodesk.com/oss/v2/buckets/my-persistent-bucket/objects/--test2.dwg'
According to the docs we use this end point:
https://developer.api.autodesk.com/oss/v2/buckets/:bucketKey/objects/:objectName
Where
:bucketKey is url encoded 'my-persistent-bucket'
:objectName is url encoded 'urn:adsk.objects:os.object:my-persistent-bucket/--test2.dwg'
I've tried using PHP's urlencode() and the following base64 encode function:
private function _base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}
to encode the :bucketKey and :objectName but no matter how I try to encode it I always get:
404 : Object not found
Could anyone help me understand where I'm going wrong?
Thanks a lot
Of course, after I've made a SO post I find the answer.
For anyone having the same issues you must encode your :objectName, which is just the filename, in my example '--test2.dwg', using PHP's rawurlencode() function rather than urlencode().

Angular2 HTTP Providers, get a string from JSON for Amcharts

This is a slightly messy questions. Although it appears I'm asking question about amCharts, I really just trying to figure how to extract an array from HTTP request and then turn it into a variable and place it in to 3-party javacript.
It all starts here, with this question, which was kindly answered by AmCharts support.
As one can see from the plnker. The chart is working. Data for the chart is hard coded:
`var chartData = [{date: new Date(2015,2,31,0,0,0, 0),value:372.10,volume:2506100},{date: new Date(2015,3,1,0, 0, 0, 0),value:370.26,volume:2458100},{date: new Date(2015,3,2,0, 0, 0, 0),value:372.25,volume:1875300},{date: new Date(2015,3,6,0, 0, 0, 0),value:377.04,volume:3050700}];`
So we know the amCharts part works. Know where the problem is changing hard coded data to a json request so it can be dynamic. I don't think this should be tremendously difficult, but for the life of me I can't seem figure it out.
The first issue is I can't find any documentation on .map, .subscribe, or .observable.
So here is a plunker that looks very similar to the first one, however it has an http providers and injectable. It's broken, because I can't figure out how to pull the data from the service an place it into the AmCharts function. I know how pull data from a http provider and display it in template using NgFor, but I don't need it in the template (view). As you can see, I'm successful in transferring the data from the service, with the getTitle() function.
this.chart_data =_dataService.getEntries();
console.log('Does this work? '+this.chart_data);
this.title = _dataService.getTitle();
console.log('This works '+this.title);
// Transfer the http request to chartData to it can go into Amcharts
// I think this should be string?
var chartData = this.chart_data;
So the ultimate question is why can't I use a service to get data, turn that data into a variable and place it into a chart. I suspect a few clues might be in options.json as the json might not be formatted correctly? Am I declaring the correct variables? Finally, it might have something to do with observable / map?
You have a few things here. First this is a class, keep it that way. By that I mean to move the functions you have inside your constructor out of it and make them methods of your class.
Second, you have this piece of code
this.chart_data =_dataService.getEntries().subscribe((data) => {
this.chart_data = data;
});
What happens inside subscribe runs asynchronously therefore this.chart_data won't exist out of it. What you're doing here is assigning the object itself, in this case what subscribe returns, not the http response. So you can simply put your library initialization inside of the subscribe and that'll work.
_dataService.getEntries().subscribe((data) => {
if (AmCharts.isReady) {
this.createStockChart(data);
} else {
AmCharts.ready(() => this.createStockChart(data));
}
});
Now, finally you have an interesting thing. In your JSON you have your date properties contain a string with new Date inside, that's nothing but a string and your library requires (for what I tested) a Date object, so you need to parse it. The problem here is that you can't parse nor stringify by default a Date object. We need to convert that string to a Date object.
Look at this snippet code, I used eval (PLEASE DON'T DO IT YOURSELF, IS JUST FOR SHOWING PURPOSES!)
let chartData = [];
for(let i = 0; i < data[0].chart_data.length; i++) {
chartData.push({
// FOR SHOWING PURPOSES ONLY, DON'T TRY IT AT HOME
// This will parse the string to an actual Date object
date : eval(data[0].chart_data[i].date);
value : data[0].chart_data[i].value;
volume : data[0].chart_data[i].volume;
});
}
Here what I'm doing is reconstructing the array so the values are as required.
For the latter case you'll have to construct your json using (new Date('YOUR DATE')).toJSON() and you can parse it to a Date object using new Date(yourJSON) (referece Date.prototype.toJSON() - MDN). This is something you should resolve in your server side. Assuming you already solved that, your code should look as follows
// The date property in your json file should be stringified using new Date(...).toJSON()
date : new Date(data[0].chart_data[i].date);
Here's a plnkr with the evil eval. Remember, you have to send the date as a JSON from the server to your client and in your client you have to parse it to a Date.
I hope this helps you a little bit.
If the getEntries method of DataService returns an observable, you need to subscribe on it to get data:
_dataService.getEntries().subscribe(
(data) => {
this.chart_data = data;
});
Don't forget that data are received asynchronously from an HTTP call. The http.get method returns an observable (something "similar" to promise) will receive the data in the future. But when the getEntries method returns the data aren't there yet...
The getTitle is a synchronous method so you can call it the way you did.

MediaType should be application/schema+json to validate schema

I'm using justinrainbow/json-schema class to validate data against a schema.
However I'm receiving this error:
Media type application/schema+json expected
I could try to change ContentType in nginx for all my json files, but it doesn't make sense.
Another way would be to change the constant inside the library to 'application/json' (as my server is delivering for json files). Again, is not ok to change the source.
Is there a way to pass this as a parameter to justinrainbow/json-schema class?
https://github.com/justinrainbow/json-schema
I couldn't find a solution for this because there is no content-type on the web as schema+json.
Just replace in justinrainbow/json-schema/src/JsonSchema/Validator.php the SCHEMA_MEDIA_TYPE to 'application/json'.
You can also serve the file by local path, not by url.
Now the library supports "json/application" additionally, but it throws an error at other content types.
To avoid this, you can extend the default "JsonSchema\Uri\UriRetriever" and override "confirmMediaType()":
class MyUriRetriever extends JsonSchema\Uri\UriRetriever {
public function confirmMediaType($uriRetriever, $uri) {
return;
}
}
$retriever = new \MyUriRetriever();
$refResolver = new JsonSchema\SchemaStorage($retriever);
$schema = $refResolver->resolveRef($schema);
$validator = new JsonSchema\Validator(new JsonSchema\Constraints\Factory($refResolver));
$validator->check($data, $schema);
$data: json decoded response from API
$schema: url of the schema
I had the same issue many times when testing other party`s API against their schema. Often they do not send the correct "Content-Type" header for their schemas and it can take long for them to change it.
Update: Ability to exclude endpoints from validation
You can use UriRetriever:addInvalidContentTypeEndpoint():
$retriever = new UriRetriever();
$retriever->addInvalidContentTypeEndpoint('http://example.com/car/list');