React JS - How do I pass variables (parameters) to the API URL? - json

I have a single page that consist of two dropdown-list components; The page is only accessible upon successful authentication (valid token). Both dropdown-list consumes it's data from different JSON-API's. I have one of the dropdown list functional, but for the other, the URL to it's API requires parameters.
Example URL:
http://buildingsAPI:111/api/buildings/
tested via postman with an id appended:
http://buildingsAPI:111/api/buildings/abcde-abce-abc2-111-2222
sample Json:
[
{
"abc_buildingid": "1111-2222-3333-aaa-1111117",
"abc_energyprogramid": "abcde-abce-abc2-111-2222",
"siteName": "Building 1",
"Available": false,
"clientName": "Client 1"
},
{
"abc_buildingid": "222-2222-3333-aaa-1111117",
"abc_energyprogramid": "xyz11-abce-abc2-111-2222",
"siteName": "Building 2",
"Available": false,
"clientName": "Client 2"
},
]
...am already obtaining the token upon user authentication (localStorage), but I also need to append/pass the abc_energyprogramid as a parameter to the API URL.
...the code:
constructor(props) {
super(props);
this.getToken = this.getToken.bind(this);
}
componentDidMount() {
const bearerToken = this.getToken();
fetch('http://buildingsAPI:111/api/buildings/?myparam1={abc_energyprogramid}', {
method: 'GET',
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${bearerToken}`
},
})
.then(results => results.json())
.then(buildings => this.setState({ buildings: buildings }))
}
getToken() {
return localStorage.getItem('id_token');
}
render() {
console.log(this.state.buildings);
return(
<div>
<select className="custom-select" id="siteName">
{ this.state.buildings.map(item =>(
<option key={item.siteName}>{item.siteName}</option>
))
}
</select>
</div>
);
}
...I currently get an error:" Unhandled Rejection (SyntaxError):unexpected end of JSON input" on this line of the code: .then(results => results.json()). Could I get some help with this please?

I think the problem is the way you're referencing abc_energyprogramid
Change this:
fetch('http://buildingsAPI:111/api/buildings/?myparam1={abc_energyprogramid}')
to:
fetch(`http://buildingsAPI:111/api/buildings/?myparam1=${abc_energyprogramid}`)
Notice the back-ticks and ES6 template string literal.

Related

Angular ngbTypeahead gives [Object] error

My component.html (Input field)
<input type="text" class="form-control" [(ngModel)]="searchQuery" [ngbTypeahead]="recommends"
name="searchQuery" typeaheadOptionField="username">
My component.ts
this.recommends = (text$: Observable<string>) => {
return text$.pipe(
debounceTime(200),
distinctUntilChanged(),
switchMap((searchText) => this.stats.getSearchCompletion(searchText))
);
}
My getSearchCompletion function
getSearchCompletion(searchQuery) {
if(searchQuery) return this.http.post(backendURL + '/my/route', { searchQuery: searchQuery }, { headers: this.headers }).pipe(map(res => res.json()));
}
The repsonse is returned in a format like this:
[{
"username": "test"
},
{
"username": "test2"
}]
I get the following error:
To Image
I guess it is because my server response has multiple objects inside a list. But how do I bind the ngbTypeahead to for example username? I tried typeaheadOptionField="username" which gives me the error. The list pops up but has no entries.
You can use some of javascript skills to convert the response into plain array of strings, something like this
if(searchQuery) return this.http.post(backendURL + '/my/route', { searchQuery: searchQuery }, { headers: this.headers }).pipe(map(res => {
let arr:string[] = [];
res.json().forEach(x=>{
arr.push(x['username']);
});
return arr;
}));
This is based on assumption that your api response is in this format
[{ "username": "test"},{ "username": "test2"}]
Which is an array of objects.
Thanks.

Data from API is displaying in the console but not in the DOM, why?

I'm learning React and a little about API's. I'm using the Destiny 2 API as a starting API to try to wrap my head around how they work.
Here is my Api.js file:
import React, { Component } from 'react';
import './style.css';
import axios from 'axios';
class Api extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
};
}
componentDidMount() {
let config = {
headers: {
'X-API-KEY': 'key-here',
},
};
axios
.get('https://www.bungie.net/Platform/Destiny2/4/Profile/4611686018484544046/?components=100', config)
.then((response) => {
console.log(response);
this.setState({
data: response.data,
});
});
}
render() {
const { item } = this.state;
return (
<div>
{Array.isArray(item) &&
item.map((object) => <p key={object.data}>{object.data.Response.profile.data.userInfo.displayName}</p>)}
</div>
);
}
}
export default Api;
The data from the API is returned as an object that contains a nested array. I can get the data to display in the console no problem.
This is the layout of the response object output to the console:
I'm trying to grab the value of "displayName" and output it into the DOM, what am I doing wrong?
I have tried returning the data as JSON by doing:
response => {return(data.json())} and iterating through the json object using {Object.keys(this.state.data).map((key) => but I have still managed to only get data in the console and not in the DOM.
Is there anything that seems to be missing? I've been stuck with this problem for several days now!
EDIT: This is the whole response from the API call
{
"Response": {
"profile": {
"data": {
"userInfo": {
"membershipType": 4,
"membershipId": "4611686018484544046",
"displayName": "Snizzy"
},
"dateLastPlayed": "2019-04-05T14:28:30Z",
"versionsOwned": 31,
"characterIds": [
"2305843009409505097",
"2305843009411764917",
"2305843009425764024"
]
},
"privacy": 1
}
},
"ErrorCode": 1,
"ThrottleSeconds": 0,
"ErrorStatus": "Success",
"Message": "Ok",
"MessageData": {}
}
In the render function, where you destructure you state, you have the wrong property.
const { item } = this.state; should be const { data } = this.state;
More about destructuring here.
Also, you need to make changes here:
EDIT: Actually, your data isn't even an array. You don't have to iterate through it.
<div>
<p>{data.Response.profile.data.userInfo.displayName}</p>}
</div>
Let's do a check to make sure that we got back the api before running. You might be rendering before the api call is finished. Try using an inline statement.
{ item ? {Array.isArray(item) && item.map(object => (
<p key={object.data}>{object.data.Response.profile.data.userInfo.displayName}</p>
))}
:
<div>Loading...</div>

LinkedIn not reading JSON request

Trying to 'share' on LinkedIn: https://developer.linkedin.com/docs/share-on-linkedin
Which is basically a POST to 'https://api.linkedin.com/v1/people/~/shares?format=json'
in its simplest form is with json:
{
"comment": "Check out developer.linkedin.com! http://linkd.in/1FC2PyG",
"visibility": {
"code": "anyone"
}
}
This requires setting http headers:
Content-Type: application/json
x-li-format: json
I'm trying to do this using OAuth.io, but LinkedIn seems to be still reading the body in XML.
See my example here: https://jsfiddle.net/Lv3jtpkb/2/
I get the following error from it:
Invalid xml {Element 'share#http://api.linkedin.com/v1' with element-only content type cannot have text content.}
I have checked if from OAuth.io server to LinkedIn API endpoint the headers specified here at frontend were somehow altered and can confirm that they have not been.
You're almost there. There are 2 errors.
Your data are formatted as a JS object. The method you're using doesn't seem to be converting the object to JSON automatically.
This line of code isn't doing anything, and is causing exceptions:
.then(user => { console.log("next:",user) })
Remove it.
Working code snippet:
$('#linkedin-button').on('click', function() {
// Initialize with your OAuth.io app public key
OAuth.initialize('A5oDtHv-oUEVlR7q7hDolXxC7RE');
alert('init');
OAuth.popup('linkedin2').then(linkedin => {
alert('logged in');
linkedin.post({
url: "/v1/people/~/shares?format=json",
data: JSON.stringify({
"comment": "Hello world!",
"visibility": {
"code": "anyone"
}
}),
headers: {
"x-li-format": "json",
"Content-Type": "application/json"
}
}).then(data => {
console.log("success:", data);
}).fail(err => { console.log("err:",err) });
})
})
Success in console:

Using Angular Observers to fetch data over a network

I'm working on an Angular app that contains a list of (financial) Trades that a user can add to. This has been going well, and I'm trying to switch over from a static list provided by a service to trying to fetch the data from a local Node.js server. I'm using an observer to asynchronously fetch the list of trades.
I've been following along with Angular's HTTP tutorial and the associated plunker. However, even though I can see the data coming from the server, I'm having trouble using the .subscribe() method to get a useful set of data out of it.
Here's my service which connects to the node server:
#Injectable()
export class TradeService {
private url = '...'; // URL to web API
tradeArray: Trade[] = [];
constructor(private http: Http) { }
//-----------GETTERS---------------//
getTradeObservable(): Observable<Trade> {
return this.http.get(this.url)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
console.log("body:" + body);
console.log("Entire Body.trades: " + body.trades);
return body.trades;
}
getTrades(): any {
this.getTradeObservable()
.subscribe(
trade => this.tradeArray.push(trade));
return this.tradeArray;
}
And here are the relevant portions the node server itself:
var TRADES = { "trades": [
{"id": 0, "cust": "Ben", "hasSub": true,
"subcust": "Rigby", "type": "s", "security": "001", "ticket": "99"},
...
{"id": 9, "cust": "Uber Bank", "hasSub": true,
"subcust": "Lil Bank", "type": "p", "security": "456", "ticket": "56"}
]};
////////////Get Requests/////////////////
//this route returns all data in JSON format
app.get('/', function(req, res) {
res.send(JSON.stringify(TRADES));
});
And the expected output from getTrades:
[
{id: 0, cust: "Ben", hasSub: true,
subCust: "Rigby", type: "s", security: '001', ticket: '99'},
...
{id: 9, cust: "Uber Bank", hasSub: true,
subCust: "Lil' Bank", type: "p", security: '456', ticket: '56'},
];
And one of the places the service is injected into and called:
export class SubmittedComponent {
constructor(private tradeService: TradeService) { }
//initally show all trades
rows = this.tradeService.getTrades();
...
I can see in the browser console that 'entire body.trades' is a full list of the data I want, but it seems subscribe is not pushing them into tradeArray, which ends up undefined.
Thank you for your time.
So I suppose that you are calling getTrades() from one of your components. If this is the case, this is what will happen:
The request will be sent
The request will be processed in the background asynchronously
The method will not wait for the request to be resolved and will return the current value of tradeArray, which is []
To avoid this, you could refactor you components so that they invoke the getTradeObservable() method an subscribe to the returned Observable.
UPDATE: Another option would be to refactor you service to use a Subject', and expose it to your components through anObservable`.
UPDATE: Assuming that you have the following definition for Trade
export interface Trade{
id: number;
cust: string;
hasSub: boolean;
subCust: string;
type: string;s
security: string;
ticket: string;
}
You could try the following approach
class TestComponent {
data: Trade[];
// inject service in component
getData(){
this.service.getTradesObservable().subscribe(data => this.data = data);
}
}
And change the definition of getTradesObservable to :
getTradeObservable(): Observable<Trade[]> {
return this.http.get(this.url)
.map(this.extractData)
.catch(this.handleError);
}
Speaking just about this portion of the code:
getTrades(): any {
this.getTradeObservable()
.subscribe(
trade => this.tradeArray.push(trade));
return this.tradeArray;
}
since getTradeObservable is asynchronous this line: return this.tradeArray; will (maybe) execute before the observable is resolved, you should remove getTrades method from your service and instead get a hold of the observable returned by getTradeObservable in your component and rather than expecting the whole thing to return the value you want, you should assign that value in the subscription like this:
#Component({
providers:[TradeService ]
})
export class myComponent{
trades:Trade[];
constructor(tradeService:TradeService){
tradeService.getTradeObservable().subscribe(tradeRes=>this.trades=tradeRes as Trade[]);
}
}

kendo UI DropDownList behaves weird

I have the following code. When fetching the value selected, it works fine. But if I try put the selected value in any condition, it falters. the code crashes.
var onAcctMgrSelect = function (e) {
// access the selected item via e.item (jQuery object)
ddAMList = $("#ddAM").data("kendoDropDownList");
if (ddAMList.value() == "0")
$("#btnSearch").attr("class", "k-button k-state-disabled");
else
$("#btnSearch").attr("class", "k-button");
///alert(ddAMList.text());
checkValidData();
};
DropDownlist Code is as below:
function loadAccountManagers() {
$("#ddAM").kendoDropDownList({
change: onAcctMgrSelect,
dataTextField: "AcctMgrFullName",
dataValueField: "Id",
dataSource: {
schema: {
data: "d", // svc services return JSON in the following format { "d": <result> }. Specify how to get the result.
total: "count",
model: { // define the model of the data source. Required for validation and property types.
id: "Id",
fields: {
Id: { validation: { required: true }, type: "int" },
AcctMgrFullName: { type: "string", validation: { required: true} }
}
}
},
transport: {
read: {
url: "../services/Prospects.svc/GetAccountManagers", //specify the URL which data should return the records. This is the Read method of the Products.svc service.
contentType: "application/json; charset=utf-8", // tells the web service to serialize JSON
type: "GET" //use HTTP POST request as the default GET is not allowed for svc
}
}
}
});
I'm basically trying to disable the submit button if the first item is selected (which is a blank item in my case with a value of '0').
Am I going wrong anywhere? Please help!