I was going through electron js but the problem that I'm facing is in writing restful API. There are hardly any resources that show utilization of API without react.js, express and falcon vue.js. I wrote python API to add two numbers just for testing but I'm clueless about how to consume those restful API in electron without any other language such as react/express/falcon as it would increase my learning curve.
Help appreciated.
note: My API is hosted
There are two built-in methods that you can use instead of using frameworks like axios, jQuery Ajax, ...
Fetch:
Using Fetch API is really simple. Just pass the URL, the path to the resource you want to fetch, to fetch() method.
simple GET method:
//simple GET method
fetch('/js/users.json')
.then(response => {
// handle response data
})
.catch(err => {
// handle errors
});
other methods like POST, DELETE,...:
// some data to post
const user = {
first_name: 'John',
last_name: 'Lilly',
job_title: 'Software Engineer'
};
// options of fetch
const options = {
method: 'POST',
body: JSON.stringify(user),
headers: {
'Content-Type': 'application/json'
}
}
fetch('https://reqres.in/api/users', options)
.then(response => {
// handle response data
})
.catch(err => {
// handle errors
});
XML HttpRequest:
XMLHttpRequest is a built-in browser object that allows to make HTTP requests in JavaScript.
Create XMLHttpRequest:
let xhr = new XMLHttpRequest();
Initialize it, usually right after new XMLHttpRequest:
xhr.open(method, URL, [async, user, password])
method – HTTP-method. Usually "GET" or "POST".
URL – the URL to request, a string, can be URL object.
async – if explicitly set to false, then the request is synchronous, we’ll cover that a bit later.
user, password – login and password for basic HTTP auth (if required).
Send it out.
xhr.send([body])
This method opens the connection and sends the request to server. The optional
body parameter contains the request body.
Some request methods like GET do not have a body. And some of them like POST
use body to send the data to the server. We’ll see examples of that later.
Listen to xhr events for response.
These three events are the most widely used:
load – when the request is complete (even if HTTP status is like 400 or 500), and the response is fully downloaded.
error – when the request couldn’t be made, e.g. network down or invalid URL.
progress – triggers periodically while the response is being downloaded, reports how much has been downloaded.
xhr.onload = function() {
alert(`Loaded: ${xhr.status} ${xhr.response}`);
};
xhr.onerror = function() { // only triggers if the request couldn't be
made at all
alert(`Network Error`);
};
xhr.onprogress = function(event) { // triggers periodically
// event.loaded - how many bytes downloaded
// event.lengthComputable = true if the server sent Content-Length
// header
// event.total - total number of bytes (if lengthComputable)
alert(`Received ${event.loaded} of ${event.total}`);
};
Related
I'm trying to figure out how to send an image to my API, and also verify a generated token that is in the header of the request.
So far this is where I'm at:
#app.post("/endreProfilbilde")
async def endreProfilbilde(request: Request,file: UploadFile = File(...)):
token=request.headers.get('token')
print(token)
print(file.filename)
I have another function that triggers the change listener and upload function, passing the parameter: bildeFila
function lastOpp(bildeFila) {
var myHeaders = new Headers();
let data = new FormData();
data.append('file',bildeFila)
myHeaders.append('token', 'SOMEDATAHERE');
myHeaders.append('Content-Type','image/*');
let myInit = {
method: 'POST',
headers: myHeaders,
cache: 'default',
body: data,
};
var myRequest = new Request('http://127.0.0.1:8000/endreProfilbilde', myInit);
fetch(myRequest)//more stuff here, but it's irrelevant for the Q
}
The Problem:
This will print the filename of the uploaded file, but the token isn't passed and is printed as None. I suspect this may be due to the content-type, or that I'm trying to force FastAPI to do something that is not meant to be doing.
As per the documentation:
Warning: When using FormData to submit POST requests using XMLHttpRequest or the Fetch_API with the
multipart/form-data Content-Type (e.g. when uploading Files and
Blobs to the server), do not explicitly set the Content-Type
header on the request. Doing so will prevent the browser from being
able to set the Content-Type header with the boundary expression
it will use to delimit form fields in the request body.
Hence, you should remove the Content-Type header from your code. The same applies to sending requests through Python Requests, as described here and here. Read more about the boundary in multipart/form-data.
Working examples on how to upload file(s) using FastAPI in the backend and Fetch API in the frontend can be found here, here, as well as here and here.
So I figured this one out thanks to a helpful lad in Python's Discord server.
function lastOpp(bildeFila) {
let data = new FormData();
data.append('file',bildeFila)
data.append('token','SOMETOKENINFO')
}
#app.post("/endreProfilbilde")
async def endreProfilbilde(token: str = Form(...),file: UploadFile = File(...)):
print(file.filename)
print(token)
Sending the string value as part of the formData rather than as a header lets me grab the parameter.
I am currently learning about Threads in Java. I wanted to know what the standard protocol would be when making Http Requests in Java that would be similar to the code I have below, which uses Javascript Fetch API and asynchronous programming. For example, if I was using the Fetch API in Javascript to first make a GET request to grab some data from a REST endpoint that I would later use to make a POST request (as seen in the code below), I would need to use a Callback function or Promise (like below) to wait until that first request has retrieved its data for the second request to then proceed. Obviously, if I did not use Promises or nest the second Http POST in the first Fetch method (GET) below, and wrote two separate Fetch API calls (one for GET, one for POST, sequentially one after other aka top-to-bottom), both calls would "fire-off" simultaneously and the second POST request wouldn't have the data it needs to make a successful POST.
const myHttpGETandPOSTmethod = () => {
// First Http request goes here
fetch('http://example.com/movies.json', {
method: 'GET',
headers: // Some headers here,
})
.then(response => response.json())
.then(data => {
console.log(data))
// Nest the second Http request inside here. It only runs after 1st request completes
return fetch('http://example.com/movies.json', {
method: 'POST',
headers: // Some headers here,
body: JSON.stringify(body);
})
.then((response) => response.json())
.then((data) => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});
})
}
So then, if I were using something like the Apache HttpClient https://hc.apache.org/httpcomponents-client-4.5.x/quickstart.html library in Java, would the standard procedure be to "spin-up" another Thread (besides the main thread) to execute the GET request and then do a thread.join() such that after the first thread completes, then the second request can fire-off its own Thread?
Would I need to use a Callable instead of Runnable so that I can save the HttpEntity data response of the first GET request?
I guess I'm just trying to understand the best way to implement the scenario I posed above regarding an HTTP GET request that is needed to make a subsequent POST request, while both fires asynchronously such that they do not block the main thread.
You can make a basic GET request using the apache Http Library as such (POST is also very similar):
CloseableHttpClient httpclient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://targethost/homepage");
CloseableHttpResponse response1 = httpclient.execute(httpGet);
try {
System.out.println(response1.getStatusLine());
HttpEntity entity1 = response1.getEntity();
// Save the response body to a string
String body = EntityUtils.toString(entity1, StandardCharsets.UTF_8);
System.out.println(body);
EntityUtils.consume(entity1);
} finally {
response1.close();
}
Or am I on the wrong approach here and looking at this incorrectly? I believe the Http library in Apache offers both synchronous and asynchronous Http calls? or should I be using a newer library for Http in Java?
I want to know if it is possible to open a browser with header authentication by Javascript?
I can assign header to the request in Postman when calling API.
But I can't find if it is reasonable to expect browser can do the same thing?
If yes, any example to trigger the browser with authentication header?
Thanks
Assuming you can get the browser to load a page that runs JavaScript then you can execute follow-on API calls and attach headers to them. There are a variety of frameworks available or you can use the ES6 Fetch API that runs fine in most modern browsers.
Ref Fetch Docs:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
Ref Headers specifically for Fetch:
https://developer.mozilla.org/en-US/docs/Web/API/Headers
Users could use a local file on their machine which has the script to fetch the data... or you could have users hit an endpoint that requires no authentication and merely serves to host up the page that has the API calls, gathers their credentials and then requests the authenticated data from the protected endpoints.
const myHeaders = new Headers();
myHeaders.set('Authentication', 'basic <insert base64 encoded basic auth string>');
const url = 'https://www.example.com/api/content';
const requestObj = {
method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default'
};
const myRequest = new Request(url, requestObj);
fetch(myRequest)
.then(response => response.json())
.then(jsonObj => {
//do stuff with whatever was returned in the json object
});
If you have an older browser that doesn't support JavaScript at the ES6 version or later, then you can revert to the older XMLHttpRequest.
Ref XMLHttpRequest Docs:
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
var url = 'https://www.example.com/api/content';
var getRequest = new XMLHttpRequest();
getRequest.open('GET', url, false);
getRequest.setRequestHeader("Authentication", ''basic <insert base64 encoded basic auth string>'');
getRequest.send(null);
if (getRequest.status == 200){
var textData = req.responseText;
// do stuff with the response data
}
That is a VERY basic use case for XMLHttpRequest... you should definitely read the docs on setting it up to use call back functions instead of operating synchronously as in the example above. But this should give you enough detail to move forward
I'm using VueJS for an app I am building. The server I have is written in Golang and has been set to accept CORS. In the app, in one of my components, searchBar, I have set it to fetch some data before it is created.
var searchBar = {
prop: [...],
data: function() {
return { ... };
},
beforeCreate: function() {
var searchBar = this;
axios.request({
url: '/graphql',
method: 'post',
data: {
'query': '{courses{id, name}}'
}
})
.then(function(response) {
searchBar.courses = response.data.data.courses;
});
},
methods: { ... },
template: `...`
};
Axios works perfectly here. It gets the data I need. searchBar has a button which causes it to emit an event which is then picked up by another component, searchResults. Upon receiving the event, searchResults will fetch some data.
var searchResults = {
data: function() {
return { ... }
},
mounted: function() {
var sr = this;
this.$bus.$on('poll-server', function(payload) {
var requestData = {
url: '/graphql',
method: 'post',
data: { ... },
...
};
...
axios.request(requestData)
.then(function(response) {
console.log(response);
}
);
});
},
template: `...`
};
Note that my Axios request call is now inside a callback function. When this call is performed, I receive a CORS error:
Access to XMLHttpRequest at 'http://127.0.0.1:9000/graphql' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
My server is located at http://127.0.0.1:9000, with the client in http://127.0.0.1:8080. Here is the content of the OPTIONS request of the second request call.
For comparison, here is the request header of the first request call (that works!).
I have already set my Golang server to support CORS via go-chi/cors. This is how set it up.
router := chi.NewRouter()
...
// Enable CORS.
cors := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
AllowedMethods: []string{"POST", "OPTIONS"},
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
ExposedHeaders: []string{"Link"},
AllowCredentials: true,
MaxAge: 300,
})
router.Use(
render.SetContentType(render.ContentTypeJSON),
middleware.Logger,
middleware.DefaultCompress,
middleware.StripSlashes,
middleware.Recoverer,
cors.Handler,
)
router.Post("/graphql", gqlServer.GraphQL())
return router, db
What is causing the error I am having and how can it be solved?
This CORS error is expected. The CORS plugin you are using does request filtering for you. If you look at the list of allowed headers, you can see it's missing the header called snb-user-gps-location that you are trying to send in your axios call.
Either add that header to the allowed list, or don't send it from the front end.
I still suspect the go-chi CORS setup. I would suggest looking at setting up CORS by hand. It's not that difficult. This page will get a basic setup: https://flaviocopes.com/golang-enable-cors/
If that works with your nested API setup, we can then work backwards to determine the go-chi config issue.
Update:
I would also investigate the other middleware steps - commenting out all non-essential ones.
Middleware handlers normally inspect the r *http.Request or write headers to the w http.ResponseWriter and then the final handler will write to the response body. But throughout the middleware chain the following header/body write flow should look like one of these two flows:
Success:
w.Header().Set(...) // headers
w.Write(...) // body
Note the above flow will issue an implicit http status code write, to keep headers appearing first and body second:
w.Header().Set(...) // headers
w.WriteHeader(http.StatusOK) // implicit success http status code
w.Write(...) // body
Failure:
In the event of reporting a runtime error, the flow should be:
w.Header().Set(...) // headers
w.WriteHeader(http.StatusInternalServerError) // some unrecoverable error
w.Write(...) // optional body
The reason I bring this up, I've seen 3 types of bugs which mess up this flow:
bad middleware handlers write headers after the body causing client confusion
calling http.Error thinking that stops the API dead - instead of returning immediately after the http.Error and ensuring no subsequent middleware handlers are called
write the same header twice. Rewriting headers in a subsequent handler will cause the client to see the last version (thus clobbering any previous versions)
So to fully trace things, I would log.Println all header/body writes for your API to ensure the above flow is correct and no intended values are being overwritten.
Specifically I am interested in changing all responses with code 403 to code 404, and changing all responses with code 301 to 302. I do not want any other part of the response to change, except the status text (which I want to be empty). Below is my own attempt at this:
addEventListener("fetch", event => {
event.respondWith(fetchAndModify(event.request));
});
async function fetchAndModify(request) {
// Send the request on to the origin server.
const response = await fetch(request);
const body = await response.body
newStatus = response.status
if (response.status == 403) {
newStatus = 404
} else if (response.status == 301) {
newStatus = 302
}
// Return modified response.
return new Response(body, {
status: newStatus,
statusText: "",
headers: response.headers
});
}
I have confirmed that this code works. I would like to know if there is any possibility at all that this overwrites part of the response other than the status code or text, and if so, how can I avoid that? If this goes against certain best practices of Cloudflare workers or javascript, please describe which ones and why.
You've stumbled on a real problem with the Fetch API spec as it is written today.
As of now, status, statusText, and headers are the only standard properties of Response's init structure. However, there's no guarantee that they will remain the only properties forever, and no guarantee that an implementation doesn't provide additional non-standard or not-yet-standard properties.
In fact, Cloudflare Workers today implements a non-standard property: webSocket, which is used to implement WebSocket proxying. This property is present if the request passed to fetch() was a WebSocket initiation request and the origin server completed a WebSocket handshake. In this case, if you drop the webSocket field from the Response, WebSocket proxying will break -- which may or may not matter to you.
Unfortunately, the standard does not specify any good way to rewrite a single property of a Response without potentially dropping unanticipated properties. This differs from Request objects, which do offer a (somewhat awkward) way to do such rewrites: Request's constructor can take another Request object as the first parameter, in which case the second parameter specifies only the properties to modify. Alternately, to modify only the URL, you can pass the URL as the first parameter and a Request object as the second parameter. This works because a Request object happens to be the same "shape" as the constructor's initializer structure (it's unclear if the spec authors intended this or if it was a happy accident). Exmaples:
// change URL
request = new Request(newUrl, request);
// change method (or any other property)
request = new Request(request, {method: "GET"});
But for Response, you cannot pass an existing Response object as the first parameter to Response's constructor. There are straightforward ways to modify the body and headers:
// change response body
response = new Response(newBody, response);
// change response headers
// Making a copy of a Response object makes headers mutable.
response = new Response(response.body, response);
response.headers.set("Foo", "bar");
But if you want to modify status... well, there's a trick you can do, but it's not pretty:
// Create an initializer by copying the Response's enumerable fields
// into a new object.
let init = {...response};
// Modify it.
init.status = 404;
init.statusText = "Not Found";
// Work around a bug where `webSocket` is `null` but needs to be `undefined`.
// (Sorry, I only just noticed this when testing this answer! We'll fix this
// in the future.)
init.webSocket = init.webSocket || undefined;
// Create a new Response.
response = new Response(response.body, init);
But, ugh, that sure was ugly.
I have proposed improvements to the Fetch API to solve this, but I haven't yet had time to follow through on them. :(