Added JBHunt connector (#1604)
* Added JBHunt connector * Updated readme file and corrected indentation in swagger and apiProperties.json files * Update apiDefinition.swagger.json
This commit is contained in:
Родитель
e536da7cca
Коммит
79ef0c2c78
|
@ -0,0 +1,26 @@
|
|||
The JBHunt connector with Dynamics 365 Intelligent Order Management provides access to committed, market-relevant rating, tendering, and tracking, connected to nearly 1M trucks through carriers on 360 Marketplace by J.B. Hunt.
|
||||
|
||||
## Use Cases of this connector
|
||||
- Use this connector in PowerApps Workflows
|
||||
- Obtain quotes for pickups 1 to 14 days in the future for the transport of a full-truckload shipment.
|
||||
- creating orders for transportation services on the J.B. Hunt 360 platform.
|
||||
|
||||
And many more!
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Sign in or sign up for a Shipper 360 or Carrier 360 account to begin. You will receive a username via email after signing up.
|
||||
Please note that this step must be completed before proceeding.
|
||||
Note: It is recommended to use this connector specifically to set up the Dynamics 365 Intelligent Order Management JBHunt provider.
|
||||
|
||||
## How to authenticate
|
||||
|
||||
JBHunt Connector work with OAuth authentication.Register your app at the Client Registration page to get a client ID and secret. To obtain an authorization or access token in your application, complete the following steps:
|
||||
|
||||
Enter a name for your application (any name will work).
|
||||
Add Password as grant type in the initial setup.
|
||||
Retrieve the app's Client ID and Secret from the bottom of this page. The Secret can be copied by clicking the gear symbol.
|
||||
|
||||
## Known issues and limitations
|
||||
|
||||
This connector was specifically developed to be used for Dynamics 365 Intelligent Order Management's JBHunt provider integration. Support for usecases outside of Dynamics 365 Intelligent Order Management will be limited.
|
|
@ -0,0 +1,101 @@
|
|||
public class Script : ScriptBase
|
||||
{
|
||||
public override async Task<HttpResponseMessage> ExecuteAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.UpdateRequestAuth().ConfigureAwait(false);
|
||||
var response = await this.Context.SendAsync(this.Context.Request, this.CancellationToken).ConfigureAwait(false);
|
||||
return response;
|
||||
}
|
||||
catch (ConnectorException ex)
|
||||
{
|
||||
var response = new HttpResponseMessage(ex.StatusCode)
|
||||
{
|
||||
Content = CreateJsonContent(ex.Message)
|
||||
};
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateRequestAuth()
|
||||
{
|
||||
string content;
|
||||
string host = this.Context.Request.RequestUri.Host;
|
||||
string uri = host.Contains("nonprod") ? "https://oauth2-tst.nonprod.jbhunt.com/oauth2provider/oauth/token" : "https://oauth2.jbhunt.com/oauth2provider/oauth/token";
|
||||
|
||||
var headers = this.Context.Request.Headers;
|
||||
|
||||
string body = $"grant_type=password&client_id={headers.GetValues("client_id").FirstOrDefault()}&client_secret={headers.GetValues("client_secret").FirstOrDefault()}&username={headers.GetValues("username").FirstOrDefault()}&password={headers.GetValues("password").FirstOrDefault()}";
|
||||
|
||||
using var tokenRequest = new HttpRequestMessage(HttpMethod.Post, uri)
|
||||
{
|
||||
Content = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded")
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using var tokenResponse = await this.Context.SendAsync(tokenRequest, this.CancellationToken).ConfigureAwait(false);
|
||||
content = await tokenResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
|
||||
|
||||
if (tokenResponse.IsSuccessStatusCode)
|
||||
{
|
||||
var jsonContent = JObject.Parse(content);
|
||||
string access_token = jsonContent["access_token"].ToString();
|
||||
|
||||
if (!string.IsNullOrEmpty(access_token))
|
||||
{
|
||||
this.Context.Request.Headers.Remove("client_id");
|
||||
this.Context.Request.Headers.Remove("client_secret");
|
||||
this.Context.Request.Headers.Remove("username");
|
||||
this.Context.Request.Headers.Remove("password");
|
||||
this.Context.Request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ConnectorException(HttpStatusCode.BadGateway, "Unable to get access_token from the response: " + content);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ConnectorException(tokenResponse.StatusCode, content);
|
||||
}
|
||||
}
|
||||
catch (HttpRequestException ex)
|
||||
{
|
||||
throw new ConnectorException(HttpStatusCode.BadGateway, "Unable to get tokenResponse: " + ex.Message, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public class ConnectorException : Exception
|
||||
{
|
||||
public ConnectorException(
|
||||
HttpStatusCode statusCode,
|
||||
string message,
|
||||
Exception innerException = null)
|
||||
: base(
|
||||
message,
|
||||
innerException)
|
||||
{
|
||||
this.StatusCode = statusCode;
|
||||
}
|
||||
|
||||
public HttpStatusCode StatusCode { get; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var error = new StringBuilder($"ConnectorException: Status code={this.StatusCode}, Message='{this.Message}'");
|
||||
var inner = this.InnerException;
|
||||
var level = 0;
|
||||
while (inner != null && level < 10)
|
||||
{
|
||||
level += 1;
|
||||
error.AppendLine($"Inner exception {level}: {inner.Message}");
|
||||
inner = inner.InnerException;
|
||||
}
|
||||
|
||||
error.AppendLine($"Stack trace: {this.StackTrace}");
|
||||
return error.ToString();
|
||||
}
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,211 @@
|
|||
{
|
||||
"properties": {
|
||||
"connectionParameters": {
|
||||
"environment": {
|
||||
"type": "string",
|
||||
"uiDefinition": {
|
||||
"displayName": "Environment: Sandbox or Production",
|
||||
"description": "JBHunt Sandbox environment or Production environment",
|
||||
"tooltip": "Select JBHunt sandbox environment or production environment to connect",
|
||||
"constraints": {
|
||||
"allowedValues": [
|
||||
{
|
||||
"text": "Production",
|
||||
"value": "https://api.jbhunt.com"
|
||||
},
|
||||
{
|
||||
"text": "Sandbox",
|
||||
"value": "https://api.nonprod.jbhunt.com"
|
||||
}
|
||||
],
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string",
|
||||
"uiDefinition": {
|
||||
"description": "Client Application Id",
|
||||
"displayName": "Client Application Id",
|
||||
"tooltip": "Client Id of Application registered with JBHunt",
|
||||
"constraints": {
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"client_secret": {
|
||||
"type": "securestring",
|
||||
"uiDefinition": {
|
||||
"description": "Client Application Secret",
|
||||
"displayName": "Client Application Secret",
|
||||
"tooltip": "Secret of Client Application registered with JBHunt",
|
||||
"constraints": {
|
||||
"clearText": false,
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"uiDefinition": {
|
||||
"displayName": "Username",
|
||||
"description": "Username of JBHunt account",
|
||||
"tooltip": "Provide JBHunt username",
|
||||
"constraints": {
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"type": "securestring",
|
||||
"uiDefinition": {
|
||||
"displayName": "Password",
|
||||
"description": "Password of JBHunt account",
|
||||
"tooltip": "Provide JBHunt account password",
|
||||
"constraints": {
|
||||
"clearText": false,
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"ordersapikey": {
|
||||
"type": "securestring",
|
||||
"uiDefinition": {
|
||||
"displayName": "Orders Api Key",
|
||||
"description": "API Key for JBHunt Orders APIs",
|
||||
"tooltip": "API Key for JBHunt Orders APIs",
|
||||
"constraints": {
|
||||
"clearText": false,
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"pricingapikey": {
|
||||
"type": "securestring",
|
||||
"uiDefinition": {
|
||||
"displayName": "Pricing Api Key",
|
||||
"description": "API Key for JBHunt Pricing APIs",
|
||||
"tooltip": "API Key for JBHunt Pricing APIs",
|
||||
"constraints": {
|
||||
"clearText": false,
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
},
|
||||
"trackitapikey": {
|
||||
"type": "securestring",
|
||||
"uiDefinition": {
|
||||
"displayName": "TrackIt Api Key",
|
||||
"description": "API Key for JBHunt TrackIt APIs",
|
||||
"tooltip": "API Key for JBHunt TrackIt APIs",
|
||||
"constraints": {
|
||||
"clearText": false,
|
||||
"required": "true"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"iconBrandColor": "#A03232",
|
||||
"capabilities": [],
|
||||
"policyTemplateInstances": [
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header- Content-Type",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "Content-Type",
|
||||
"x-ms-apimTemplateParameter.value": "application/json",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request"
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header- Client ID",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "client_id",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('client_id','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request"
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - Client Secret",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "client_secret",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('client_secret','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request"
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - Username",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "username",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('username','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request"
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - Password",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "password",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('password','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request"
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - Orders",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "Api-Key",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('ordersapikey','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request",
|
||||
"x-ms-apimTemplate-operationName": [
|
||||
"Create_order"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - Pricing",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "Api-Key",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('pricingapikey','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request",
|
||||
"x-ms-apimTemplate-operationName": [
|
||||
"Request_quote"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "setheader",
|
||||
"title": "Set HTTP header - TrackIt",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.name": "Api-Key",
|
||||
"x-ms-apimTemplateParameter.value": "@connectionParameters('trackitapikey','')",
|
||||
"x-ms-apimTemplateParameter.existsAction": "override",
|
||||
"x-ms-apimTemplate-policySection": "Request",
|
||||
"x-ms-apimTemplate-operationName": [
|
||||
"Find_orders"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"templateId": "dynamichosturl",
|
||||
"title": "Choose Host for connection",
|
||||
"parameters": {
|
||||
"x-ms-apimTemplateParameter.urlTemplate": "@connectionParameters('environment')"
|
||||
}
|
||||
}
|
||||
],
|
||||
"publisher": "Microsoft",
|
||||
"stackOwner": "J.B. Hunt Transport, Inc."
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче