I have a bot developed in SDK 4 and deployed in IIS. When I integrate with web chat using secret it works .
window.WebChat.renderWebChat(
{
directLine: window.WebChat.createDirectLine({
secret: 'SECRET CODE'
}),
// Passing 'styleOptions' when rendering Web Chat
styleOptions
},
document.getElementById('webchat')
);
But it have very limited styling options in above case. I would like to use REACT which requires token exchange. I am not sure how this will be used? Mean what changes are required at client end & what at Bot end? I cannot find any descriptive document for this. Would be great if we can sample for both at client & Bot end changes for token exchange.
It is possible to use REACT to style your webchat. The botframework-webchat repo here has samples and examples displaying this. For the token exchange, you're going to want to use the following:
import { DirectLine } from 'botframework-directlinejs';
import React from 'react';
import ReactWebChat from 'botframework-webchat';
export default class extends React.Component {
constructor(props) {
super(props);
this.directLine = new DirectLine({ token: 'YOUR_DIRECT_LINE_TOKEN' });
}
render() {
return (
<ReactWebChat directLine={ this.directLine } userID='YOUR_USER_ID' />
element
);
}
}
Related
Can anyone help me why my code doesn't work to fetch API?
I have to build a weather app from several components, must build it structured.
My plan is to have one service component that I have API service in there. then I have to make 3 more components, search component to handle the city search, weatherToday component to show today weather, and weatherForecast component to show five days forecast.
And I have to fetch the API with async an await. Here is the code that I tried(just now I have the code in my App.js just to try if my fetch work)
import { useState, useEffect } from "react";
function App() {
const [data, setData] = useState();
const fetchData = async () => {
await fetch(
`http://api.weatherapi.com/v1/forecast.json?key=1d172d3904e246849d3183628230802&q=Stockholm&days=6&aqi=no&alerts=no`
)
.then((response) => {
return response.json();
})
.then((data) => {
setData(data);
});
};
useEffect(() => {
fetchData();
}, []);
return (
<>
<h3>{data.location.name}</h3>
<p>{data.current.temp_c}</p>
<p>{data.location.localtime}</p>
</>
);
}
export default App;
First of all, welcome to React and StackOverflow!
There's a few issues here:
The main issue is CORS. You can't call this API from your browser - it's meant to be called from a server (backend). I highly recommend using Next.js since you like React, it uses that as it's framework - but it allows you to have Server Components, essentially an Express backend, so that you can perform this API call - then retrieve that data using this client component just to display the data (not to fetch it).
Another issue (but not the problem here) is reusing the data variable in the local scope of then((data) => is not good when you have data defined higher up in the component scope for your state. Use then((d) => instead.
I created a Next.js 13 sandbox for you with this working API call to get you started:
https://codesandbox.io/p/sandbox/broken-field-4nsp1p
In Next.js 13, you can use the app folder, where every component is a Server Component by default. Then you can create Client Component, like the one you have above - you simply have to add use client to the very top of the file, that's it.
Since Next.js 13 is very new (the app folder and concept of Server Components very new and bound to change), you would want to potentially just stick with the pages folder.
In there, you'll see the client component which calls the api folder's getWeather API call.
Finally, you shared your private key with the public. You need to destroy and regenerate that key now:
From the WeatherAPI.com Docs:
Authentication
API access to the data is protected by an API key. If at anytime, you
find the API key has become vulnerable, please regenerate the key
using Regenerate button next to the API key.
https://www.weatherapi.com/docs/
If don't want to use Next.js - then you'll need to use some sort of backend, like Firebase Functions or Google Cloud Functions, etc. Next.js is probably the easiest thing to adapt if you like React though!
Learn about Next.js 13 & /app folder:
https://beta.nextjs.org/docs/getting-started
Learn about Next.js 12 & /pages folder:
https://nextjs.org/docs
Implementing Fetch via Next.js 13
app/head.tsx
export default function Head() {
return (
<>
<title>Weather App</title>
<meta content="width=device-width, initial-scale=1" name="viewport" />
</>
);
}
app.layout.tsx
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
{/*
<head /> will contain the components returned by the nearest parent
head.tsx. Find out more at https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>{children}</body>
</html>
);
}
app/page.tsx
const App = async () => {
console.log("App.js");
const results = await fetch(
`http://api.weatherapi.com/v1/forecast.json?key=1d172d3904e246849d3183628230802&q=Stockholm&days=6&aqi=no&alerts=no`
);
const json = await results.json();
console.log("json", json);
return (
<>
<h3>{json.location.name}</h3>
<p>{json.location.temp_c}</p>
<p>{json.location.localtime}</p>
</>
);
};
export default App;
When visiting either / or /weather, you will see the same results, since the example is implemented in both v12 and v13:
--- OR --- Implementing Fetch via Next.js 12
pages/weather.tsx
async function getData() {
const res = await fetch("/api/getWeather");
console.log("res", res);
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
// Recommendation: handle errors
if (!res.ok) {
// This will activate the closest `error.js` Error Boundary
throw new Error("Failed to fetch data");
}
const json = await res.json();
console.log({ json });
return json;
}
export default async function Page() {
const data = await getData();
console.log("data", data);
return (
<main>
<h3>{data.location.name}</h3>
<p>{data.current.temp_c}</p>
<p>{data.location.localtime}</p>
</main>
);
}
pages/api/getWeather.ts
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
const results = await fetch(
`http://api.weatherapi.com/v1/forecast.json?key=1d172d3904e246849d3183628230802&q=Stockholm&days=6&aqi=no&alerts=no`
);
const json = await results.json();
console.log("json", json);
res.status(200).send(json);
}
Remember to revoke your exposed secret API key.
I hope this helps you start building your app. Good luck!
I need to send a JWt (access token) to the chatbot via directline. I'm using react as the front end, and the chatbot is integrated into the front end via botframework-webchat.
So far, I was able to send the access token through an activity, which is not recommended as I think.
Right now, the chatbot is asking the user to log in, which is not good because the user is already logged in to the application.
My first question - Is it possible to authenticate the chatbot by an id token instead of connecting with Azure AD, B2C, or any auth service provider?
If it is possible, How can I send the id token to the bot, via botframework-webchat
Thanks in advance
Here is my code for the front end
const Chatbot = (props) => {
const language = localStorage.getItem('language');
const directLine = useMemo(
() => createDirectLine({ token: <my_token>, locale: 'sv-se' }),
[]
);
useEffect(() => {
var activity = {
from: {
id: '001',
name: 'noviral',
},
name: 'startConversation',
type: 'event',
value: 'Hi noviral!',
locale: language === 'en' ? 'en-US' : 'sv-se',
};
directLine.postActivity(activity).subscribe(function (id) {
if (console) {
console.log('welcome message sent to health bot');
}
});
}, []);
return (
<Layout className="login-layout">
<div className="login-div">
<div className="chatbot">
<div className="consent-wrapper">
<ReactWebChat
directLine={directLine}
userID={'001'}
username="Noviral"
locale={language === 'en' ? 'en-US' : 'sv-se'}
></ReactWebChat>
</div>
</div>
</div>
</Layout>
);
};
export default withTranslation()(Chatbot);
Sending the token via an activity is acceptable as activities sent via Direct Line are secure. If you look over the 24.bot-authentication-msgraph sample, you can see that the default action the bot takes is to send an activity displaying the user's token.
As for authentication, the question doesn't seem to be what token you will use but rather how you will authenticate. If you don't use a service provider + login, how is the bot going to verify who the user is? That being said, there are some SSO (single sign-on) options available via Web Chat (see here) that, if a user is already logged in, then SSO could pick it up. You will have to look them over to decide if these options meet your needs.
i want a cognito authorized user to be able to publish and subscribe to AWS IoT using Amplify PubSub but am having difficulty doing so.
i use javascript (inside a Vue app)
i have successfully managed to publish and subscribe to AWS IoT using the aws-iot-device-sdk so all the policies, etc are working.
here's the code i'm using with PubSub:
const region = "eu-west-1";
const endpoint = "blahBlah-ats.iot.eu-west-1.amazonaws.com";
const currentlySubscribedTopic = "myTopic";
Amplify.addPluggable(
new AWSIoTProvider({
aws_pubsub_region: region,
// aws_pubsub_endpoint: "xxxxxxzbx-ats.iot.eu-west-1.amazonaws.com"
// aws_pubsub_endpoint: 'wss://xxxxxxxxxxxxx.iot.<YOUR-IOT-REGION>.amazonaws.com/mqtt',
aws_pubsub_endpoint: "wss://" + endpoint + "/mqtt"
})
);
to subscribe:
PubSub.subscribe(currentlySubscribedTopic).subscribe({
next: data => console.log("Message received", data),
error: error => console.error(error),
close: () => console.log("Done")
});
to publish I call this method:
async publishMessage() {
console.log("publishing message...");
await PubSub.publish(currentlySubscribedTopic, {
msg: "Hello to all subscribers!"
});
console.log("published..");
}
unfortunately nothing happens (not even errors), so I am obviously doing something wrong.
how do i actually make the connection? is there a connect() function?
how do i incorporate the cognito credentials? i have tried this inside Auth.currentSession():
AWS.config.update({
region: "eu-west-1",
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: "eu-west-1:xxxx-7be8-487a-9e0b-91980xxx976e",
Logins: {
// optional tokens, used for authenticated login
"cognito-idp.eu-west-1.amazonaws.com/eu-west-1_xxxx4OFmI":
session.idToken.jwtToken
}
})
});
and can use AWS.config.credentials.get() to get the credentials but don't know how to use them to make the connection.
i'd appreciate some help as to how to do this.
thanks
I was toiling with this for quite awhile today and finally got it working. Pasting my code below. Though its not shown, the PubSub.publish() also worked fine too.
# App.js
import React from 'react';
import './App.css';
import Amplify from 'aws-amplify';
import PubSub from '#aws-amplify/pubsub';
import { AWSIoTProvider } from '#aws-amplify/pubsub/lib/Providers';
import awsconfig from './aws-exports';
import { withAuthenticator, AmplifySignOut } from '#aws-amplify/ui-react';
import EventViewer from './event-viewer.js';
Amplify.Logger.LOG_LEVEL = 'VERBOSE';
Amplify.addPluggable(new AWSIoTProvider({
aws_pubsub_region: 'us-west-2',
aws_pubsub_endpoint: 'wss://MY_IOT_ENDPOINT-ats.iot.us-west-2.amazonaws.com/mqtt',
}));
Amplify.configure(awsconfig);
PubSub.configure();
PubSub.subscribe('myTopic1').subscribe({
next: data => console.log('Message received', data),
error: error => console.error(error),
close: () => console.log('Done'),
});
function App() {
return (
<div className="App">
<AmplifySignOut />
<EventViewer/>
</div>
);
}
export default withAuthenticator(App);
Keep in mind, this also requires that:
You have created a proper AWS IoT policy (e.g. for example, having iot:Connect, and having iot:Subscribe and iot:Receive scoped to the appropriate topics)
You have attached the IoT Policy to your user's Cognito Federated Identity Id
I'm starting to work with GraphQL and the new Nexus Framework GraphQL server, which is a great product.
On my server-side, I defined my schema, I can query my database with Prisma and everything runs smoothly. I can query data also from the Nexus GraphQL playground and also with Postman.
Now, I want to make things work on the client-side. I see that Apollo Client is the best solution to integrate React with GraphQL, but I just can't make things work. I read tons of docs but I'm missing something that I can't figure out.
GraphQL and the client part will be hosted on the same server, on separate node applications.
I'm configuring Apollo based on its documentations. The example below is for the new 3.0 Beta Version of Apollo which I'm testing, but the same scenario happens on the last stable version. I believe that I need to do something else to integrate Apollo and Nexus.
Every query returns: "Must Provide Query String".
The same query inside the playground works perfectly.
Here is my basic testing code:
apollo.js:
import { ApolloClient, HttpLink, InMemoryCache } from '#apollo/client'
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new HttpLink({
uri: 'http://localhost:4000/graphql',
fetchOptions: {
mode: 'no-cors',
}
})
})
export default client
App.js:
import React from 'react'
import { ApolloProvider } from '#apollo/client';
import client from './database/apollo'
import Home from './components/Home'
const App = () => {
return (
<ApolloProvider client={client}>
<Home />
</ApolloProvider>
)
}
export default App;
Home.js:
import React, { useState, useEffect, useReducer } from 'react'
import { useQuery, gql } from '#apollo/client'
const PUBLICATIONS = gql`
{
albumreviews(last: 1) {
title
}
}
`
const Home = () =>{
const { loading, error, data } = useQuery(PUBLICATIONS)
if (loading) return <p>Loading...</p>
if (error) return <p>Error :(</p>
return data.albumreviews.map(({ review }) => (
<div>{JSON.parse(review)}</div>
))
}
export default Home
On the client-side: "Error" is displayed.
On the server-side: "Must provide query string"
Believe me, I've tried to adjust the query thousands of times trying to get a different answer.
Could some help me to move forward with this? Should I provide the Nexus schema to the apollo client? What is the better way of doing this?
You should pretty much never use no-cors. Off hand, I'm not sure why that option would cause your request to be malformed, but it will make it impossible for your response to be read anyway. Remove fetchOptions and whitelist your client URL in your CORS configuration on the server-side. CORs usage with Nexus is shown here in the docs.
AppSync uses MQTT over WebSockets for its subscription, yet Apollo uses WebSockets. Neither Subscription component or subscribeForMore in Query component works for me when using apollo with AppSync.
One AppSync feature that generated a lot of buzz is its emphasis on
real-time data. Under the hood, AppSync’s real-time feature is powered
by GraphQL subscriptions. While Apollo bases its subscriptions on
WebSockets via subscriptions-transport-ws, subscriptions in GraphQL
are actually flexible enough for you to base them on another messaging
technology. Instead of WebSockets, AppSync’s subscriptions use MQTT as
the transport layer.
Is there any way to make use of AppSync while still using Apollo?
Ok, here is how it worked for me. You'll need to use aws-appsync SDK (https://github.com/awslabs/aws-mobile-appsync-sdk-js) to use Apollo with AppSync. Didn't have to make any other change to make subscription work with AppSync.
Configure ApolloProvider and client:
// App.js
import React from 'react';
import { Platform, StatusBar, StyleSheet, View } from 'react-native';
import { AppLoading, Asset, Font, Icon } from 'expo';
import AWSAppSyncClient from 'aws-appsync' // <--------- use this instead of Apollo Client
import {ApolloProvider} from 'react-apollo'
import { Rehydrated } from 'aws-appsync-react' // <--------- Rehydrated is required to work with Apollo
import config from './aws-exports'
import { SERVER_ENDPOINT, CHAIN_ID } from 'react-native-dotenv'
import AppNavigator from './navigation/AppNavigator';
const client = new AWSAppSyncClient({
url: config.aws_appsync_graphqlEndpoint,
region: config.aws_appsync_region,
auth: {
type: config.aws_appsync_authenticationType,
apiKey: config.aws_appsync_apiKey,
// jwtToken: async () => token, // Required when you use Cognito UserPools OR OpenID Connect. token object is obtained previously
}
})
export default class App extends React.Component {
render() {
return <ApolloProvider client={client}>
<Rehydrated>
<View style={styles.container}>
<AppNavigator />
</View>
</Rehydrated>
</ApolloProvider>
}
Here is how the subscription in a component looks like:
<Subscription subscription={gql(onCreateBlog)}>
{({data, loading})=>{
return <Text>New Item: {JSON.stringify(data)}</Text>
}}
</Subscription>
Just to add a note about the authentication as it took me a while to work this out:
If the authenticationType is "API_KEY" then you have to pass the apiKey as shown in #C.Lee's answer.
auth: {
type: config.aws_appsync_authenticationType,
apiKey: config.aws_appsync_apiKey,
}
If the authenticationType is "AMAZON_COGNITO_USER_POOLS" then you need the jwkToken, and
if you're using Amplify you can do this as
auth: {
type: config.aws_appsync_authenticationType,
jwtToken: async () => {
const session = await Auth.currentSession();
return session.getIdToken().getJwtToken();
}
}
But if your authenticationType is "AWS_IAM" then you need the following:
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: () => Auth.currentCredentials()
}