Skip to content

Commit

Permalink
feat: enhance existing Execute REST API command to remember last used…
Browse files Browse the repository at this point in the history
… APIs
  • Loading branch information
Codeneos committed Dec 18, 2023
1 parent 2deeaff commit e24bdf5
Showing 1 changed file with 117 additions and 26 deletions.
143 changes: 117 additions & 26 deletions packages/vscode-extension/src/commands/execRestApiCommand.ts
Original file line number Diff line number Diff line change
@@ -1,53 +1,144 @@
import * as vscode from 'vscode';

import { HttpMethod, HttpRequestInfo } from '@vlocode/salesforce';
import { Timer } from '@vlocode/util';

import { VlocodeCommand } from '../constants';
import { vscodeCommand } from '../lib/commandRouter';
import { HttpMethod } from '@vlocode/salesforce';
import { Timer } from '@vlocode/util';
import * as vscode from 'vscode';
import { ApiRequestDocumentParser } from '../lib/salesforce/apiRequestDocumentParser';
import MetadataCommand from './metadata/metadataCommand';

@vscodeCommand(VlocodeCommand.execRestApi)
export default class ExecuteRestApiCommand extends MetadataCommand {
public async execute() {
let url = await vscode.window.showInputBox({ placeHolder: 'Enter the Salesforce API endpoint', ignoreFocusOut: true });

private httpMethodOptions: Array<{ label: string, method: HttpMethod, allowsBody?: boolean }> = [
{ label: 'GET', method: 'GET' },
{ label: 'POST', method: 'POST', allowsBody: true },
{ label: 'PATCH', method: 'PATCH', allowsBody: true },
{ label: 'PUT', method: 'PUT', allowsBody: true },
{ label: 'DELETE', method: 'DELETE' }
];

public async execute(args?: HttpRequestInfo | vscode.Uri) {
if (args instanceof vscode.Uri) {
const document = await vscode.workspace.openTextDocument(args);
await this.executeRequestFromDocument(document);
} else if (typeof args === 'object') {
await this.executeRequest(args);
} else {
const request = await this.showRecentRequests() ?? await this.showRequestInput();
request && await this.executeRequest(request);
}
}

private async executeRequestFromDocument(document: vscode.TextDocument) {
const request = await ApiRequestDocumentParser.parse(document);
await this.executeRequest(request);
}

private async showRequestInput() : Promise<HttpRequestInfo | undefined> {
const url = await vscode.window.showInputBox({
placeHolder: 'Enter the relative Salesforce API endpoint URI',
ignoreFocusOut: true
});

if (!url) {
return;
}

const method = await vscode.window.showQuickPick(
[ 'GET', 'POST' ],
{ placeHolder: 'Select HTTP Method', ignoreFocusOut: true }) as HttpMethod;
if (!method) {
const selectedMethod = await vscode.window.showQuickPick(
this.httpMethodOptions,
{
placeHolder: 'Select HTTP Method',
ignoreFocusOut: true
}
);

if (!selectedMethod) {
return;
}

// transform into valid REST API
if (!url.startsWith('/services')) {
// assume APEX rest url when not prefixed with services
url = `/services/apexrest/${url}`.replace(/[/]+/g, '/');
const body = selectedMethod.allowsBody
? await vscode.window.showInputBox({
placeHolder: 'Enter POST body',
ignoreFocusOut: true
}) : undefined;

return {
url,
method: selectedMethod.method,
body
};
}

private async showRecentRequests() : Promise<HttpRequestInfo | undefined> {
const recent = this.context.recent.get<HttpRequestInfo>('apiRequests');
if (!recent.length) {
return;
}

let body;
if (method == 'POST') {
body = await vscode.window.showInputBox({ placeHolder: 'Enter POST body', ignoreFocusOut: true });
if (!body) {
return;
const options = [
...recent.map(r => ({ label: `${r.method} ${r.url}`, request: r })),
...[{
label: '',
kind: vscode.QuickPickItemKind.Separator
},{
label: '$(add) New request',
request: undefined
},{
label: '$(trashcan) Clear recent requests',
action: 'clear'
}]
];

const selected = await vscode.window.showQuickPick(options, {
placeHolder: 'Select recent request',
ignoreFocusOut: true
});

if (selected) {
if ('request' in selected) {
return selected.request;
}

if ('action' in selected && selected.action === 'clear') {
this.context.recent.clear('apiRequests');
}
}
}

private async executeRequest(request: HttpRequestInfo) {
// normalize request
request.method = request.method.toUpperCase() as HttpMethod;
if (!request.url.startsWith('/services')) {
// assume APEX rest url when not prefixed with services
request.url = `/services/apexrest/${request.url}`.replace(/[/]+/g, '/');
}

// add to recent requests
this.context.recent.add('apiRequests', request, {
equals: (a, b) => a.method === b.method && a.url === b.url
});

this.logger.info(`Invoking ${url} as ${method}`);
const timer = new Timer();
const connection = await this.salesforce.getJsForceConnection();
const request = { method, url, body };
const response = await this.vlocode.withActivity({
progressTitle: `${method} ${url}...`,
progressTitle: `${request.method} ${request.url}...`,
location: vscode.ProgressLocation.Notification,
cancellable: false
}, () => connection.request(request));
this.logger.info(`${method} ${url} [${timer.stop()}]`);
}, async () => {
const connection = await this.salesforce.getJsForceConnection();
return await connection.request(request);
});
this.logger.info(`${request.method} ${request.url} [${timer.stop()}]`);

const responseDocument = await vscode.workspace.openTextDocument({
language: 'json',
content: JSON.stringify(response, null, 4)
});

const responseDocument = await vscode.workspace.openTextDocument({ language: 'json', content: JSON.stringify(response, null, 4) });
if (responseDocument) {
void vscode.window.showTextDocument(responseDocument);
}
}
}
}

0 comments on commit e24bdf5

Please sign in to comment.