Make HTTP requests from plugins

Regular webpages opened in Chrome don’t get access to the file system, while obsidian plugins can use the javascript fs module for local files. I thought that something similar is available for web requests.

1 Like

If you are okay with your plugin only working in the desktop you can use the package node-fetch. GitHub - node-fetch/node-fetch: A light-weight module that brings the Fetch API to Node.js node’s libraries bypass cors restrictions but are only available in the desktop apps.

4 Likes

Hi,

I have a similar problem. I want to implement a CalDav Client Plugin and get the same error.

I try to implement a middleware with express and the cores package, but it doesn’t work. Can someone give me please a code example, a tutorial or a link to the Glichßs express server?

Thanks
Kantiran

You can overcome this by using node.js’ http/https module instead of fetch (or use a convenience module like request). It doesn’t have the same limitations.

require('request')('http://example.com/', (error, response, body) => {
    console.log(JSON.parse(body));
});
2 Likes

I want to get google books API data, but I’m running into this same CORs policy issue. @intellectronica, I don’t think your solution works for me, at least while trying in the dev console. Some people might have luck with this article. I haven’t got it to work yet.

I’m not working on a plugin, but I’m using a dataviewJS code block to download image data.

Hello @mjduck,

This may interest you !

It’s a script to be used inside Quickadd plugin to fetch book data from Google Books API, and then automatically create a note from a template.

You can check line 183 of the script how the request is made using request. I have not encountered CORs issues with that function.

The author of Quickadd plugin made a script to fetch movie data using OMDB API (using the same request function) which helped me a lot to write this Google Books API script.

1 Like

Well that’s neat. Thanks @JamesKF !

1 Like

In plugin you should import requestUrl function provided by obsidian package, see the declaration at obsidian-api/obsidian.d.ts at c01fc3074deeb3dfc6ee02546d113b448735b294 · obsidianmd/obsidian-api · GitHub

4 Likes

Is this usable from within a Templater template or DataviewJS? That is, is it usable within arbitrary JS executing within an Obsidian plugin?

Asking as something of a node/TS newbie but experienced developer. I assume that this depends on what sort of library search paths are available from within the environment provided at runtime by these respective plugins?

1 Like

DataviewJS and Templater have access to most functions.
These included.
You can check by opening the Console in the Developer tools, and see if it shows up.

The one thing they can’t do is anything related to event handling.

1 Like

So how would a basic dataviewjs codeblock look that incorporates such a requestUrl call? How would the response be handled inside such a dataviewjs codeblock?
Imagine the request I want to use returns a JSON string which contains data/numbers I want to see in a table (or even visualize with the Obsidian Charts plugin)?

As a quick example:
One of my notes has a weather forecast embedded that uses DVJS

Here is a part of it

const headers = {
"Authorization": "Bearer whatever"
}

const forecast = await requestUrl({url: "https://weatherapi/forecast", headers})

dv.table(["Datum", "Icon", "Beschreibung", "Min", "Max", "Regen", "Luftfeuchtigkeit"], forecast.json.map(day => {
return [
	dv.date(day.date).day + ".",
	"![icon|50](" + day.icon + ")",
	day.description,
	day.temperature_min + "°C",
	day.temperature_max + "°C",
	day.probability_of_precipitation + "%",
	day.humidity + "%"
]}))

The data returned by that API looks like this:

[
    {
        "date": "2022-06-26T11:00:00Z",
        "sunrise": "2022-06-26T02:55:38Z",
        "sunset": "2022-06-26T20:00:30Z",
        "temperature_day": 19.19,
        "temperature_night": 18.76,
        "temperature_min": 18.3,
        "temperature_max": 21.55,
        "feels_like_day": 19.38,
        "feels_like_night": 18.65,
        "pressure": 1016,
        "humidity": 85,
        "dew_point": 16.65,
        "uvi": 6.26,
        "clouds": 100,
        "visibility": 0,
        "wind_speed": 7.47,
        "wind_degree": 0,
        "description": "Leichter Regen",
        "icon": "icon_url_here",
        "probability_of_precipitation": 0.5
    },
....
]

2 Likes

Awesome, @joethei, I guess this helps a lot! Will dive into this, asap! :star_struck:
Thanks a lot!!! :pray:

I am using requestUrl to avoid this issue but it seems that I am getting an issue anyway. Error thrown:

{
“status”:400,
“headers”:{
“vary”:“Origin, Access-Control-Request-Method, Access-Control-Request-Headers”,
“x-content-type-options”:“nosniff”,
“x-frame-options”:“DENY”,
“x-xss-protection”:“1; mode=block”
}
}

Anyone got any ideas?

You’d have to post the request code for anyone to give any hints.

HTTP status 400 “indicates that the server cannot or will not process the request due to something that is perceived to be a client error (for example, malformed request syntax”.

So it sounds like the code to create the request is invalid.

I do apologise, first time posting here … not something I am used to doing :slight_smile:

Here is the code, it’s a pretty simple call:

const options: RequestUrlParam = {
    url: url,
    method: 'POST',
    headers: {
        'X-Api-Key': this.settings.apiToken,
        'Content-Type': 'application/json'
    },
    body: json
}


var response: RequestUrlResponse;

try
{
    response = await requestUrl(options);

    return response.text;
}
catch(e) {
    console.log(JSON.stringify(e);
}

I captured the actual request and sent it to the server (headers and all) using Postman (just to check that what I am sending is valid) and the server accepted it no problem.

I can’t actually see anything of my call appearing in the Network tab of Developer Tools. I can see other traffic but nothing on this call. All seems a bit weird but I am very new to this so hoping someone can spot something obvious.

It might also be worth (or not) pointing out that it is throwing an error rather than returning the status via the response.

You’ll need to stringify that JSON first I believe. Postman is probably handling that for you.

Is there a current best practice for making HTTP requests from plugins avoiding CORS ? I haven’t found any official documentation on it and at least one of the packages mentioned as a possibility is now deprecated. This seems like it would be common enough of a desire that there would be some documentation.

You can use this function from the official docs:

Request a URL using HTTP/HTTPS, without any CORS restrictions.

1 Like

Thanks! I dunno how that didn’t show up in my searching. That is exactly what I am looking for : )

1 Like