Why build a custom connector?
Microsoft offers connectivity through standard and premium connectors to more than 200 services today in PowerApps and Flow.
Although there is a large selection of connectors, there are services today for which Microsoft doesn't provide a connector yet. For example, we don't have a connector for Yelp!
If you want to automate Yelp, you will have to build your own connector, ideally, or use HTTP actions, which is far from ideal.
Prerequisites
To build a custom connector you will need:
Custom connector vs HTTP actions
There are several advantages of building a custom connector instead of using HTTP actions:
- Flexibility – you can create multiple actions within the same connector and use them in both Flow and PowerApps;
- Parameters – you can configure actions with path and query parameters – you can pass a value produced by the output of one action to the input of another;
- Sharing – you can share the connector with other users in your organization and you can also share the connection, which is very useful when working with on-premises APIs through the on-premises data gateway;
- Security – you can keep the security separated from the business logic giving users the possibility to authenticate using their own connection, without exposing the application ID and application secret;
- Continuous integration – you can continue to develop new actions without breaking functionality of existing actions that you already created and are in production;
Create a new custom connector
To create a new custom connector, go to Flow or PowerApps, sign in, click on the Data menu on the left navigation pane, and then click on Custom Connectors.
This will bring up the Custom connectors screen. Here you have the option to create a custom connector from blank, import one from an OpenAPI file (swagger) or from an URL or from a Postman collection.
Click on Create from blank.
The Create from blank experience will ask for a name:
Give it a name and click Continue. This will open the custom connector designer where you will see 4 tabs: General, Security, Definition, and Test
General tab
The General tab is where you will enter the basic stuff about your connector, such as the host and if the connection is made through a gateway.
Developing a custom connector involves knowing how the API of the target service works. Luckily, Yelp did a great job documenting their API.
It's best to do some research first to understand how the API works and decide what kind of actions you would like to create.
I gave my connector a simple description, entered the host api.yelp.com and the base URL /v3/
You can't put the scheme or the sub-path in the Host field.
You can't leave the Base URL empty, so it needs at least a /, otherwise you will get this error: Specified file does not match OpenAPI 2.0 specification: 'String " does not match regex pattern '^/'. Path 'basePath'.'
This is how the General tab looks:
API authentication
More importantly, before anything else, you need to know what kind of security model the API uses.
What I'm going to show below is very Yelp-specific, but it will help you get an idea about what you need to do to configure the security for your connector.
In Yelp's case, I looked in the Authentication guide and found out that I first need to create an app.
Creating an app is super simple, I had to sign-in first and then created the app.
When the app is created, a client ID and API key are generated.
The API Key is what I will need to authorize the requests made to Yelp.
Security tab
The Yelp documentation explains that, in order to authenticate the API calls with the API Key, I will have to set the Authorization HTTP header value as Bearer <API Key>.
I am not going to go into details about what this means, but the Bearer part represents the authorization type and the API Key represents the credentials.
Knowing the authentication type, configuring the Security tab is very easy.
I've selected API Key as my Authentication type, then proceeded to configure the rest of the security settings.
Parameter label
I entered Yelp API Key as label because that is what I want to see when I create a new connection.
Parameter name
I entered Authorization as name because that's what the Yelp API accepts in order to authenticate the request.
Authorization is the name of the parameter that that will carry the authentication credentials and it has to match the API specifications.
Parameter location
I've selected Header for the parameter location. This indicates where the parameter will be located when the requests will be made.
If the parameter location is set to Header, then the parameter will be passed to the API through the request header. Else, it will be passed as a query parameter.
Definition tab
The next step is to configure the connector definition. In the definition tab you can find Actions, Triggers, References, and Policies
I will go through what I believe it's important to know about Actions in this article. I will write about Triggers, References, and Policies on other articles.
For my custom connector I will need an action: Search Businesses
Search Businesses will return a JSON array containing businesses that match a search term and a location.
Creating an action
For the Search Businesses action I am using the /businesses/search endpoint.
According to the documentation of this endpoint, I will have to send a GET request to https://api.yelp.com/v3/businesses/search
This endpoint accepts multiple parameters, but only the location parameter is required. If the location is not provided then latitude and longitude are required.
To make the Search Businesses action work I will pass two parameters: term and location to make it easier to search for Romanian restaurants in New York City, for example.
I start by adding a new action and name name it Search Businesses.
The Summary is the actual display name of the action, the Description is the information that shows up when you hover on the 🛈 symbol on the action, and the Operation ID is the action identifier.
It's best to give the action identifier a self explanatory name because it will be easier to use in PowerApps. For the Search Businesses action the command in PowerApps will be Yelp.SearchBusinesses({location:"New York City", term:"Romanian restaurant"})
The next step is to configure the HTTP request.
Clicking on the Import from sample button will open a configuration pane where I set the verb (aka method) to GET and the URL to https://api.yelp.com/v3/businesses/search?term&location
I leave the Headers section alone because I don't have custom headers.
term & location are query parameters as they come after the ? in the URL
So when the request will be sent to the Yelp API, the URL will look like this: https://api.yelp.com/v3/businesses/search?term=Romanian restaurant&location=New York City
After clicking the Import button, I can see that the parameters were parsed and appear under the query section in the Request.
I can edit the parameters now and configure them as required.
I will provide a description and a summary for each parameter in order to improve the UX for users who interact with this connector.
The Summary is actually the label that will appear on the action in Flow and the Description is the placeholder text that appears on the field.
This is how it's going to look in Flow. Notice that I made location a required parameter and it's automatically flagged as such with a * on the action.
Now that I'm done with the Request, the next step is to configure the Response of this action.
Clicking the Add default response button opens up the Response configuration page.
On this page I have the option to configure the Response by clicking the Import from sample button, similarly to what I did when I configured the Request.
Clicking on the Import from sample button will open a configuration pane where I paste the JSON response body sample documented by Yelp on their Business Search endpoint page.
The JSON response body sample looks like below but it's not valid because it contains some unnecessary characters which were meant to indicate that the businesses array may contain more than one item.
Because you can't really add comments in JSON those annotations made the JSON sample invalid.
If you run into this issue, just use an online JSON validator and it will flag the bad lines for you. Word of advice: never paste sensitive information in online tools.
{
"total": 8228,
"businesses": [
{
"rating": 4,
"price": "$",
"phone": "+14152520800",
"id": "E8RJkjfdcwgtyoPMjQ_Olg",
"alias": "four-barrel-coffee-san-francisco",
"is_closed": false,
"categories": [
{
"alias": "coffee",
"title": "Coffee & Tea"
}
],
"review_count": 1738,
"name": "Four Barrel Coffee",
"url": "https://www.yelp.com/biz/four-barrel-coffee-san-francisco",
"coordinates": {
"latitude": 37.7670169511878,
"longitude": -122.42184275
},
"image_url": "http://s3-media2.fl.yelpcdn.com/bphoto/MmgtASP3l_t4tPCL1iAsCg/o.jpg",
"location": {
"city": "San Francisco",
"country": "US",
"address2": "",
"address3": "",
"state": "CA",
"address1": "375 Valencia St",
"zip_code": "94103"
},
"distance": 1604.23,
"transactions": ["pickup", "delivery"]
},
// …
],
"region": {
"center": {
"latitude": 37.767413217936834,
"longitude": -122.42820739746094
}
}
}
Removing the unnecessary characters will fix the issue and the JSON will be valid.
Just like I did with the Request, after clicking the Import button, I can see that the parameters were parsed and appear under the Body section in the Response.
Those tokens that are generated automatically through the parsing process will show up as Dynamic Content Items in Flow (and in PowerApps).
On the bottom of the Response page there is a Validation section that provides information if there are potential issues with the Response.
Testing the custom connector
Now it's time to test the connector and the first step is to create a new connection.
To create the connection, I have to use the Yelp API Key I mentioned previously and, to this key, I will prepend the authorization type so my API Key will look like this: Bearer xrlex53…oC2sXHYx
After the connection is created, I refresh the connections, select the connection, enter the term and the location and then test the operation:
The result is successful – I receive a 200 status code which indicates that that the request had succeeded.
I can also see that there's a schema validation warning. This is because the rating item is configured as integer but the response indicates that the rating should be a decimal number.
It's very easy to change the schema property by going back to the Response section and editing the rating item.
I am changing the data type to number and the format to float and update the connector.
It's important to update the connector every time we make a change, otherwise the changes we make won't be committed and the test will render the same results.
I am testing the operation again and I can see that the schema validation warning is gone.
Testing in Flow
The next step is to test the connector in Flow.
Usually when I test custom connectors, I create a simple flow with a manual trigger like so:
This test is successful and I can see that the action is outputting the businesses array, as expected.
Testing in PowerApps
Testing in PowerApps involves more work.
For this test I created an app from blank with a single screen and added a button to search for Businesses based on term and location provided by the user through two text boxes.
The button sets a variable named Businesses with the JSON object returned by the Search Businesses request: Set(Businesses,Yelp.SearchBusinesses({location:"New York City", term:"Romanian restaurant"}))
To display the results, I added a gallery and set its Items property to the Businesses.businesses array: