Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W-16501195 Wr/api request graphql #6

Merged
merged 18 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
164 changes: 88 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,55 +1,7 @@
**NOTE: This template for sf plugins is not yet official. Please consult with the Platform CLI team before using this template.**

# plugin-template-sf

[![NPM](https://img.shields.io/npm/v/@salesforce/plugin-template-sf.svg?label=@salesforce/plugin-template-sf)](https://www.npmjs.com/package/@salesforce/plugin-template-sf) [![Downloads/week](https://img.shields.io/npm/dw/@salesforce/plugin-template-sf.svg)](https://npmjs.org/package/@salesforce/plugin-template-sf) [![License](https://img.shields.io/badge/License-BSD%203--Clause-brightgreen.svg)](https://raw.githubusercontent.com/salesforcecli/plugin-template-sf/main/LICENSE.txt)

## Using the template

This repository provides a template for creating a plugin for the Salesforce CLI. To convert this template to a working plugin:

1. Please get in touch with the Platform CLI team. We want to help you develop your plugin.
2. Generate your plugin:

```
sf plugins install dev
sf dev generate plugin
git init -b main
git add . && git commit -m "chore: initial commit"
```

3. Create your plugin's repo in the salesforcecli github org
4. When you're ready, replace the contents of this README with the information you want.

## Learn about `sf` plugins

Salesforce CLI plugins are based on the [oclif plugin framework](https://oclif.io/docs/introduction). Read the [plugin developer guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_plugins.meta/sfdx_cli_plugins/cli_plugins_architecture_sf_cli.htm) to learn about Salesforce CLI plugin development.

This repository contains a lot of additional scripts and tools to help with general Salesforce node development and enforce coding standards. You should familiarize yourself with some of the [node developer packages](#tooling) used by Salesforce. There is also a default circleci config using the [release management orb](https://github.com/forcedotcom/npm-release-management-orb) standards.

Additionally, there are some additional tests that the Salesforce CLI will enforce if this plugin is ever bundled with the CLI. These test are included by default under the `posttest` script and it is required to keep these tests active in your plugin if you plan to have it bundled.

### Tooling

- [@salesforce/core](https://github.com/forcedotcom/sfdx-core)
- [@salesforce/kit](https://github.com/forcedotcom/kit)
- [@salesforce/sf-plugins-core](https://github.com/salesforcecli/sf-plugins-core)
- [@salesforce/ts-types](https://github.com/forcedotcom/ts-types)
- [@salesforce/ts-sinon](https://github.com/forcedotcom/ts-sinon)
- [@salesforce/dev-config](https://github.com/forcedotcom/dev-config)
- [@salesforce/dev-scripts](https://github.com/forcedotcom/dev-scripts)

# Everything past here is only a suggestion as to what should be in your specific plugin's description

This plugin is bundled with the [Salesforce CLI](https://developer.salesforce.com/tools/sfdxcli). For more information on the CLI, read the [getting started guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_intro.htm).

We always recommend using the latest version of these commands bundled with the CLI, however, you can install a specific version or tag if needed.

## Install

```bash
sf plugins install @salesforce/plugin-template-sf@x.y.z
sf plugins install @salesforce/plugin-api
```

## Issues
Expand Down Expand Up @@ -107,59 +59,119 @@ sf plugins

<!-- commands -->

- [`sf api request graphql`](#sf-api-request-graphql)
- [`sf api request rest ENDPOINT`](#sf-api-request-rest-endpoint)

## `sf api request rest ENDPOINT`
## `sf api request graphql`

Make an authenticated HTTP request to Salesforce REST API and print the response.
Execute GraphQL statements

````
USAGE
$ sf api request rest ENDPOINT -o <value> [--flags-dir <value>] [--api-version <value>] [-i | -S Example:
report.xlsx] [-X GET|POST|PUT|PATCH|HEAD|DELETE|OPTIONS|TRACE] [-H key:value...] [--body file]
ARGUMENTS
ENDPOINT Salesforce API endpoint
$ sf api request graphql -o <value> --body file [--json] [--flags-dir <value>] [-S Example: report.xlsx | -i]
FLAGS
-H, --header=key:value... HTTP header in "key:value" format.
-S, --stream-to-file=Example: report.xlsx Stream responses to a file.
-X, --method=<option> [default: GET] HTTP method for the request.
<options: GET|POST|PUT|PATCH|HEAD|DELETE|OPTIONS|TRACE>
-i, --include Include the HTTP response status and headers in the output.
-o, --target-org=<value> (required) Username or alias of the target org. Not required if the
`target-org` configuration variable is already set.
--api-version=<value> Override the api version used for api requests made by this command
--body=file File to use as the body for the request. Specify "-" to read from standard
input; specify "" for an empty body.
--body=file (required) File or content with GraphQL statement. Specify "-" to read from
standard input.
GLOBAL FLAGS
--flags-dir=<value> Import flag values from a directory.
--json Format output as json.
DESCRIPTION
Execute GraphQL statements
Run any valid GraphQL statement via the /graphql
[API](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-about.html)
EXAMPLES
- List information about limits in the org with alias "my-org":
sf api request rest 'limits' --target-org my-org
- List all endpoints
sf api request rest '/'
- Get the response in XML format by specifying the "Accept" HTTP header:
sf api request rest 'limits' --target-org my-org --header 'Accept: application/xml'
- POST to create an Account object
sf api request rest 'sobjects/account' --body "{\"Name\" : \"Account from REST API\",\"ShippingCity\" : \"Boise\"}" --method POST
- or with a file 'info.json' containing
```json
{
"Name": "Demo",
"ShippingCity": "Boise"
- Runs the graphql query directly via the command line
sf api request graphql --body '{ "query": "query accounts { uiapi { query { Account { edges { node { Id \n Name { value } } } } } } }" }'
- Runs a mutation to create an Account, with an `example.txt` file, containing
```text
mutation AccountExample{
uiapi {
AccountCreate(input: {
Account: {
Name: "Trailblazer Express"
}
}) {
Record {
Id
Name {
value
}
}
}
}
}
````

$ sf api request graphql --body example.txt
will create a new account returning specified fields (Id, Name)

```
_See code: [src/commands/api/request/graphql.ts](https://github.com/salesforcecli/plugin-api/blob/v1.1.0/src/commands/api/request/graphql.ts)_
## `sf api request rest ENDPOINT`
Make an authenticated HTTP request to Salesforce REST API and print the response.
```

USAGE
$ sf api request rest ENDPOINT -o <value> [--flags-dir <value>] [--api-version <value>] [-i | -S Example:
report.xlsx] [-X GET|POST|PUT|PATCH|HEAD|DELETE|OPTIONS|TRACE] [-H key:value...] [--body file]

ARGUMENTS
ENDPOINT Salesforce API endpoint

FLAGS
-H, --header=key:value... HTTP header in "key:value" format.
-S, --stream-to-file=Example: report.xlsx Stream responses to a file.
-X, --method=<option> [default: GET] HTTP method for the request.
<options: GET|POST|PUT|PATCH|HEAD|DELETE|OPTIONS|TRACE>
-i, --include Include the HTTP response status and headers in the output.
-o, --target-org=<value> (required) Username or alias of the target org. Not required if the
`target-org` configuration variable is already set.
--api-version=<value> Override the api version used for api requests made by this command
--body=file File to use as the body for the request. Specify "-" to read from standard
input; specify "" for an empty body.

GLOBAL FLAGS
--flags-dir=<value> Import flag values from a directory.

EXAMPLES

- List information about limits in the org with alias "my-org":
sf api request rest 'limits' --target-org my-org
- List all endpoints
sf api request rest '/'
- Get the response in XML format by specifying the "Accept" HTTP header:
sf api request rest 'limits' --target-org my-org --header 'Accept: application/xml'
- POST to create an Account object
sf api request rest 'sobjects/account' --body "{\"Name\" : \"Account from REST API\",\"ShippingCity\" : \"Boise\"}" --method POST
- or with a file 'info.json' containing

```json
{
"Name": "Demo",
"ShippingCity": "Boise"
}
```

$ sf api request rest 'sobjects/account' --body info.json --method POST

- Update object
sf api request rest 'sobjects/account/<Account ID>' --body "{\"BillingCity\": \"San Francisco\"}" --method PATCH

```
_See code: [src/commands/api/request/rest.ts](https://github.com/salesforcecli/plugin-api/blob/0.1.0/src/commands/api/request/rest.ts)_
_See code: [src/commands/api/request/rest.ts](https://github.com/salesforcecli/plugin-api/blob/v1.1.0/src/commands/api/request/rest.ts)_
<!-- commandsstop -->
```
8 changes: 8 additions & 0 deletions command-snapshot.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
[
{
"alias": [],
"command": "api:request:graphql",
"flagAliases": [],
"flagChars": ["S", "i", "o"],
"flags": ["api-version", "body", "flags-dir", "include", "json", "stream-to-file", "target-org"],
"plugin": "@salesforce/plugin-api"
},
{
"alias": [],
"command": "api:request:rest",
Expand Down
46 changes: 46 additions & 0 deletions messages/graphql.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# summary

Execute GraphQL statements

# description

Run any valid GraphQL statement via the /graphql [API](https://developer.salesforce.com/docs/platform/graphql/guide/graphql-about.html)

# examples

- Runs the graphql query directly via the command line

<%= config.bin %> <%= command.id %> --body "query accounts { uiapi { query { Account { edges { node { Id \n Name { value } } } } } } }"

- Runs a mutation to create an Account, with an `example.txt` file, containing

```text
mutation AccountExample{
uiapi {
AccountCreate(input: {
Account: {
Name: "Trailblazer Express"
}
}) {
Record {
Id
Name {
value
}
}
}
}
}
```

<%= config.bin %> <%= command.id %> --body example.txt

will create a new account returning specified fields (Id, Name)

# flags.header.summary

HTTP header in "key:value" format.

# flags.body.summary

File or content with GraphQL statement. Specify "-" to read from standard input.
8 changes: 0 additions & 8 deletions messages/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ Make an authenticated HTTP request to Salesforce REST API and print the response

<%= config.bin %> <%= command.id %> 'sobjects/account/<Account ID>' --body "{\"BillingCity\": \"San Francisco\"}" --method PATCH

# flags.include.summary

Include the HTTP response status and headers in the output.

# flags.method.summary

HTTP method for the request.
Expand All @@ -47,10 +43,6 @@ HTTP method for the request.

HTTP header in "key:value" format.

# flags.stream-to-file.summary

Stream responses to a file.

# flags.body.summary

File to use as the body for the request. Specify "-" to read from standard input; specify "" for an empty body.
7 changes: 7 additions & 0 deletions messages/shared.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# flags.include.summary

Include the HTTP response status and headers in the output.

# flags.stream-to-file.summary

Stream responses to a file.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@salesforce/core": "^8.4.0",
"@salesforce/kit": "^3.2.1",
"@salesforce/sf-plugins-core": "^11.3.2",
"@salesforce/ts-types": "^2.0.12",
"ansis": "^3.3.2",
"got": "^13.0.0",
"proxy-agent": "^6.4.0"
Expand Down
63 changes: 63 additions & 0 deletions src/commands/api/request/graphql.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2023, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/

import fs from 'node:fs';
import * as os from 'node:os';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages, Org, SFDX_HTTP_HEADERS } from '@salesforce/core';
import { ProxyAgent } from 'proxy-agent';
import { includeFlag, sendAndPrintRequest, streamToFileFlag } from '../../../shared/shared.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-api', 'graphql');

export default class Graphql extends SfCommand<void> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
public static readonly state = 'beta';

public static readonly flags = {
'target-org': Flags.requiredOrg(),
'api-version': Flags.orgApiVersion(),
'stream-to-file': streamToFileFlag,
include: includeFlag,
body: Flags.string({
summary: messages.getMessage('flags.body.summary'),
allowStdin: true,
helpValue: 'file',
required: true,
}),
};

public async run(): Promise<void> {
const { flags } = await this.parse(Graphql);

const org = flags['target-org'];
const streamFile = flags['stream-to-file'];
const apiVersion = flags['api-version'] ?? (await org.retrieveMaxApiVersion());
const body = `{"query":"${(fs.existsSync(flags.body) ? fs.readFileSync(flags.body, 'utf8') : flags.body)
.replaceAll(os.EOL, '\\n')
.replaceAll('"', '\\"')}"}`;
const url = new URL(`${org.getField<string>(Org.Fields.INSTANCE_URL)}/services/data/v${apiVersion}/graphql`);

await org.refreshAuth();

const options = {
agent: { https: new ProxyAgent() },
headers: {
...SFDX_HTTP_HEADERS,
Authorization: `Bearer ${org.getConnection(apiVersion).getConnectionOptions().accessToken!}`,
},
body,
throwHttpErrors: false,
followRedirect: false,
};

await sendAndPrintRequest({ streamFile, url, options, include: flags.include, this: this });
}
}
Loading
Loading