Skip to content

Commit bbc4e39

Browse files
[react-native] Add a basic sample for AppConfiguration (Azure#21907)
* [react-native] Add a basic sample for AppConfiguration * Apply suggestions from code review Co-authored-by: Harsha Nalluru <[email protected]> Co-authored-by: Harsha Nalluru <[email protected]>
1 parent 47dd3d6 commit bbc4e39

File tree

14 files changed

+6220
-0
lines changed

14 files changed

+6220
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
node_modules/
2+
.expo/
3+
dist/
4+
npm-debug.*
5+
*.jks
6+
*.p8
7+
*.p12
8+
*.key
9+
*.mobileprovision
10+
*.orig.*
11+
web-build/
12+
.env
13+
14+
# macOS
15+
.DS_Store
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { StatusBar } from 'expo-status-bar';
2+
import { Button, StyleSheet, Text, View } from 'react-native';
3+
4+
import "./shims";
5+
import { runAppConfigSample } from "./appConfigSample";
6+
7+
export default function App() {
8+
return (
9+
<View style={styles.container}>
10+
<Text>Open up App.tsx to start working on your app!</Text>
11+
<Button title="Click me!" onPress={() => runAppConfigSample() } />
12+
<StatusBar style="auto" />
13+
</View>
14+
);
15+
}
16+
17+
const styles = StyleSheet.create({
18+
container: {
19+
flex: 1,
20+
backgroundColor: '#fff',
21+
alignItems: 'center',
22+
justifyContent: 'center',
23+
},
24+
});
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Azure SDK samples for React Native using Expo (TypeScript)
2+
3+
This sample application shows how to use the TypeScript client libraries for Azure in some common scenarios.
4+
5+
In this sample, we build a simple application in React Native using Expo and integrating with Azure App Configuration service.
6+
7+
## Prerequisites
8+
9+
The samples are compatible with [LTS versions of Node.js](https://nodejs.org/about/releases/).
10+
11+
Before running the samples in Node, they must be compiled to JavaScript using the TypeScript compiler. For more information on TypeScript, see the [TypeScript documentation][typescript].
12+
13+
The sample is using [Expo](https://expo.dev/), a framework and platform for universal React applications.
14+
15+
You need [an Azure subscription][freesub] and the following resources created to run this sample:
16+
17+
## Step by step
18+
19+
### Create the project
20+
21+
Run expo CLI to create a blank project with typescript support, give it a name of `appconf-rn-expo`.
22+
23+
```shell
24+
expo init -t expo-template-blank-typescript
25+
```
26+
27+
At this point, we should be able to see the app running if the environment is set up correctly
28+
29+
```shell
30+
expo start --android
31+
```
32+
33+
### Add a button to the app
34+
35+
Open App.tsx and add the following code so it looks similar to following code
36+
```diff
37+
-import { StyleSheet, Text, View } from 'react-native';
38+
+import { Button, StyleSheet, Text, View } from 'react-native';
39+
+import { runAppConfigSample } from "./appConfigSample";
40+
...
41+
42+
<Text>Open up App.tsx to start working on your app!</Text>
43+
+ <Button title="Click me!" onPress={() => runAppConfigSample() } />
44+
<StatusBar style="auto" />
45+
```
46+
47+
### Add the App Configuration sample file
48+
49+
create a new file `appConfigSample.ts` in the sample directory as `App.tsx` with following content from [appConfigSample.ts](./appConfigSample.ts) file
50+
51+
### Add dependencies
52+
53+
We need to add a dependency to the JavaScript Client SDK library for Azure App Configuration (version 1.4.0-beta.1 or later). We use `@babel/plugin-proposal-async-generator-functions` to help transform async iterator usage in our sample. We also use `babel-plugin-inline-dotenv` to help load secrets from our `.env` file while developing.
54+
55+
```shell
56+
yarn add @azure/[email protected]
57+
yarn add --dev babel-plugin-inline-dotenv @babel/plugin-proposal-async-generator-functions
58+
```
59+
60+
Then add the following into `babel.config.js` to enable the plugin
61+
62+
```diff
63+
presets: ["babel-preset-expo"],
64+
+ plugins: [
65+
+ "@babel/plugin-proposal-async-generator-functions",
66+
+ ["inline-dotenv", { unsafe: true }],
67+
+ ],
68+
```
69+
70+
### Add connection string to .env file
71+
72+
Create a `.env` file in the project directory. Retrieve your connection string from Azure portal and add them to the `.env` file. Since this file contains secrets you need to add it to the ignore list if your code is committed to a repository.
73+
74+
**Note** We use connection string directly here for testing purpose. You should consider the trade-off between security and convenience and better use a backend to dynamically provide secrets to only authenticated users.
75+
76+
```
77+
APPCONFIG_CONNECTION_STRING="<your app configuration connection string>"
78+
```
79+
80+
**Note**: if you update the .env file, you would need to clear expo cache and rebuild. It can be done by passing `-c` to the start command, for example, in `package.json`
81+
82+
```diff
83+
- "android": "expo start --android",
84+
+ "android": "expo start --android -c",
85+
```
86+
87+
### Add polyfills
88+
89+
The `crypto` dependency of the JavaScript Client SDK library for Azure App Configuration are not available in React-Native, so we need to provide polyfills for them. We also need to polyfill the `TextEncoder` API. Add the following dependencies to the project
90+
91+
```shell
92+
yarn add isomorphic-webcrypto react-native-get-random-values react-native-url-polyfill text-encoding-polyfill
93+
```
94+
95+
Then add a `shims.ts` file in the project root with the following content
96+
97+
```typescript
98+
import 'react-native-url-polyfill/auto';
99+
import "react-native-get-random-values";
100+
import "text-encoding-polyfill";
101+
const getRandomValues = global.crypto.getRandomValues;
102+
import * as crypto from "isomorphic-webcrypto";
103+
global.crypto = crypto;
104+
global.crypto.getRandomValues = getRandomValues;
105+
```
106+
107+
Then add the following line to `App.tsx`
108+
109+
```diff
110+
+import "./shims";
111+
import { runAppConfigSample } from "./appConfigSample";
112+
```
113+
114+
Now run the app in the emulator (Android in this case)
115+
116+
```shell
117+
npm run android
118+
```
119+
120+
Click on the **CLICK ME!** button, you should see the following logged to the console output!
121+
122+
```
123+
Running helloworld sample
124+
Adding in new setting Samples:Greeting
125+
Samples:Greeting has been set to Hello!
126+
Samples:Greeting has been set to Goodbye!
127+
Samples:Greeting has been deleted
128+
```
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"expo": {
3+
"name": "appconf-rn-expo",
4+
"slug": "appconf-rn-expo",
5+
"version": "1.0.0",
6+
"orientation": "portrait",
7+
"icon": "./assets/icon.png",
8+
"splash": {
9+
"image": "./assets/splash.png",
10+
"resizeMode": "contain",
11+
"backgroundColor": "#ffffff"
12+
},
13+
"updates": {
14+
"fallbackToCacheTimeout": 0
15+
},
16+
"assetBundlePatterns": [
17+
"**/*"
18+
],
19+
"ios": {
20+
"supportsTablet": true
21+
},
22+
"android": {
23+
"adaptiveIcon": {
24+
"foregroundImage": "./assets/adaptive-icon.png",
25+
"backgroundColor": "#FFFFFF"
26+
}
27+
},
28+
"web": {
29+
"favicon": "./assets/favicon.png"
30+
}
31+
}
32+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @summary Demonstrates the CRUD operations on the configuration settings.
3+
*/
4+
import { AppConfigurationClient } from "@azure/app-configuration";
5+
6+
export async function runAppConfigSample() {
7+
console.log(`Running helloworld sample`);
8+
9+
// Set the following environment variable or edit the value on the following line.
10+
const connectionString =
11+
process.env["APPCONFIG_CONNECTION_STRING"] || "<connection string>";
12+
const client = new AppConfigurationClient(connectionString);
13+
14+
const greetingKey = "Samples:Greeting";
15+
16+
await cleanupSampleValues([greetingKey], client);
17+
18+
// creating a new setting
19+
console.log(`Adding in new setting ${greetingKey}`);
20+
await client.addConfigurationSetting({ key: greetingKey, value: "Hello!" });
21+
22+
const newSetting = await client.getConfigurationSetting({ key: greetingKey });
23+
console.log(`${greetingKey} has been set to ${newSetting.value}`);
24+
25+
// changing the value of a setting
26+
await client.setConfigurationSetting({ key: greetingKey, value: "Goodbye!" });
27+
28+
const updatedSetting = await client.getConfigurationSetting({
29+
key: greetingKey,
30+
});
31+
console.log(`${greetingKey} has been set to ${updatedSetting.value}`);
32+
33+
// removing the setting
34+
await client.deleteConfigurationSetting({ key: greetingKey });
35+
console.log(`${greetingKey} has been deleted`);
36+
37+
await cleanupSampleValues([greetingKey], client);
38+
}
39+
40+
async function cleanupSampleValues(
41+
keys: string[],
42+
client: AppConfigurationClient
43+
) {
44+
const settingsIterator = client.listConfigurationSettings({
45+
keyFilter: keys.join(","),
46+
});
47+
48+
for await (const setting of settingsIterator) {
49+
await client.deleteConfigurationSetting({
50+
key: setting.key,
51+
label: setting.label,
52+
});
53+
}
54+
}
17.1 KB
Loading
1.43 KB
Loading
21.9 KB
Loading
46.2 KB
Loading
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = function(api) {
2+
api.cache(true);
3+
return {
4+
presets: ["babel-preset-expo"],
5+
plugins: [
6+
"@babel/plugin-proposal-async-generator-functions",
7+
["inline-dotenv", { unsafe: true }],
8+
],
9+
};
10+
};

0 commit comments

Comments
 (0)