From f8822e549bd5ee408f076106df35ffe628f4fa4c Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Wed, 26 Jun 2024 16:24:56 -0300 Subject: [PATCH 1/8] chore(oauth): add client credentials example --- src/partials/document/oauth2.html.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/partials/document/oauth2.html.md b/src/partials/document/oauth2.html.md index 73428d9..bedca61 100644 --- a/src/partials/document/oauth2.html.md +++ b/src/partials/document/oauth2.html.md @@ -92,3 +92,23 @@ console.log("User ID: " + userInfo.id); console.log("Org ID: " + userInfo.organizationId); ``` +### Client Credentials Flow (OAuth 2.0 Client Credentials Flow) + +Similar to the JWT example, just pass the client id and secret from your connected app and use the `client_credentials` grant type. + +For more information about the setup, see: https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_client_credentials_flow.htm&type=5 + +```javascript +import { Connection } from 'jsforce'; + +const conn = new jsforce.Connection({ + instanceUrl: '', + oauth2: { + clientId : '', + clientSecret : '', + loginUrl + }, +}); + +const userInfo = await conn.authorize({ grant_type: "client_credentials" }) +``` From 08774412cb0cec7bb4e671deeef15f419b282257 Mon Sep 17 00:00:00 2001 From: Austin Turner Date: Sun, 27 Oct 2019 11:07:11 -0600 Subject: [PATCH 2/8] Added section for request Added section for working with connection#request() This includes information on how to use the API as well as a number of examples There are a large number of github issues related to this use-case, so hopefully this PR will reduce the number of issues/questions that people have in the future --- src/documents/document/index.html.eco | 2 + src/partials/document/request.html.md | 103 ++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/partials/document/request.html.md diff --git a/src/documents/document/index.html.eco b/src/documents/document/index.html.eco index e2566aa..b3f9a15 100644 --- a/src/documents/document/index.html.eco +++ b/src/documents/document/index.html.eco @@ -47,4 +47,6 @@ These docs are for jsforce v3. <%- @partial('document/tooling') %> +<%- @partial('document/request') %> + <%- @partial('document/advanced') %> diff --git a/src/partials/document/request.html.md b/src/partials/document/request.html.md new file mode 100644 index 0000000..26b42aa --- /dev/null +++ b/src/partials/document/request.html.md @@ -0,0 +1,103 @@ +--- +--- + +## Request + +Make REST api calls to APIs that are not explicitly supported by JSForce. + +### Setting the URL + +The Endpoint URL can be in one of the following formats: + +- Absolute URL: `https://na1.salesforce.com/services/data/v32.0/sobjects/Account/describe`. +- Relative path from root: `/services/data/v32.0/sobjects/Account/describe`. +- Relative path from version root: `/sobjects/Account/describe`. + - This is only supported if you have explicitly set a default version. + +### Making Requests + +You can use `Connection#request()` to make api requests. + +For GET requests, you can pass in a string URL. + +```javascript +/* @interactive */ +conn.request('/services/data/v47.0/ui-api/object-info').then(response => { + console.log(response); +}); +``` + +If you prefer to use callbacks instead of promises, pass a callback as the second parameter. + +```javascript +conn.request('/services/data/v47.0/ui-api/object-info', function(err, response) { + console.log(response); +}); +``` + +For other HTTP methods, you can pass an object to the request method. Ensure that you serialize the body of the request. + +```javascript +/* @interactive */ +// Bulk API 2.0 - Query +const requestBody = { + operation: 'query', + query: 'SELECT Id, Name FROM Account LIMIT 1000', +}; + +conn + .request({ + method: 'POST', + url: '/services/data/v47.0/jobs/query', + body: JSON.stringify(requestBody), + headers: { + 'content-type': 'application/json', + }, + }) + .then(response => { + console.log(response); + }); +``` + +#### Request Helper Methods + +In addition to `Connection#request()`, JSForce provides the following helper methods that can also be used: + +- `Connection#requestGet()` +- `Connection#requestPatch()` +- `Connection#requestPost()` +- `Connection#requestPut()` +- `Connection#requestDelete()` + +For `requestPatch`, `requestPost` and `requestPut`, these will be serialized automatically and the `content-type` will be set to `application/json`. + +```javascript +/* @interactive */ +const requestBody = { + operation: 'query', + query: 'SELECT Id, Name FROM Account LIMIT 1000', +}; + +conn.requestPost('/services/data/v47.0/jobs/query', requestBody).then(response => { + console.log(response); +}); +``` + +#### Request HTTP Options + +All request methods allow setting HTTP options to be passed to the HTTP request. + +| Name | Type | Description | +| ----------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| responseType | string | overrides the content-type from the response to change how the response is parsed. Valid values are `text/xml`, `application/xml`, `application/json`, `text/csv`. If you do not want JSForce to auto-parse the response, set this to any other value, e.x. `text`. | +| noContentResponse | any | Alternative response when no content returned in response (= HTTP 204) | +| transport | Transport | Transport for http api - you should not need to set this option. | + +If you would like to opt-out of parsing, you can set the `responseType` to text. This is useful if you want the raw response from Salesforce instead of having the results automatically parsed. + +```javascript +// Get raw CSV data instead of allowing JSForce to parse the CSV to JSON +requestGet('/services/data/v47.0/jobs/query/7502J00000LYZC4QAP/results', { responseType: 'text' }).then(response => { + console.log(response); +}); +``` From c42cb4e723665b2b6a8bc4d7ab345d612edd6b6e Mon Sep 17 00:00:00 2001 From: Andrew Plummer Date: Tue, 30 Jun 2020 15:54:58 +0100 Subject: [PATCH 3/8] Fix Salesforrce typo --- src/partials/document/connection.html.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/partials/document/connection.html.md b/src/partials/document/connection.html.md index 8c44d23..9508ce8 100644 --- a/src/partials/document/connection.html.md +++ b/src/partials/document/connection.html.md @@ -77,7 +77,7 @@ const jsforce = require('jsforce'); const conn = new jsforce.Connection({ instanceUrl : '', - accessToken : '' + accessToken : '' }); ``` @@ -97,7 +97,7 @@ const conn = new jsforce.Connection({ redirectUri : '' }, instanceUrl : '', - accessToken : '', + accessToken : '', refreshToken : '' }); conn.on("refresh", (accessToken, res) => { From e9816dffe2696f240a0fda597187b747c08a2380 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Thu, 27 Jun 2024 11:48:41 -0300 Subject: [PATCH 4/8] chore: doc HTTP headers opts --- src/partials/document/crud.html.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/partials/document/crud.html.md b/src/partials/document/crud.html.md index d018988..53cb53d 100644 --- a/src/partials/document/crud.html.md +++ b/src/partials/document/crud.html.md @@ -220,6 +220,26 @@ const rets = await conn.sobject('Account') console.log('processed: ' + rets.length); ``` +### HTTP headers + +You can pass a `headers` object containing REST API headers on any CRUD operation: + +```javascript +const rets = await conn.sobject('Account') + .create( + accounts, + { + allowRecursive: true, + headers: { + 'Sforce-Duplicate-Rule-Header': 'allowSave=true' + } + } + ); +``` + +For more info about supported headers, see: +https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/headers.htm + ### Update / Delete Queried Records If you want to update/delete records in Salesforce that match a specific condition in bulk, From 568dc99748c08b95401b5d2979fbf36b97ab739d Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Thu, 27 Jun 2024 18:04:39 -0300 Subject: [PATCH 5/8] chore: add cors section --- src/documents/document/index.html.eco | 2 ++ src/partials/document/cors.html.md | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 src/partials/document/cors.html.md diff --git a/src/documents/document/index.html.eco b/src/documents/document/index.html.eco index b3f9a15..896ea47 100644 --- a/src/documents/document/index.html.eco +++ b/src/documents/document/index.html.eco @@ -49,4 +49,6 @@ These docs are for jsforce v3. <%- @partial('document/request') %> +<%- @partial('document/cors') %> + <%- @partial('document/advanced') %> diff --git a/src/partials/document/cors.html.md b/src/partials/document/cors.html.md new file mode 100644 index 0000000..fd2bea1 --- /dev/null +++ b/src/partials/document/cors.html.md @@ -0,0 +1,7 @@ +## CORS + +If you're getting CORS-related errors when using jsforce in the browser it might be that the API being used doesn't support CORS, see: +https://help.salesforce.com/s/articleView?id=sf.extend_code_cors.htm&type=5 + +For those cases you'll need to the `jsforce-ajax-proxy` proxy server, check the README for setup instructions: +https://github.com/jsforce/jsforce-ajax-proxy/ From f7887c8dbddaf70c21b0cf298ac8cd8d312db67c Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Thu, 27 Jun 2024 19:50:41 -0300 Subject: [PATCH 6/8] chore: improve query builder docs --- src/partials/document/query.html.md | 58 +++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/partials/document/query.html.md b/src/partials/document/query.html.md index c5e0aaf..fa13c79 100644 --- a/src/partials/document/query.html.md +++ b/src/partials/document/query.html.md @@ -209,3 +209,61 @@ await conn.sobject("Contact") }); ``` +#### Conditionals + +You can define multiple `AND`/`OR` conditional expressions by passing them in an array: +```javascript +// The following code gets translated to this soql query: +// SELECT Name FROM Contact WHERE LastName LIKE 'A%' OR LastName LIKE 'B%' +// +const contacts = await conn.sobject("Contact") + .find({ + $or: [{ LastName: { $like : 'A%' }}, { LastName: { $like : 'B%'} }] + }, ['Name']) + +console.log(contacts); +``` + +#### Dates + +`jsforce.Sfdate` provides some utilities to help working dates in SOQL: +https://jsforce.github.io/jsforce/classes/date.SfDate.html + +Literals like `YESTERDAY`, `TODAY`, `TOMORROW`: + +```javascript +// SELECT Name FROM Account WHERE PersonBirthDate = TODAY +// +const accounts = await conn.sobject("Account") + .find({ + PersonBirthDate: jsforce.SfDate.TODAY + }, ['Name']); + +console.log(accounts); +``` + +Dynamic N days/weeks/month/quarter functions: + +```javascript +// SELECT Name FROM Account WHERE PersonBirthDate = LAST_N_WEEKS:5 +// +const accounts = await conn.sobject("Account") + .find({ + PersonBirthDate: jsforce.SfDate.LAST_N_WEEKS(5) + }, ['Name']); + +console.log(accounts); +``` + +Even parse a JS `Date` object: +```javascript +// SELECT Name FROM Account WHERE PersonBirthDate = 2024-06-27 +// +const accounts = await conn.sobject("Account") + .find({ + PersonBirthDate: jsforce.SfDate.toDateLiteral(new Date()) + }, ['Name']); + +console.log(accounts); +``` + From fbca1ad90f491eee378244551b718ee7173efa5c Mon Sep 17 00:00:00 2001 From: Cristian Dominguez Date: Wed, 3 Jul 2024 13:49:47 -0300 Subject: [PATCH 7/8] chore: update request examples --- src/partials/document/request.html.md | 40 ++++++++++++--------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/src/partials/document/request.html.md b/src/partials/document/request.html.md index 26b42aa..b8ef364 100644 --- a/src/partials/document/request.html.md +++ b/src/partials/document/request.html.md @@ -16,23 +16,21 @@ The Endpoint URL can be in one of the following formats: ### Making Requests -You can use `Connection#request()` to make api requests. +You can use `Connection.request()` to make api requests. For GET requests, you can pass in a string URL. ```javascript /* @interactive */ -conn.request('/services/data/v47.0/ui-api/object-info').then(response => { - console.log(response); -}); +const res = await conn.request('/services/data/v47.0/ui-api/object-info'); +console.log(res) ``` If you prefer to use callbacks instead of promises, pass a callback as the second parameter. ```javascript -conn.request('/services/data/v47.0/ui-api/object-info', function(err, response) { - console.log(response); -}); +const res = await conn.request('/services/data/v47.0/ui-api/object-info'); +console.log(res) ``` For other HTTP methods, you can pass an object to the request method. Ensure that you serialize the body of the request. @@ -45,7 +43,7 @@ const requestBody = { query: 'SELECT Id, Name FROM Account LIMIT 1000', }; -conn +const res = await conn .request({ method: 'POST', url: '/services/data/v47.0/jobs/query', @@ -53,21 +51,19 @@ conn headers: { 'content-type': 'application/json', }, - }) - .then(response => { - console.log(response); }); +console.log(res) ``` #### Request Helper Methods -In addition to `Connection#request()`, JSForce provides the following helper methods that can also be used: +In addition to `Connection.request()`, JSForce provides the following helper methods that can also be used: -- `Connection#requestGet()` -- `Connection#requestPatch()` -- `Connection#requestPost()` -- `Connection#requestPut()` -- `Connection#requestDelete()` +- `Connection.requestGet()` +- `Connection.requestPatch()` +- `Connection.requestPost()` +- `Connection.requestPut()` +- `Connection.requestDelete()` For `requestPatch`, `requestPost` and `requestPut`, these will be serialized automatically and the `content-type` will be set to `application/json`. @@ -78,9 +74,8 @@ const requestBody = { query: 'SELECT Id, Name FROM Account LIMIT 1000', }; -conn.requestPost('/services/data/v47.0/jobs/query', requestBody).then(response => { - console.log(response); -}); +const res = await conn.requestPost('/services/data/v47.0/jobs/query', requestBody); +console.log(res); ``` #### Request HTTP Options @@ -97,7 +92,6 @@ If you would like to opt-out of parsing, you can set the `responseType` to text. ```javascript // Get raw CSV data instead of allowing JSForce to parse the CSV to JSON -requestGet('/services/data/v47.0/jobs/query/7502J00000LYZC4QAP/results', { responseType: 'text' }).then(response => { - console.log(response); -}); +const res = await conn.requestGet('/services/data/v47.0/jobs/query/7502J00000LYZC4QAP/results', { responseType: 'text' }); +console.log(res); ``` From c0e48fe9581b9b7e99ab7dc65eaaedf775d91da1 Mon Sep 17 00:00:00 2001 From: Cristian Dominguez <6853656+cristiand391@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:34:07 -0300 Subject: [PATCH 8/8] Update src/partials/document/cors.html.md Co-authored-by: Steve Hetzel --- src/partials/document/cors.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/partials/document/cors.html.md b/src/partials/document/cors.html.md index fd2bea1..2d5142a 100644 --- a/src/partials/document/cors.html.md +++ b/src/partials/document/cors.html.md @@ -3,5 +3,5 @@ If you're getting CORS-related errors when using jsforce in the browser it might be that the API being used doesn't support CORS, see: https://help.salesforce.com/s/articleView?id=sf.extend_code_cors.htm&type=5 -For those cases you'll need to the `jsforce-ajax-proxy` proxy server, check the README for setup instructions: +For those cases you'll need to use the `jsforce-ajax-proxy` proxy server, check the README for setup instructions: https://github.com/jsforce/jsforce-ajax-proxy/