I am currently developing a proof-of-concept REST api app with Deno and I have a problem with my post method (getAll et get working). The body of my request does not contain data sent with Insomnia.
My method :
addQuote: async ({ request, response }: { request: any; response: any }) => {
const body = await request.body();
if (!request.hasBody) {
response.status = 400;
response.body = { message: "No data provided" };
return;
}
let newQuote: Quote = {
id: v4.generate(),
philosophy: body.value.philosophy,
author: body.value.author,
quote: body.value.quote,
};
quotes.push(newQuote);
response.body = newQuote;
},
Request :
Response :
I put Content-Type - application/json in the header.
If I return only body.value, it's empty.
Thanks for help !
Since value type is promise we have to resolve before accessing value.
Try this:
addQuote: async ({ request, response }: { request: any; response: any }) => {
const body = await request.body(); //Returns { type: "json", value: Promise { <pending> } }
if (!request.hasBody) {
response.status = 400;
response.body = { message: "No data provided" };
return;
}
const values = await body.value;
let newQuote: Quote = {
id: v4.generate(),
philosophy: values.philosophy,
author: values.author,
quote: values.quote,
};
quotes.push(newQuote);
response.body = newQuote;
}
Related
I have migrated a piece of code to be able to export data as excel file in angular.
I assume the fact that the json is well formed and send from the server to the angular side. I can see it in the network frame in th browser.
For small json, it's ok but when the size of the json starts to be large, the answer still failed.
This following code corresponding to the service call
exportSynthesis(recordId: number, moduleId: number) {
const body = null;
return this.http.post(this.apiUrl + `/data`
+ `${recordId}/module/${moduleId}`, body,
{
headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
observe: 'response', responseType: 'json' }).pipe(
map((resp: any) => {
return resp.body;
}));
}
and here, its the method which manages the return.
exportSynthesis() {
this.service.exportSynthesis(this.recordId, this.moduleId)
.subscribe(
(exportResult) => { this.exportResult = exportResult; },
err => {
console.log('err:', err);
this.errorHandlerService.handleError('failed', err);
},
() => {
console.log('json:', this.exportResult);
const worksheet: XLSX.WorkSheet = XLSX.utils.json_to_sheet(this.exportResult);
const workbook: XLSX.WorkBook = { Sheets: { 'data': worksheet }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(workbook, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '(GEO) ' + this.record.label + ' - name.xlsx';
a.click();
window.URL.revokeObjectURL(url);
a.remove();
});
}
Currently, i do not manage to understand why it still finish in error and I get only "ok" in the console log.
Any idea?
regards
Angular's HttpClientModule default response is a json.
Your problem is that you try to access the body property of the HTTP response, but Angular interprets that as you trying to access the body property in the body of the response.
Remove observe and responseType from your post request and treat the response as a json. It should work.
find:
just need to use text as json
return this.http.post(this.apiUrl + `/geo/v1/synthesis/xls/record/`
+ `${recordId}/module/${moduleId}`, body,
{
headers: headers,
observe: 'response',
responseType: 'text' as 'json'}).
map((resp: any) => {
return resp.body;
});
}
I'm relatively new in this environment. I use "Ant design pro 4" with React and Typescript for a new project.
I call successful my IdentityServer 4 for a token for a login. I see my response in my Browser.
But how get the token in my code?
import { Reducer } from 'redux';
import { Effect } from 'dva';
export interface StateType {
status?: 'ok' | 'error';
jsonRes: string;
type?: string;
currentAuthority?: 'user' | 'guest' | 'admin';
}
export interface LoginModelType {
namespace: string;
state: StateType;
effects: {
login: Effect;
};
reducers: {
changeLoginStatus: Reducer<StateType>;
};
}
const Model: LoginModelType = {
namespace: 'login',
state: {
// status: undefined,
jsonRes: '',
},
effects: {
* login({ payload }, { call, put }) {
const response = yield call(accountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
},
},
reducers: {
changeLoginStatus(state, { payload }) {
return {
...state,
jsonRes: payload.json, //not work
};
},
},
};
export default Model;
EDIT:
Maybe that's helpful.
export async function accountLogin(params: LoginParamsType) {
const sendData = `grant_type=password&username=${params.userName}&password=${params.password}& ........`;
const retValue = request('https://localhost:44308/connect/token', {
method: 'POST',
data: sendData,
mode: 'no-cors',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'string',
});
return retValue;
}
use payload.json().It will read the response stream to completion and parses the response as json.
I'm sure you had it figured it out by now, but here it goes anyways
reducers: {
changeLoginStatus(state, { payload }) {
return {
...state,
jsonRes: payload.access_token, //<--this should do it
};
},
when you call const response = yield call(accountLogin, payload); it gets you the output you see in debug window.
Hope that helps.
Can any one please give an example of fetching application/octet-stream response from angular 6 httpClient. I am using the below code and it doesn't work ( I get unknown error - 401 response) -
import { saveAs } from 'file-saver';
getJobOutput() {
this.workflowService.fetchOutput(this.jobId,this.outputId).subscribe((response : any) => { // download file
var blob = new Blob([response.blob()], {type: 'application/octet-stream'});
var filename = 'file.csv';
saveAs(blob, filename);
});
}
Service is as below -
fetchOutput(jobId : string, outputId) {
var jobOutputURL = "myEnpoint";
var params = this.createHttpAuthorization(jobOutputURL,"GET");
params["format"] = "csv";
const options = {
headers: new HttpHeaders( { 'Content-Type': 'application/octet-stream',
'Accept' : 'application/octet-stream',
'Access-Control-Allow-Origin' : '*'}
)};
var endpoint = `${jobOutputURL}?oauth_consumer_key=${params["oauth_consumer_key"]}&oauth_signature_method=${params["oauth_signature_method"]}&oauth_nonce=${params["oauth_nonce"]}&oauth_timestamp=${params["oauth_timestamp"]}&oauth_version=1.0&format=${params["format"]}&oauth_signature=${params["oauth_signature"]}`;
return this.httpClient.get(endpoint, {...options, responseType: 'blob'});
}
To fetch an application/octet-stream, you have to set arraybuffer as the response type in the Angular HttpHeaders.
This is the service method:
fetchOutput(): Observable<ArrayBuffer> {
let headers = new HttpHeaders();
const options: {
headers?: HttpHeaders;
observe?: 'body';
params?: HttpParams;
reportProgress?: boolean;
responseType: 'arraybuffer';
withCredentials?: boolean;
} = {
responseType: 'arraybuffer'
};
return this.httpClient
.get('https://your-service-url.com/api/v1/your-resource', options)
.pipe(
map((file: ArrayBuffer) => {
return file;
})
);
}
This is the call to the service method and to the saveAs function:
this.yourService
.fetchOutput()
.subscribe((data: any) => {
const blob = new Blob([data], { type: 'application/octet-stream' });
const fileName = 'Your File Name.csv';
saveAs(blob, fileName);
})
As other users are suggestion: 401 Unauthorized is usually a client side error due to missing credentials.
I try to post an image with http.post from Angular6.
See below my rest service and component.
Service
setOptions(data: boolean = false, headersToSet?: any): any {
let token: string;
const headers = [];
token = JSON.parse(localStorage.getItem('SOSF_MANAGER_TOKEN'));
// AUTHORIZATION
headers['Authorization'] = 'Bearer ' + token;
headers['Content-Type'] = data ? 'multipart/form-data' : 'application/json';
// OTHER HEADERS
if (headersToSet !== undefined) {
for (const headerName of Object.keys(headersToSet)) {
headers[headerName] = headersToSet[headerName];
}
}
return { headers };
}
// POST
postDb(url: string, body: any): Observable<any> {
let options: any;
options = this.setOptions(body instanceof FormData);
url = this.url + url;
if (!(body instanceof FormData)) {
body = JSON.stringify(body);
} else {
// TO DO
}
console.log(body);
if (environment.console_log_construct) {
console.log(`POST : ${url}`);
}
return this.http.post(url, body, options).pipe(
map(response => {
return response;
}, error => {
console.error(`POST ERROR: ${url}`, error);
}));
}
Component
// Open Our formData Object
const formData = new FormData();
// Append our file to the formData object
formData.append('file', files[0]);
// POST
this.restService.postDb('files/images', formData)
.subscribe(response => {});
If I let JSON.stringify(body) when body is formData, formdata is set to {}. But if I let body like this, it throw a error 'Uncaught SyntaxError: Unexpected token o in JSON at position 1'. How can I achieve it ?
I'm trying to make an HTTP POST and then check the response to see if it fails or succeeds.
The HTTP call looks like this :
doLogin(credentials) {
var header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username=' + credentials.username + '&password=' + credentials.password;
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(
data => {
resolve(data.json());
},
error => {
resolve(error.json());
}
);
});
}
And the call of this function is the following :
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
result => {
this.data = result;
console.log(this.data);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
On Chrome console, the data is the following :
Object {status: "Login success", token: "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJjcmlzdGkiLCJ1c2VyS…blf1AzZ6KzRWQFNGXCrIeUHRG3Wrk7ZfCou135WmbVa15iYTA"}
How can I access the status in Angular 2? Because if I'm trying to access this.data.status, it's not working.
Should I create a class with the status and token properties?
To answer your question, you can use the response.okboolean that's available in the subscription of the observable from the http.
So based on your code you could pass the data object straight to the promise and inspect data.ok before parsing the data.json.
//...
return new Promise((resolve, reject) => {
this.http.post(this.url, body, {
headers: header
})
.subscribe(resolve,
error => {
reject(error.json());
}
);
});
// then you would have something like this:
this._loginService.doLogin(this.credentials).then(
result => {
if (result.ok) {
this.data = result;
console.log(this.data);
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
})
SUGGESTION
Now, I would recommend getting rid of the promise, as I believe you don't really need it. whoever is consuming your service can just subscribe to the observable returned by the http post, like so:
doLogin(credentials) {
let header = new Headers();
header.append('Content-Type', 'application/x-www-form-urlencoded');
var body = 'username='+credentials.username+'&password='+credentials.password;
return this.http.post(this.url, body, { headers: header });
}
Then, when logging in:
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).subscribe(response => {
if (response.ok) { // <== CHECK Response status
this.data = response.json();
console.log(this.data);
} else {
// handle bad request
}
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Hope this helps!
You could do it like this:
data: Object;
errorMessage: Object;
login($event, username, password) {
this.credentials = {
username: username,
password: password
};
this._loginService.doLogin(this.credentials).then(
(result: any) => {
this.data = result;
console.log(this.data);
console.log(this.data.status);
},
error => {
this.errorMessage = <any>error;
console.log(this.errorMessage);
});
}
Set the result to type any. That way you'll be able to access the status, however you could create a class and use rxjs/map within your service to populate the class if you so desire.