Skip to content

Commit

Permalink
feat(api-gen): added apiType option to loadSchema command (#564)
Browse files Browse the repository at this point in the history
  • Loading branch information
patzick committed Feb 5, 2024
1 parent 9643e56 commit 93a6048
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 25 deletions.
15 changes: 15 additions & 0 deletions .changeset/quiet-ghosts-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
"@shopware/api-gen": minor
---

Added `apiType` option in `loadSchema` command. With `SHOPWARE_ADMIN_USERNAME` and `SHOPWARE_ADMIN_PASSWORD` env variables we can now authorize Admin API schema.

example:

```bash
# load schema from store API
pnpx @shopware/api-gen loadSchema --apiType=store --filename=storeApiSchema.json

# load schema from admin API
pnpx @shopware/api-gen loadSchema --apiType=admin --filename=adminApiSchema.json
```
2 changes: 0 additions & 2 deletions packages/api-client-next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"build": "export NODE_ENV=production && unbuild && pnpm build:types",
"build:types": "tsc ./src/*.ts --declaration --allowJs --emitDeclarationOnly --outDir ./temp --skipLibCheck",
"dev": "export NODE_ENV=development && unbuild --stub",
"generate": "esno ../api-gen/src/cli.ts generate",
"lint": "eslint src/**/*.ts* --fix --max-warnings=0 && pnpm run typecheck",
"typecheck": "tsc --noEmit",
"test": "vitest run --typecheck",
Expand All @@ -51,7 +50,6 @@
},
"devDependencies": {
"@codspeed/vitest-plugin": "^2.3.1",
"@shopware/api-gen": "workspace:*",
"@types/prettier": "^3.0.0",
"@vitest/coverage-v8": "^1.2.2",
"eslint-config-shopware": "workspace:*",
Expand Down
23 changes: 22 additions & 1 deletion packages/api-gen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ npx i @shopware/api-gen [command]

### `generate`

Transform OpenAPI specification from JSON file to Typescript schemas.
Transform OpenAPI specification from JSON file to Typescript schemas. Use `loadSchema` command first.

options:

```bash
pnpx @shopware/api-gen generate --help

# generate schemas from store API
pnpx @shopware/api-gen generate --filename=storeApiSchema.json

# generate schemas from admin API
pnpx @shopware/api-gen generate --filename=adminApiSchema.json
```

### `loadSchema`
Expand All @@ -35,6 +41,21 @@ options:

```bash
pnpx @shopware/api-gen loadSchema --help

# load schema from store API
pnpx @shopware/api-gen loadSchema --apiType=store --filename=storeApiSchema.json

# load schema from admin API
pnpx @shopware/api-gen loadSchema --apiType=admin --filename=adminApiSchema.json
```

Remember to add `.env` file in order to authenticate with Shopware instance.

```bash
OPENAPI_JSON_URL="https://your-shop-instance.shopware.store"
OPENAPI_ACCESS_KEY="YOUR_STORE_API_ACCESS_KEY"
SHOPWARE_ADMIN_USERNAME="my@username.com"
SHOPWARE_ADMIN_PASSWORD="my-password"
```

<!-- AUTO GENERATED CHANGELOG -->
Expand Down
1 change: 1 addition & 0 deletions packages/api-gen/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"vitest": "^1.2.2"
},
"dependencies": {
"@shopware/api-client": "workspace:*",
"ofetch": "^1.3.3",
"openapi-typescript": "^6.7.4",
"prettier": "^3.2.4",
Expand Down
8 changes: 7 additions & 1 deletion packages/api-gen/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function commonOptions(args: Argv<unknown>): Argv<CommonOptions> {

// eslint-disable-next-line no-unused-expressions
yargs(hideBin(process.argv))
.scriptName("client")
.scriptName("@shopware/api-gen")
.usage("$0 [args]")
.command(
"generate",
Expand All @@ -42,6 +42,12 @@ yargs(hideBin(process.argv))
"Load JSON schema from your API instance. You need to have proper .env file",
(args) => {
return commonOptions(args)
.option("apiType", {
describe:
"Type of the API schema to load. It can be 'store' or 'admin'",
default: "store",
choices: ["store", "admin"],
})
.positional("filename", {
type: "string",
default: "apiSchema.json",
Expand Down
94 changes: 82 additions & 12 deletions packages/api-gen/src/commands/loadSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,98 @@ import { writeFileSync } from "node:fs";
import * as dotenv from "dotenv";
import c from "picocolors";
import { format } from "prettier";
import { createAdminAPIClient, createAPIClient } from "@shopware/api-client";
import type {
operations as adminOperations,
operationPaths as adminOperationPaths,
} from "@shopware/api-client/admin-api-types";
// TODO: change adminOperations to storeOperations after fixing NEXT-33506
// import type {
// operations,
// operationPaths,
// } from "@shopware/api-client/api-types";

const config = dotenv.config().parsed || {};

export async function loadSchema(args: { cwd: string; filename: string }) {
const SCHEMA_ENDPOINT = "_info/openapi3.json";
const STORE_API_ENDPOINT = `/store-api/${SCHEMA_ENDPOINT}`;
const ADMIN_API_ENDPOINT = `/api/${SCHEMA_ENDPOINT}`;

export async function loadSchema(args: {
cwd: string;
filename: string;
apiType: string;
}) {
if (!["store", "admin"].includes(args.apiType)) {
console.error(
c.red(`Invalid "apiType" argument. It should be "store" or "admin"`),
);
process.exit(1);
}
const isAdminApi = args.apiType === "admin";

const requiredEnvVars = ["OPENAPI_JSON_URL"];
if (isAdminApi) {
requiredEnvVars.push("SHOPWARE_ADMIN_USERNAME");
requiredEnvVars.push("SHOPWARE_ADMIN_PASSWORD");
} else {
requiredEnvVars.push("OPENAPI_ACCESS_KEY");
}

const missingEnvVars = requiredEnvVars.filter((envVar) => !config[envVar]);
try {
if (!config.OPENAPI_JSON_URL || !config.OPENAPI_ACCESS_KEY) {
if (missingEnvVars.length) {
console.error(
c.red(
`Missing ${c.bold("OPENAPI_JSON_URL")} or ${c.bold(
"OPENAPI_ACCESS_KEY",
)} env variables.\n\nCheck whether the .env file is created.\n`,
`Missing ${c.bold(missingEnvVars.join(","))} env variables.\n\nCheck whether the .env file is created.\n`,
),
);
process.exit(1);
}

const apiJSON = await fetch(config.OPENAPI_JSON_URL, {
headers: {
"sw-access-key": config.OPENAPI_ACCESS_KEY,
Authorization: config.OPENAPI_ACCESS_KEY,
},
}).then((res) => res.json());
const configUrl = config.OPENAPI_JSON_URL.replace(
"/api/_info/openapi3.json",
"",
).replace("/atore-api/_info/openapi3.json", "");

const downloadUrl =
configUrl + (isAdminApi ? ADMIN_API_ENDPOINT : STORE_API_ENDPOINT);

let apiJSON;

if (isAdminApi) {
const adminClient = createAdminAPIClient<
adminOperations,
adminOperationPaths
>({
baseURL: `${configUrl}/api`,
credentials: {
grant_type: "password",
client_id: "administration",
scopes: "write",
username: config.SHOPWARE_ADMIN_USERNAME,
password: config.SHOPWARE_ADMIN_PASSWORD,
},
});
apiJSON = await adminClient.invoke(
"api-info get /_info/openapi3.json?type",
{
type: "json",
},
);
} else {
// TODO: change adminOperations to storeOperations after fixing NEXT-33506
const apiClient = createAPIClient<adminOperations, adminOperationPaths>({
baseURL: `${configUrl}/store-api`,
accessToken: config.OPENAPI_ACCESS_KEY,
});
apiJSON = await apiClient.invoke(
"api-info get /_info/openapi3.json?type",
{
type: "json",
},
);
}

const formatted = await format(JSON.stringify(apiJSON), {
semi: false,
Expand All @@ -40,7 +110,7 @@ export async function loadSchema(args: { cwd: string; filename: string }) {
console.log(
c.green(
`Schema file loaded from ${c.bold(
config.OPENAPI_JSON_URL,
downloadUrl,
)} and saved to ${c.bold(args.filename)}`,
),
);
Expand Down
14 changes: 5 additions & 9 deletions pnpm-lock.yaml

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

0 comments on commit 93a6048

Please sign in to comment.