Angular 2 RC 5 Attempting to Get and Display a PDF from a Server - pdf

I am trying to display a PDF that is generated from a server onto a view in my Angular 2 RC 5 project. Right now, the ASPNETCORE server is returning the object as an 'application/pdf' and the Angular client is trying to parse the response as a blob. However, I get the following error on the client side:
Error: The request body isn't either a blob or an array buffer
The code that I'm using to call the PDF server is essentially:
getHeaders() : Headers {
var headers = new Headers({
'responseType': 'application/blob'
});
return headers;
}
getBlob() {
return this.http.get(uri, new RequestOptions({headers: this.getHeaders()}, body: "" }))
.map(response => (<Response>response).blob());
}

Try to set the responseType to Blob, it should work:
getBlob() {
return this.http.get(uri, {responseType: ResponseContentType.Blob})
.map(response => (<Response>response).blob());
}

Work's for me :
Component :
downloadInvoice(invoice) {
this.loading = true;
this.invoiceDataService
.downloadInvoice(invoice)
.subscribe(
(blob) => {
FileSaver.saveAs(blob, 'test.pdf');
},
error => this.error = error,
() => {
this.loading = false;
console.log('downloadInvoices : Request Complete')
}
)
}
Data service :
downloadInvoice(invoice): Observable<Blob> {
return this.api.downloadInvoice(invoice);
}
Api service :
downloadInvoice(invoice: Invoice): Observable<Blob> {
return this.authHttp
.get(this.apiBase + '/invoices/' + invoice.hashid + '/download', {responseType: ResponseContentType.Blob})
.map(response => {
return new Blob([response.blob()], {type: 'application/pdf'});
})
.catch(this.handleError.bind(this));
}
Enjoy :)

For Angular 5, ResponseContentType has been deprecated, so a current solution I found was to use:
getFile(): Observable<File> {
let options = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
responseType: 'blob' as 'json'
};
return this.http.get<File>(uri, options);
}

Related

ReactNative: uploading image file to server using Axios is not working

I am building a mobile application using ReactNative. My app needs to upload image file to the server. I am using Axios for that. But the file is always empty on the server-side.
This is my code.
const makeMultipartFormDataRequest = async ({
path,
data = null,
headers = null
}) => {
let accessToken = await getAccessToken();
if (accessToken) {
if (headers == null) {
headers = {
'Authorization': `Bearer ${accessToken}`
}
} else {
headers.Authorization = `Bearer ${accessToken}`;
}
}
let formData = new FormData();
if (data) {
for (let prop in data) {
let field = null;
if (typeof data[prop] == "object" && data[prop]?.mime) {
field = {
uri: data[prop].uri,
name: data[prop].name,
type: data[prop].mime
}
} else {
field = data[prop];
}
// here image file is added proof_file field
formData.append(prop, field);
}
}
let url = config.apiEndpoint + path;
return axios.post(url, formData, {
headers: headers
});
}
As you see in the code, I put a comment where I put the file into the request. When I log the value in the console, I got this.
{"name": "IMG_0003.JPG", "type": "image/jpeg", "uri": "/Users/waihein/Library/Developer/CoreSimulator/Devices/ED2E89F7-F8C9-498E-9B80-41E13814A480/data/Containers/Data/Application/6AEBDAD9-A84C-4B33-95E5-0180F09B1AD5/tmp/react-native-image-crop-picker/E3B07A1B-B79D-43A0-A649-E05F8500783B.jpg"}
But the file is never sent in the request. What is wrong with my code and how can I fix it?
As you are sending form data you should specify that in the content type. Something like this,
headers: { "Content-Type": "multipart/form-data" }

Firebase Cloud Functions Call : error : Object message : "Bad Request" status : "INVALID_ARGUMENT"

first of all i am working with react-native
i wanted to use Custom Claims on my project since it seems to fit the role distribution i expect to use on my app.
after setting my app following the documentation i succeed on creating some functions
but, here's the thing, when i try to call a function by fetching the endpoint i always get this error :
in the console
error
:
Object
message
:
"Bad Request"
status
:
"INVALID_ARGUMENT"
in firebase console
addAdminRoleTest Request body is missing data. { email: 'dev#test.com' }
i couldn't find any answer to that except that i send wrong information from my fetch but i don't understand why.
i even tried to simplify my function only to get the data i sent but i had the exact same error
find below my cloud function & the calling method :
functions/index.js
exports.addAdminRole = functions.https.onCall((data, context) => {
// get user
return admin.auth().getUserByEmail(data.email).then(user => {
// if not already (admin)
if(user.customClaims && (user.customClaims).admin === true) {
return;
}
// add custom claim (admin)
return admin.auth().setCustomUserClaims(user.uid, {
admin: true
});
}).then(() => {
return {
message: `Bravo : ${data.email} fait partie de l'équipe Admins`
}
}).catch(err => {
return err;
});
});
simplified function :
exports.addAdminRoleTest = functions.https.onCall(data => {
console.log("parse data : "+JSON.parse(data));
return (
JSON.parse(data)
);
});
adminScreen.js
function httpAddAdminRole() {
const initRequest = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify({
email: 'dev#test.com'
})
}
console.log(initRequest);
return fetch('https://us-central1-my-project.cloudfunctions.net/addAdminRole', initRequest)
.catch(err => console.log(err))
.then(res => res.json())
.then(parsedRes => {
console.log(parsedRes);
});
}
in the end this was mostly json knowledge that missed me
my body should have data included
here's the answer i came to :
functions/index.js
exports.addAdminRole = functions.https.onCall((data, context) => {
const dataParsed = JSON.parse(data);
// get user
return admin.auth().getUserByEmail(dataParsed.email).then(user => {
// if not already (admin)
if(user.customClaims && (user.customClaims).admin === true) {
console.log(dataParsed.email + " is already an Admin");
return;
}
// add custom claim (admin)
return admin.auth().setCustomUserClaims(user.uid, {
admin: true
});
}).then(() => {
return {
message: `Bravo : ${dataParsed.email} is now an Admin`
}
}).catch(err => {
return err;
});
});
adminScreen.js
function httpAddAdminRole(mail) {
const initRequest = {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body:JSON.stringify({
data:JSON.stringify({
email: mail
})
})
}
console.log(initRequest);
return fetch('https://us-central1-my-project.cloudfunctions.net/addAdminRole', initRequest)
.catch(err => console.log(err))
.then(res => res.json())
.then(parsedRes => {
console.log(parsedRes);
});
}

Api call is not happening while calling Http Request using HttpClient in angular 7

I am converting a post API request written in javascript to typescript, but my new code seems to be not running as i do not see any network calls in the debugger. Please find my code snippets below.
javascript (working)
private resourcesAccessable(url, token, clientId, resources) {
var request = new XMLHttpRequest();
request.open('POST', url, false);
request.setRequestHeader("Authorization", "Bearer " + token);
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
console.log(request);
var response ;
request.onreadystatechange = function () {
if (request.readyState == 4) {
var status = request.status;
if (status >= 200 && status < 300) {
response = JSON.parse(request.responseText);
} else if (status == 403) {
console.log('Authorization request was denied by the server.');
return null;
} else {
console.log('Could not obtain authorization data from server.');
return null;
}
}
}
var params = "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&response_mode=permissions&audience="+clientId;
if(Array.isArray(resources)){
for (var i = 0; i < resources.length; i++) {
params = params+"&permission="+resources[i]
}
}
request.send(params);
console.log(response);
return response;
}
typescript (not working)
resourcesAccessable(url, token, clientId, resources) {
private http: HttpClient,
private payload
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token
})
};
this.payload = new URLSearchParams();
this.payload.set('grant_type','urn:ietf:params:oauth:grant-type:uma-ticket');
this.payload.set('response_mode','permissions');
this.payload.set('audience', clientId);
this.payload.set('permission',resources);
return this.http.post(url, payload.toString(), httpOptions)
.pipe(
tap(
(data) => {
console.log('----->>>', data);
}
)
), error => {
console.log('error ' + JSON.stringify(error));
};
}
I have tried many things to run the above code but none of them worked for me.
Split your code into the following sections. Angular/RxJS is different from vanilla JavaScript. You create Observable http calls which the Subscriber then reads from.
Inject HttpClient into your class -- necessary for http calls to work. (Needs additional dependencies to work. Please refer https://angular.io/guide/http)
constructor(protected http: HttpClient) {}
Function Definition
resourcesAccessable(url, token, clientId, resources): Observable<any> {
const payload = new URLSearchParams()
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + token
})
}
payload.set('grant_type', 'urn:ietf:params:oauth:grant-type:uma-ticket')
payload.set('response_mode', 'permissions')
payload.set('audience', clientId)
payload.set('permission', resources)
return this.http.post(url, payload.toString(), httpOptions)
}
Function Call
this.resourcesAccessable('', '', '', '')
.subscribe(
(data) => {
console.log('----->>>', data);
}
, error => {
console.log('error ' + JSON.stringify(error));
},
() => console.log('Completed'));

Convert byte array into blob (pdf file) and download using angular 5

I'm receiving a byte array from server side and has converted it successfully to blob. However, when I'm trying to download it, it shows the file is corrupted. Below are my codes -
// In client side controller
this.contractsService.downloadPdf(id)
.then((result) => {
var blob = new Blob([result], { type: "application/pdf" });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "testing.pdf";
link.click();
});
And,
// In client side service
private headers = new HttpHeaders({ 'Content-Type': 'application/json' });
downloadPdf(id: number) {
return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers })
.map((res: any) => res)
.toPromise();
}
Any sort of help will be very much appreciated.
Thank you.
Install file-saver
npm i --save file-saver#latest
Your service method
downloadPdf(id: number) {
return this.http
.get(this.apiRoutes.download + "/" + id, { responseType:'blob' })
.toPromise();
}
Now in your component
import { saveAs } from 'file-saver'
this.contractsService.downloadPdf(id)
.then(blob=> {
saveAs(blob, 'testing.pdf');
});
This should do the trick. The HttpClient will now extract the file from the stream. Also have a look in the documentation for blobs with the HttpClient.
In client side service, try explicitly setting the response type of the get request:
downloadPdf(id: number) {
return this.http.get(this.apiRoutes.download + "/" + id, { headers: this.headers; responseType: 'arraybuffer' })
.map((res: any) => res)
.toPromise();
}

Create a new script tag (Shopify) Error: Invalid URI "/"

Based on this tutorial, I tried the below code. I'm trying to add a new script to the web page.
request.post(accessTokenRequestUrl, {
json: accessTokenPayload
})
.then((accessTokenResponse) => {
const accessToken = accessTokenResponse.access_token;
// DONE: Use access token to make API call to 'shop' endpoint
const shopRequestUrl = 'https://' + shop + '/admin/shop.json';
const shopRequestHeaders = {
'X-Shopify-Access-Token': accessToken,
'Content-Type': 'application/json'
};
const createScriptTagUrl = 'https://' + shop + '/admin/script_tags.json';
const scriptTagBody = {
"script_tag": {
"event": "onload",
"src": "https:\/\/djavaskripped.org\/fancy.js"
}
}
request.get(shopRequestUrl, {
headers: shopRequestHeaders
})
.then((shopResponse) => {
res.status(200).end(shopResponse);
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
request.post(createScriptTagUrl, {
json: scriptTagBody
}, {
headers: shopRequestHeaders
})
.then((scriptResponse) => {
res.status(200).end(scriptResponse);
})
.catch((error) => {
res.status(error.statusCode).send(error.error.error_description);
});
However, I get RequestError: Error: Invalid URI "/"
Am I missing anything? Or is the src value is having some problem?
I think you are using get method to create the script tag instead of post. Please use post method and also remove \ from the src.
Thanks
Fixed using the below code. Basically, the request body was supposed to be sent as JSON.
request.post({
url: createScriptTagUrl,
body: scriptTagBody,
headers: shopRequestHeaders,
json: true
}, function(error, response, body) {
if (!error) {
console.log(body)
}
});