Microsoft Teams Custom App doesn't work on mobile - mobile

I've already develop one custom Microsoft Teams app that correctly works on Desktop, but it doesn't work on mobile app.
It only display the page about the debug.
This is the tab into mobile app:
how can I solve it?
Thanks
This is the tab into desktop app:
This is one part of the code of my home tab for my personal app:
class Tab extends React.Component {
constructor(props) {
super(props)
this.state = {
user: null,
loading: true,
isLogged: false,
error: null,
layout: true
}
}
componentDidMount() {
const params = new URLSearchParams(this.props.location.search);
let teamsUser = {
Tid: params.get('tid'),
Aaid: params.get('aaId')
}
getUser(teamsUser).then((userResponse) => {
this.setState({
user: userResponse,
loading: false,
isLogged: true
})
}).catch((error) => {
logger.warn(JSON.stringify(error));
this.setState({
error: error,
loading: false
})
});
}
setLogged = (user) => {
this.setState({
user: user,
isLogged: true,
loading: false
})
}
render() {
let content;
const { user, loading, isLogged, error } = this.state;
if (loading) {
content = <Loading></Loading>
} else if (error) {
throw Error(error)
}
else if (isLogged) {
content = <Catalogue user={user}></Catalogue>
} else {
content = <UserLogin setLogged={this.setLogged}></UserLogin>
}
return (
<Layout>
{content}
</Layout>
);
}
}
export default Tab
and this is my manifest where I put the url with the tid and aaid:
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.9/MicrosoftTeams.schema.json",
"manifestVersion": "1.9",
"version": "1.0.0",
"id": "86af4197-14c8-4439-a440-3d33b4567f54",
"packageName": "com.microsoft.teams.extension",
"developer": {
"name": "Teams App, Inc.",
"websiteUrl": "https://localhost:3000",
"privacyUrl": "https://localhost:3000/privacy",
"termsOfUseUrl": "https://localhost:3000/termsofuse"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "AppLocal",
"full": ""
},
"description": {
"short": "Short description for Personal App.",
"full": "Full description of Personal App."
},
"accentColor": "#FFFFFF",
"staticTabs": [
{
"entityId": "index",
"name": "Catalogue",
"contentUrl": "https://localhost:3000/catalogue?tid={tid}&aaId={userObjectId}",
"websiteUrl": "https://localhost:3000/catalogue",
"scopes": [
"personal"
]
},
{
"entityId": "live",
"name": "Live",
"contentUrl": "https://localhost:3000/live?tid={tid}&aaId={userObjectId}",
"websiteUrl": "https://localhost:3000/live",
"scopes": [
"personal"
]
},
{
"entityId": "about",
"scopes": [
"personal"
]
}
],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": [
"localhost:3000",
"localhost"
]
}
I hope the above mentioned code can help you help me.

I have tested with your code and I replaced localhost URL with ngrok URL it's working fine. Running the application locally does not give you access to Teams app functionality. So could you please try with ngrok url.

I solved it, my error was in the App.js file. I had a wrong path that redirected to another page (the page published above) when try to open the url outside Microsoft Teams. I have remove it and all work's fine. Thank's for all

Related

'redirect_uri' is invalid for Microsoft login MSAL authentication Azure

Using login with Microsoft on Azure AD B2C I get the following error:
invalid_request: The provided value for the input parameter 'redirect_uri' is not valid. The expected value is a URI which matches a redirect URI registered for this client application.
I can reach other providers and login with email just not Microsoft.. lol.
I have searched for hours and tried everything I can think of, hopefully someone else can help identify the issue. Initially I was only able to get Microsoft login to work using https://login.microsoft.com/common or something similar but that did not use my userflow/ allow other providers. Now that I have the userflow working from my application I cannot login with Microsoft. Below is my config and code.
I initially followed the Microsoft tutorial here:
https://learn.microsoft.com/en-us/azure/developer/javascript/tutorial/single-page-application-azure-login-button-sdk-msal
then pieced others together to get it to use my userflow to execute and it works other than login with Microsoft.
Registered Application Manifest on Azure:
{
"id": "<ID>",
"acceptMappedClaims": null,
"accessTokenAcceptedVersion": 2,
"addIns": [],
"allowPublicClient": true,
"appId": "<app id>",
"appRoles": [],
"oauth2AllowUrlPathMatching": false,
"createdDateTime": "2021-06-09T22:15:39Z",
"disabledByMicrosoftStatus": null,
"groupMembershipClaims": null,
"identifierUris": [],
"informationalUrls": {
"termsOfService": null,
"support": null,
"privacy": null,
"marketing": null
},
"keyCredentials": [],
"knownClientApplications": [],
"logoUrl": null,
"logoutUrl": null,
"name": "Management",
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
"oauth2Permissions": [],
"oauth2RequirePostResponse": false,
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [],
"preAuthorizedApplications": [],
"publisherDomain": "dwsdevb2c.onmicrosoft.com",
"replyUrlsWithType": [
{
"url": "https://jwt.ms/",
"type": "Spa"
},
{
"url": "https://jwt.ms",
"type": "Spa"
},
{
"url": "http://localhost:3000/",
"type": "Spa"
},
{
"url": "http://localhost:3000",
"type": "Spa"
}
],
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null,
"signInUrl": "http://localhost:3000/",
"signInAudience": "AzureADandPersonalMicrosoftAccount",
"tags": [
"notApiConsumer",
"singlePageApp"
],
"tokenEncryptionKeyId": null
}
azure-authentication-config.tsx
import { Configuration, LogLevel } from '#azure/msal-browser';
const AzureActiveDirectoryAppClientId: any =
process.env.REACT_APP_AZURE_ACTIVE_DIRECTORY_APP_CLIENT_ID;
export const b2cPolicies = {
names: {
signUpSignIn: 'B2C_1_dwsdevuserflow01',
forgotPassword: 'B2C_1_dwsdevuserflow01',
editProfile: 'B2C_1_dwsdevprofileflow01',
},
authorities: {
signUpSignIn: {
authority:
'https://dwsdevb2c.b2clogin.com/dwsdevb2c.onmicrosoft.com/B2C_1_dwsdevuserflow01',
},
forgotPassword: {
authority:
'https://dwsdevb2c.b2clogin.com/dwsdevb2c.onmicrosoft.com/B2C_1_dwsdevuserflow01',
},
editProfile: {
authority:
'https://dwsdevb2c.b2clogin.com/dwsdevb2c.onmicrosoft.com/B2C_1_dwsdevprofileflow01',
},
},
authorityDomain: 'https://dwsdevb2c.b2clogin.com',
// authorityDomain: 'https://login.microsoft.com/common',
};
export const MSAL_CONFIG: Configuration = {
auth: {
clientId: AzureActiveDirectoryAppClientId,
authority: b2cPolicies.authorities.signUpSignIn.authority,
knownAuthorities: [b2cPolicies.authorityDomain],
redirectUri: window.location.origin,
postLogoutRedirectUri: window.location.origin, // Indicates the page to navigate after logout.
navigateToLoginRequestUrl: false,
},
cache: {
cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true,
},
system: {
loggerOptions: {
loggerCallback: (level, message, containsPii) => {
if (containsPii) {
return;
}
switch (level) {
case LogLevel.Error:
console.error(message);
return;
case LogLevel.Info:
console.error(message);
return;
case LogLevel.Verbose:
console.error(message);
return;
case LogLevel.Warning:
console.error(message);
return;
default:
break;
}
},
},
},
};
azure-authentication-context.tsx
import {
PublicClientApplication,
AuthenticationResult,
AccountInfo,
EndSessionRequest,
RedirectRequest,
PopupRequest,
} from '#azure/msal-browser';
import { MSAL_CONFIG } from './azure-authentication-config';
export class AzureAuthenticationContext {
private myMSALObj: PublicClientApplication = new PublicClientApplication(
MSAL_CONFIG,
);
private account?: AccountInfo;
private loginRedirectRequest?: RedirectRequest;
private loginRequest?: PopupRequest;
public isAuthenticationConfigured = false;
constructor() {
// #ts-ignore
this.account = null;
this.setRequestObjects();
if (MSAL_CONFIG?.auth?.clientId) {
this.isAuthenticationConfigured = true;
}
}
private setRequestObjects(): void {
this.loginRequest = {
scopes: ['openid', 'profile'],
prompt: 'select_account',
};
this.loginRedirectRequest = {
...this.loginRequest,
redirectStartPage: MSAL_CONFIG.auth.redirectUri, //window.location.href,
};
}
login(signInType: string, setUser: any): void {
if (signInType === 'loginPopup') {
this.myMSALObj
.loginPopup(this.loginRequest)
.then((resp: AuthenticationResult) => {
this.handleResponse(resp, setUser);
})
.catch((err) => {
console.error(err);
});
} else if (signInType === 'loginRedirect') {
this.myMSALObj.loginRedirect(this.loginRedirectRequest);
}
}
logout(account: AccountInfo): void {
const logOutRequest: EndSessionRequest = {
account,
};
this.myMSALObj.logout(logOutRequest);
}
handleResponse(response: AuthenticationResult, incomingFunction: any) {
if (response !== null && response.account !== null) {
this.account = response.account;
} else {
this.account = this.getAccount();
}
if (this.account) {
incomingFunction(this.account);
}
}
private getAccount(): AccountInfo | undefined {
console.log(`loadAuthModule`);
const currentAccounts = this.myMSALObj.getAllAccounts();
if (currentAccounts === null) {
// #ts-ignore
console.log('No accounts detected');
return undefined;
}
if (currentAccounts.length > 1) {
// #ts-ignore
console.log(
'Multiple accounts detected, need to add choose account code.',
);
return currentAccounts[0];
} else if (currentAccounts.length === 1) {
return currentAccounts[0];
}
}
}
export default AzureAuthenticationContext;
In AzureAD navigate to Home => App Registrations > YOUR_APP
Under “Single-page application” you should see the Redirect URIs listed. It is my understanding that the redirectUri value under Auth in your MSAL_CONFIG file needs to match on of the URI’s listed there. Have you confirmed that is the case? I am unable to tell what ‘window.location.origin’ is producing based on your config.

Excel Add-In keeps getting 401 error when trying to access Dynamics 365 Web Api

I am trying to develop a word add in in React with Typescript that allows me to access the dynamics 365 Web Api. The best example I've actually found was in a sample excel add in that accesses the graph api using MSAL 2.0 here https://github.com/OfficeDev/PnP-OfficeAddins/tree/master/Samples/auth/Office-Add-in-Microsoft-Graph-React. If I can get a successful get request to my Dynamics 365 api after modifying the example code I will port the code over to my Word Add in.
However I keep getting a 401 error when trying to go to https://saltrial.crm.dynamics.com/api/data/v9.1/
I get a response back when I simply paste this in a browser, but inside the add in I get 401 unauthorized. I also get 401 unauthorized when I paste the token received from the add in into postman with the header of Bearer + token. I have gotten a successful Access token however when I selected
I will show you my setup in Azure AD.... I have a client secret setup, but am not using it in my add in code.
Manifest
{
"id": "35c3a758-0edb-45f6-a97d-9c7180decd73",
"acceptMappedClaims": null,
"accessTokenAcceptedVersion": 2,
"addIns": [],
"allowPublicClient": true,
"appId": "4f7xxxxxxxxxxxxxxxxxxxxxx310bf0",
"appRoles": [],
"oauth2AllowUrlPathMatching": false,
"createdDateTime": "2021-01-24T07:09:12Z",
"disabledByMicrosoftStatus": null,
"groupMembershipClaims": null,
"identifierUris": [
"api://localhost:3000/4fxxxxxxxxxxxxxxxxxxxxxxx"
],
"informationalUrls": {
"termsOfService": null,
"support": null,
"privacy": null,
"marketing": null
},
"keyCredentials": [],
"knownClientApplications": [],
"logoUrl": null,
"logoutUrl": null,
"name": "TrySSO",
"oauth2AllowIdTokenImplicitFlow": true,
"oauth2AllowImplicitFlow": true,
"oauth2Permissions": [
{
"adminConsentDescription": "Enable Office to call the add-in's web APIs with the same rights as the current user.",
"adminConsentDisplayName": "Office can act as the user",
"id": "5b3a4e4a-e55e-45ba-820b-ea16efbe3d5f",
"isEnabled": true,
"lang": null,
"origin": "Application",
"type": "User",
"userConsentDescription": "Enable Office to call the add-in's web APIs with the same rights that you have.",
"userConsentDisplayName": "Office can act as you",
"value": "access_as_user"
}
],
"oauth2RequirePostResponse": false,
"optionalClaims": null,
"orgRestrictions": [],
"parentalControlSettings": {
"countriesBlockedForMinors": [],
"legalAgeGroupRule": "Allow"
},
"passwordCredentials": [
{
"customKeyIdentifier": null,
"endDate": "2299-12-31T05:00:00Z",
"keyId": "570axxxxxxxxxxxxxxxxxxxxxxxxxxbcd1",
"startDate": "2021-01-28T04:11:05.086Z",
"value": null,
"createdOn": "2021-01-28T04:11:06.027737Z",
"hint": "mm-",
"displayName": "wordaddinsecret"
}
],
"preAuthorizedApplications": [
{
"appId": "ea5a67f6-b6f3-4338-b240-c655ddc3cc8e",
"permissionIds": [
"5b3a4e4a-e55e-45ba-820b-ea16efbe3d5f"
]
},
{
"appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c",
"permissionIds": [
"5b3a4e4a-e55e-45ba-820b-ea16efbe3d5f"
]
},
{
"appId": "57fb890c-0dab-4253-a5e0-7188c88b2bb4",
"permissionIds": [
"5b3a4e4a-e55e-45ba-820b-ea16efbe3d5f"
]
},
{
"appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3",
"permissionIds": [
"5b3a4e4a-e55e-45ba-820b-ea16efbe3d5f"
]
}
],
"publisherDomain": "salnewtrial.onmicrosoft.com",
"replyUrlsWithType": [
{
"url": "https://localhost:3000/login/login.html",
"type": "Spa"
},
{
"url": "https://login.microsoftonline.com/common/oauth2/nativeclient",
"type": "InstalledClient"
},
{
"url": "https://localhost:3000/login.html",
"type": "Web"
}
],
"requiredResourceAccess": [
{
"resourceAppId": "00000007-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "78ce3f0f-a1ce-49c2-8cde-64b5c0896db4",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "14dad69e-099b-42c9-810b-d002981feec1",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
},
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
]
}
],
"samlMetadataUrl": null,
"signInUrl": null,
"signInAudience": "AzureADMyOrg",
"tags": [],
"tokenEncryptionKeyId": null
}
Inside my login.ts in excel add in
(() => {
// The initialize function must be run each time a new page is loaded
Office.initialize = () => {
const msalInstance = new PublicClientApplication({
auth: {
clientId: "4f7f40ec-xxxxxxxxx-5d6b18310bf0",
authority: "https://login.microsoftonline.com/cd77a053-xxxxxxxxxx3402c0fd62", *This is tenant id
redirectUri: "https://localhost:3000/login/login.html", // Must be registered as "spa" type
},
cache: {
cacheLocation: "localStorage", // needed to avoid "login required" error
storeAuthStateInCookie: true, // recommended to avoid certain IE/Edge issues
},
});
// handleRedirectPromise should be invoked on every page load
msalInstance
.handleRedirectPromise()
.then((response) => {
// If response is non-null, it means page is returning from AAD with a successful response
if (response) {
Office.context.ui.messageParent(
JSON.stringify({ status: "success", result: response.accessToken })
);
} else {
// Otherwise, invoke login
msalInstance.loginRedirect({
scopes: [
"user.read",
"files.read.all",
"https://saltrial.crm.dynamics.com//user_impersonation",
],
});
}
})
.catch((error) => {
const errorData: string = `errorMessage: ${error.errorCode}
message: ${error.errorMessage}
errorCode: ${error.stack}`;
Office.context.ui.messageParent(
JSON.stringify({ status: "failure", result: errorData })
);
});
};
})();
Here is my API Call in Add in
import axios from 'axios';
export const getGraphData = async (url: string, accesstoken: string) => {
const response = await axios({
url: url,
method: 'get',
headers: {'Authorization': `Bearer ${accesstoken}`,
'OData-MaxVersion': '4.0',
'OData-Version': '4.0',
"Accept": "application/json",
"Content-Type": "application/json; charset=utf-8",
}
});
return response;
};
Code that calls my api function and passes the scopes and dynamics url. I console log the access token and put it into postman with header Bearer token, I get 401. Also the add-in displays 401 unauthorized in the task pane....Ignore any naming of functions referring to the graph api, I'm hitting the dynamics 365 api and hoping I don't get the 401 error. Thanks.
getFileNames = async () => {
this.setState({ fileFetch: "fetchInProcess" });
getGraphData(
// Get the `name` property of the first 3 Excel workbooks in the user's OneDrive.
"https://saltrial.crm.dynamics.com/api/data/v9.1/WhoAmI",
this.accessToken
)
.then(async (response) => {
await writeFileNamesToWorksheet(response, this.displayError);
this.setState({ fileFetch: "fetched", headerMessage: "Success" });
})
.catch((requestError) => {
// If this runs, then the `then` method did not run, so this error must be
// from the Axios request in getGraphData, not the Office.js in
// writeFileNamesToWorksheet
console.log("Access Token >>>>>>>>>>>>>>>>> ", this.accessToken);
this.displayError(requestError);
});
};

Alexa skill not asking for permission (notification) when enabling the skill via voice

The skill in question asks for one permission when enabling in Web or app (Outbound Notification). But, when implemented Skill Enabled Event it's not asking user to give notification permission or not. Skill enablement works itself but permission is by default No. How to make alexa to ask for permission when enabling via voice?
Can Alexa prompt them via voice to enable the outbound notification?
skill.json
{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "test skill summary",
"examplePhrases": [
"Alexa, launch test skill",
"Alexa, open test skill",
"Alexa, start test skill"
],
"keywords": [
"test skill"
],
"name": "test skill",
"description": "test skill Description",
"smallIconUri": "",
"largeIconUri": "",
"updatesDescription": ""
}
},
"isAvailableWorldwide": true,
"testingInstructions": "n/a",
"category": "EVENT_FINDERS",
"distributionCountries": [],
"automaticDistribution": {
"isActive": false
}
},
"apis": {
"custom": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:"
},
"interfaces": []
}
},
"manifestVersion": "1.0",
"privacyAndCompliance": {
"allowsPurchases": false,
"locales": {
"en-US": {
"privacyPolicyUrl": "",
"termsOfUseUrl": ""
}
},
"isExportCompliant": true,
"containsAds": false,
"isChildDirected": false,
"usesPersonalInfo": false
},
"events": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:"
},
"publications": [
{
"eventName": "AMAZON.MessageAlert.Activated"
},
{
"eventName": "AMAZON.MediaContent.Available"
}
],
"regions": {
"NA": {
"endpoint": {
"uri": "arn:aws:lambda:us-east-1:",
"sslCertificateType": "Trusted"
}
}
},
"subscriptions": [
{
"eventName": "SKILL_PROACTIVE_SUBSCRIPTION_CHANGED"
},
{
"eventName": "SKILL_ENABLED"
},
{
"eventName": "SKILL_DISABLED"
},
{
"eventName": "SKILL_PERMISSION_ACCEPTED"
},
{
"eventName": "SKILL_PERMISSION_CHANGED"
},
{
"eventName": "SKILL_ACCOUNT_LINKED"
}
]
},
"permissions": [
{
"name": "alexa::devices:all:notifications:write"
}
]
}
}
Thank you for the help
There may be a different way, but once you are in the skill I believe you will need to send an ask for permissions card. As I understand it the idea is to make sure that Amazon is involved as a third party permissions granter. This will pop a permissions request in the Alexa app on the users phone. This added layer of security just makes sure the customer saw exactly what permissions they were granting.
You can do this a few different ways in your skill. You could check the first time that the user connects and keep track of that first connection in a persistent customer data layer. Or you could just check if the user has permission when you go to use that part of the skill. If they don't respond telling the customer you sent them a card to grant permissions.
Here is more info on permission cards:
https://developer.amazon.com/en-US/docs/alexa/custom-skills/request-customer-contact-information-for-use-in-your-skill.html#permissions-card-for-requesting-customer-consent
To run reminders via a lambda, other permissions are probably the same format.
const CreateReminderIntent = {
canHandle(handlerInput) {
const { request } = handlerInput.requestEnvelope;
return request.type === 'IntentRequest' && request.intent.name === 'CreateReminderIntent';
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
const consentToken = requestEnvelope.context.System.user.permissions
&& requestEnvelope.context.System.user.permissions.consentToken;
if (!consentToken) {
return handlerInput.responseBuilder
.addDirective({
type: "Connections.SendRequest",
name: "AskFor",
payload: {
"#type": "AskForPermissionsConsentRequest",
"#version": "1",
"permissionScope": "alexa::alerts:reminders:skill:readwrite"
},
token: "<string>"
})
.getResponse();
}
try {
const speechText = "Great! I've scheduled a reminder for you";
const ReminderManagementServiceClient = serviceClientFactory.getReminderManagementServiceClient();
const reminderPayload = {
"trigger": {
"type": "SCHEDULED_RELATIVE",
"offsetInSeconds": "10",
"timeZoneId": "Europe/London"
},
"alertInfo": {
"spokenInfo": {
"content": [{
"locale": "en-GB",
"text": "Wash the dog"
}]
}
},
"pushNotification": {
"status": "ENABLED"
}
};
await ReminderManagementServiceClient.createReminder(reminderPayload);
return responseBuilder
.speak(speechText)
.getResponse();
} catch (error) {
console.error(error);
return responseBuilder
.speak('Uh Oh. Looks like something went wrong.')
.getResponse();
}
}
};

I need to do a React.js app that logs in into an API to get the session key from the current session using Axios

I apologize if it doesnt make much sense, I am new to stackoverflow and React
I already made the React app, my problem is that I dont understand how to login into an API and making a GET request to get the current session key.
I have tried following axios docs and fetch but the only thing I get is or Network error or a CORS error.
this is with axios
// class LoginForm extends React.Component {
// state = {
// users: []
// }
// componentDidMount() {
// const url = API_URL;
// axios.get(url)
// .then(res=> {
// const users = res.data;
// this.setState({users});
// })
// }
// render() {
// return (
// <div>{Object.keys(this.state.users).map(user => <h3>{user.skey}</h3> )}</div>
// )
// };
// }
this is with fetch
componentDidMount() {
fetch(API_URL)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result.items
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
this is the JSON from the API (I had altered content for security)
{
"skey": "lep8k7jcbtba2Hwlcf4ZGVtgbmwo8s56721",
"authenticated": false,
"silo": "demo",
"user": {
"uuid": "f205daa8-b838-41c7-984be",
"username": "guest",
"full_name": "Guest",
"email": "guest",
"groups": [
{
"uuid": "27e2e4f9-ebee-4ecca10151",
"name": "guest_user"
},
{
"uuid": "c354f1b5-ca702fe3",
"name": "public"
}
],
"roles": [
{
"uuid": "027a210b657f52b10dd4",
"name": "limited"
}
],
"permits": [
{
"uuid": "e1e896-c5bd-35494211374e",
"name": "collection.create.ccpUser"
},
{
"uuid": "0e4a0a9c-8cca9-4803da46d23d",
"name": "contribution.create.ccpArticle"
},
{
"uuid": "83f93b4dab-116dd29b19e3",
"name": "contribution.view.ccpComment"
},
{
"uuid": "b7401658-4509-98e28868748b",
"name": "view_pub_public"
},
{
"uuid": "0016447d-af2b-3c4dd0bcf55d",
"name": "ws.config.list"
},
{
"uuid": "0c776bcb-7656-6e15-9ecb2389ea6f",
"name": "ws.pubs"
},
{
"uuid": "4839a09b-5be-b119-3ee8281780e3",
"name": "ws.user.login"
}
]
},
"httpSession": "devtvowc4gmo8s5672",
"cmsVersion": "6.3p"
}
Wrap your res around parenthesis. Try this:
axios.get(url)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})

Render JSON data from API call in react

Working on an app using the google maps API for geolocation with Reactjs. My aim right now is to simply render the entire JSON data to the window (will be used later). No errors, but nothing is rendering to the page. Am I trying to access the data inccorrectly?
class App extends Component {
constructor () {
super();
this.state = {
isLoaded: false,
results: {}
};
}
componentDidMount() {
fetch(geo_url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
results: result.results
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const {error, isLoaded, results} = this.state;
if (error) {
return <div>Error: {error.message} </div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="App">
Location Data:
{results.geometry}
</div>
);
}
}
}
Below is a sample of the JSON i'm trying to access:
{
"results": [
{
"address_components": [
{
"long_name": "1600",
"short_name": "1600",
"types": [
"street_number"
]
},
{
"long_name": "Amphitheatre Parkway",
"short_name": "Amphitheatre Pkwy",
"types": [
"route"
]
},
{
"long_name": "Mountain View",
"short_name": "Mountain View",
"types": [
"locality",
"political"
]
},
{
"long_name": "Santa Clara County",
"short_name": "Santa Clara County",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "California",
"short_name": "CA",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "United States",
"short_name": "US",
"types": [
"country",
"political"
]
},
{
"long_name": "94043",
"short_name": "94043",
"types": [
"postal_code"
]
}
],
"formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.422617,
"lng": -122.0853839
},
"location_type": "ROOFTOP",
"viewport": {
"northeast": {
"lat": 37.4239659802915,
"lng": -122.0840349197085
},
"southwest": {
"lat": 37.4212680197085,
"lng": -122.0867328802915
}
}
},
"place_id": "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
"plus_code": {
"compound_code": "CWF7+2R Mountain View, California, United States",
"global_code": "849VCWF7+2R"
},
"types": [
"street_address"
]
}
],
"status": "OK"
}
First render occurs before results are retrieved. Check in render() whether results exist already. If not, display a 'loading' message.
In addition to that, fix your handling of error while trying to retrieve data. You are setting a state.error variable which was not defined. Then, in render, display an error message if loading is done but there is an error.
First, you have to do :
<div className="App">
{this.state.results.geometry}
</div>
or
render() {
const {results} = this.state
return (
<div className="App">
{results.geometry}
</div>
);
}
}
But Like #Yossi saids, you result are not defined in you first render. That's why you have : "results not defined". You can use "lodash" to force your render. It's works even if I don't know if it's a good practice
You can test :
import _ from 'lodash';
render() {
const {results} = this.state
return (
{!_.isEmpty(results) &&
<div className="App">
{results.geometry}
</div>
}
);
}
It should be works :)
PS : sorry for my bad english ;)
You can set in state a key for error: false.
In componentDidMount its better to use then and catch for errors
componentDidMount() {
fetch(geo_url)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
results: result.results
});
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
).catch(error) {
this.setState({
isLoaded: true,
error
})
}
}

Resources