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

Add graphql API support for testing environment #213

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 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
9 changes: 7 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 52 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-apimanagement",
"displayName": "Azure API Management",
"description": "An Azure API Management extension for Visual Studio Code.",
"version": "1.0.3",
"version": "1.0.3-beta",
"publisher": "ms-azuretools",
"icon": "resources/apim-icon-newone.png",
"aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217",
Expand Down Expand Up @@ -40,15 +40,20 @@
"onCommand:azureApiManagement.deleteOperation",
"onCommand:azureApiManagement.importOpenApiByFile",
"onCommand:azureApiManagement.importOpenApiByLink",
"onCommand:azureApiManagement.importGraphqlAPIByLink",
"onCommand:azureApiManagement.testOperation",
"onCommand:azureApiManagement.importGraphqlSchemaByFile",
"onCommand:azureApiManagement.openInPortal",
"onCommand:azureApiManagement.showApi",
"onCommand:azureApiManagement.showArmApi",
"onCommand:azureApiManagement.showArmGraphqlApi",
"onCommand:azureApiManagement.showGraphqlAPIQuery",
"onCommand:azureApiManagement.showArmApiOperation",
"onCommand:azureApiManagement.showArmProduct",
"onCommand:azureApiManagement.showServicePolicy",
"onCommand:azureApiManagement.showApiPolicy",
"onCommand:azureApiManagement.showOperationPolicy",
"onCommand:azureApiManagement.showGraphqlSchema",
"onCommand:azureApiManagement.createNamedValue",
"onCommand:azureApiManagement.deleteNamedValue",
"onCommand:azureApiManagement.updateNamedValue",
Expand Down Expand Up @@ -169,11 +174,26 @@
"title": "%azureApiManagement.importOpenApiByLink%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.importGraphqlAPIByLink",
"title": "%azureApiManagement.importGraphqlAPIByLink%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.testOperation",
"title": "%azureApiManagement.testOperation%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.importGraphqlSchemaByFile",
"title": "%azureApiManagement.importGraphqlSchemaByFile%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.showGraphqlSchema",
"title": "%azureApiManagement.showGraphqlSchema%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.openInPortal",
"title": "%azureApiManagement.openInPortal%",
Expand Down Expand Up @@ -215,6 +235,16 @@
"title": "%azureApiManagement.showArmApi%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.showGraphqlAPIQuery",
"title": "%azureApiManagement.showGraphqlAPIQuery%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.showArmGraphqlApi",
"title": "%azureApiManagement.showArmGraphqlApi%",
"category": "Azure API Management"
},
{
"command": "azureApiManagement.showArmApiOperation",
"title": "%azureApiManagement.showArmApiOperation%",
Expand Down Expand Up @@ -491,6 +521,11 @@
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementApis",
"group": "1@2"
},
{
"command": "azureApiManagement.importGraphqlAPIByLink",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementApis",
"group": "1@3"
},
{
"command": "azureApiManagement.importFunctionApp",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementApis",
Expand Down Expand Up @@ -581,6 +616,21 @@
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementNamedValues",
"group": "1@1"
},
{
"command": "azureApiManagement.showGraphqlAPIQuery",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementGraphqlObjectType",
"group": "1@1"
},
{
"command": "azureApiManagement.importGraphqlSchemaByFile",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementGraphql",
"group": "1@1"
},
{
"command": "azureApiManagement.showGraphqlSchema",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementGraphql",
"group": "1@2"
},
{
"command": "azureApiManagement.deleteNamedValue",
"when": "view == azureApiManagementExplorer && viewItem == azureApiManagementNamedValue",
Expand Down Expand Up @@ -723,6 +773,7 @@
"await-notify": "1.0.1",
"decompress": "^4.2.1",
"fs-extra": "^4.0.2",
"graphql": "^15.5.0",
"guid-typescript": "^1.0.9",
"gulp-decompress": "^3.0.0",
"gulp-download": "0.0.1",
Expand Down
5 changes: 5 additions & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,25 @@
"azureApiManagement.openInPortal": "Open in Portal",
"azureApiManagement.importOpenApiByFile": "Import from OpenAPI file",
"azureApiManagement.importOpenApiByLink": "Import from OpenAPI link",
"azureApiManagement.importGraphqlAPIByLink": "Import Graphql API from OpenAPI link",
"azureApiManagement.showExplorer": "Show or hide the Azure API Management Explorer.",
"azureApiManagement.showSavePrompt": "Show warning dialog on remote file uploading.",
"azureApiManagement.createService": "Create API Management in Azure",
"azureApiManagement.deleteService": "Delete API Management",
"azureApiManagement.copySubscriptionKey" : "Copy Subscription Key",
"azureApiManagement.showApi": "Edit OpenAPI",
"azureApiManagement.showArmApi": "Edit API",
"azureApiManagement.showArmGraphqlApi": "Edit Graphql API",
"azureApiManagement.showArmApiOperation": "Edit Operation",
"azureApiManagement.showGraphqlAPIQuery": "Test Grapql Query",
"azureApiManagement.showServicePolicy": "Edit Global policy",
"azureApiManagement.showApiPolicy": "Edit API policy",
"azureApiManagement.showOperationPolicy": "Edit Operation policy",
"azureApiManagement.deleteApi": "Delete API",
"azureApiManagement.deleteOperation": "Delete Operation",
"azureApiManagement.testOperation": "Test Operation",
"azureApiManagement.importGraphqlSchemaByFile": "Import Graphql API schema file",
"azureApiManagement.showGraphqlSchema": "Open Schema",
"azureApiManagement.advancedCreationDescription":"Enables advanced creation of Azure API Management Instance, which will prompt for several additional values instead of using a default.",
"azureApiManagement.createNamedValue": "Create Named value",
"azureApiManagement.deleteNamedValue": "Delete Named value",
Expand Down
25 changes: 25 additions & 0 deletions src/azure/apim/TempApiContract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { AuthenticationSettingsContract, Protocol, SubscriptionKeyParameterNamesContract } from "@azure/arm-apimanagement/src/models";

export interface IApiContract {
id: string;
name: string;
properties: {
displayName: string;
apiRevision: string;
authenticationSettings?: AuthenticationSettingsContract;
description: string;
isCurrent: boolean;
path: string;
protocols?: Protocol[];
serviceUrl: string;
subscriptionKeyParameterNames?: SubscriptionKeyParameterNamesContract;
subscriptionRequired?: boolean;
// tslint:disable-next-line: no-reserved-keywords
type: string;
};
}
18 changes: 18 additions & 0 deletions src/azure/apim/TempSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

export class TempSchema {
public id: string;
public name: string;
// tslint:disable-next-line: no-reserved-keywords
public type: string;
public location?: string;
public properties: {
contentType: string,
document: {
value: string
}
};
}
81 changes: 81 additions & 0 deletions src/commands/createGraphqlApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

//import { ServiceClient } from "@azure/ms-rest-js";
import requestPromise from "request-promise";
import { ProgressLocation, window } from "vscode";
import { IActionContext } from "../../extension.bundle";
import { SharedAccessToken } from "../constants";
import { ApisTreeItem, IApiTreeItemContext } from "../explorer/ApisTreeItem";
import { ServiceTreeItem } from "../explorer/ServiceTreeItem";
import { ext } from "../extensionVariables";
import { localize } from "../localize";
import { apiUtil } from "../utils/apiUtil";

// tslint:disable-next-line: export-name
export async function createGraphqlApi(context: IActionContext & Partial<IApiTreeItemContext>, node?: ApisTreeItem): Promise<void> {
if (!node) {
const serviceNode = <ServiceTreeItem>await ext.tree.showTreeItemPicker(ServiceTreeItem.contextValue, context);
node = serviceNode.apisTreeItem;
}

const link = await askLink();
const apiName = await apiUtil.askApiName();
const path = await apiUtil.askPath();
const body = {
name : apiName,
properties: {
displayName: apiName,
subscriptionRequired: true,
serviceUrl: link,
path: path,
type: "graphql",
protocols: [
"https"
]
}
};

await window.withProgress(
{
location: ProgressLocation.Notification,
title: localize("", `Creating new Graphql API'...`),
cancellable: false
},
async () => {
const requestOptions : requestPromise.RequestPromiseOptions = {
method: "PUT",
headers: {
Authorization: SharedAccessToken
},
body: JSON.stringify(body)
};
// tslint:disable-next-line: no-non-null-assertion
await <Thenable<string>>requestPromise(`https://${node!.root.serviceName}.management.preview.int-azure-api.net/subscriptions/${node!.root.subscriptionId}/resourceGroups/${node!.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node!.root.serviceName}/apis/${apiName}?api-version=2021-04-01-preview`, requestOptions).promise();
}
).then(async () => {
window.showInformationMessage(localize("", `New Graphql API has been created!`));
node?.refresh(context);
});

}

async function askLink() : Promise<string> {
const promptStr: string = localize('apiLinkPrompt', 'Specify a Graphql OpenAPI link.');
return (await ext.ui.showInputBox({
prompt: promptStr,
placeHolder: 'https://',
validateInput: async (value: string): Promise<string | undefined> => {
value = value ? value.trim() : '';
const regexp = /http(s?):\/\/[\d\w][\d\w]*(\.[\d\w][\d\w-]*)*(:\d+)?(\/[\d\w-\.\?,'/\\\+&amp;=:%\$#_]*)?/;
const isUrlValid = regexp.test(value);
if (!isUrlValid) {
return localize("invalidOpenApiLink", "Provide a valid link. example - https://petstore.swagger.io/v2/swagger.json");
} else {
return undefined;
}
}
})).trim();
}
76 changes: 76 additions & 0 deletions src/commands/importGraphqlSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.md in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as fse from 'fs-extra';
import requestPromise from 'request-promise';
import { OpenDialogOptions, ProgressLocation, Uri, window, workspace } from "vscode";
import { IActionContext } from "vscode-azureextensionui";
import { SharedAccessToken } from '../constants';
import { GraphqlApiTreeItem } from "../explorer/GraphqlApiTreeItem";
import { ServiceTreeItem } from "../explorer/ServiceTreeItem";
import { ext } from "../extensionVariables";
import { localize } from '../localize';

// tslint:disable-next-line: export-name
export async function importGraphqlSchemaByFile(actionContext: IActionContext, node?: GraphqlApiTreeItem): Promise<void> {
if (!node) {
const serviceNode = <GraphqlApiTreeItem>await ext.tree.showTreeItemPicker(ServiceTreeItem.contextValue, actionContext);
node = serviceNode;
}

const uris = await askSchemaDocument();
const uri = uris[0];
// tslint:disable-next-line: no-unsafe-any
const fileContent = await fse.readFile(uri.fsPath);
const documentString = fileContent.toString();
const body = {
properties: {
contentType: "application/vnd.ms-azure-apim.graphql.schema",
document: {
value: documentString
}
}
};
const requestOptions : requestPromise.RequestPromiseOptions = {
method: "PUT",
headers: {
Authorization: SharedAccessToken
},
body: JSON.stringify(body)
};
window.withProgress(
{
location: ProgressLocation.Notification,
title: localize("addSchema", `Add Graphql Schema to Graphql API ${node.root.apiName} ...`),
cancellable: false
},
// tslint:disable-next-line:no-non-null-assertion
async () => {
await <Thenable<string>>requestPromise(
`https://${node?.root.serviceName}.management.preview.int-azure-api.net/subscriptions/${node?.root.subscriptionId}/resourceGroups/${node?.root.resourceGroupName}/providers/Microsoft.ApiManagement/service/${node?.root.serviceName}/apis/${node?.root.apiName}/schemas/default?api-version=2021-04-01-preview`, requestOptions).promise();
}
).then(async () => {
// tslint:disable-next-line:no-non-null-assertion
await node!.refresh(actionContext);
window.showInformationMessage(localize("addSchema", `Add Schema to graphql API '${node?.root.apiName}' succesfully.`));
});
}

async function askSchemaDocument(): Promise<Uri[]> {
const openDialogOptions: OpenDialogOptions = {
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
openLabel: "Import",
filters: {
JSON: ["js"]
}
};
const rootPath = workspace.rootPath;
if (rootPath) {
openDialogOptions.defaultUri = Uri.file(rootPath);
}
return await ext.ui.showOpenDialog(openDialogOptions);
}
Loading