Skip to content

Commit

Permalink
feat: generate api code
Browse files Browse the repository at this point in the history
  • Loading branch information
dpilch committed Sep 22, 2023
1 parent 813cdfb commit faea5eb
Show file tree
Hide file tree
Showing 18 changed files with 338 additions and 27 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

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

51 changes: 49 additions & 2 deletions packages/model-generator/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,67 @@
```ts

import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import { BackendIdentifier } from '@aws-amplify/deployed-backend-client';
import { ModelsTarget } from '@aws-amplify/graphql-generator';
import { StatementsTarget } from '@aws-amplify/graphql-generator';
import { TypesTarget } from '@aws-amplify/graphql-generator';

// @public
export const createGraphqlDocumentGenerator: ({ apiId, }: GraphqlDocumentGeneratorFactoryParams) => GraphqlDocumentGenerator;
export const createGraphqlDocumentGenerator: ({ backendIdentifier, credentialProvider, }: GraphqlDocumentGeneratorFactoryParams) => GraphqlDocumentGenerator;

// @public (undocumented)
export type DocumentGenerationParameters = {
language: TargetLanguage;
};

// @public
export const generateAPICode: (props: GenerateAPICodeProps) => Promise<GeneratedOutput>;

// @public (undocumented)
export type GenerateAPICodeProps = GenerateOptions & BackendIdentifier;

// @public (undocumented)
export type GeneratedOutput = {
[filename: string]: string;
};

// @public (undocumented)
export type GenerateGraphqlCodegenOptions = {
format: 'graphql-codegen';
statementTarget: 'javascript' | 'graphql' | 'flow' | 'typescript' | 'angular';
maxDepth?: number;
typenameIntrospection?: boolean;
typeTarget?: 'json' | 'swift' | 'typescript' | 'flow' | 'scala' | 'flow-modern' | 'angular';
multipleSwiftFiles?: boolean;
};

// @public (undocumented)
export type GenerateIntrospectionOptions = {
format: 'introspection';
};

// @public (undocumented)
export type GenerateModelsOptions = {
format: 'modelgen';
modelTarget: 'java' | 'swift' | 'javascript' | 'typescript' | 'dart';
generateIndexRules?: boolean;
emitAuthProvider?: boolean;
useExperimentalPipelinedTransformer?: boolean;
transformerVersion?: boolean;
respectPrimaryKeyAttributesOnConnectionField?: boolean;
generateModelsForLazyLoadAndCustomSelectionSet?: boolean;
addTimestampFields?: boolean;
handleListNullabilityTransparently?: boolean;
};

// @public (undocumented)
export type GenerateOptions = GenerateGraphqlCodegenOptions | GenerateModelsOptions | GenerateIntrospectionOptions;

// @public (undocumented)
export type GenerationResult = {
writeToDirectory: (directoryPath: string) => Promise<void>;
operations: Record<string, string>;
};

// @public (undocumented)
Expand All @@ -28,7 +74,8 @@ export type GraphqlDocumentGenerator = {

// @public (undocumented)
export type GraphqlDocumentGeneratorFactoryParams = {
apiId: string;
backendIdentifier: BackendIdentifier;
credentialProvider: AwsCredentialIdentityProvider;
};

// @public (undocumented)
Expand Down
1 change: 1 addition & 0 deletions packages/model-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@aws-amplify/graphql-generator": "^0.1.0",
"@aws-sdk/client-appsync": "^3.398.0",
"@aws-sdk/client-s3": "^3.414.0",
"@aws-sdk/credential-providers": "^3.414.0",
"@aws-sdk/types": "^3.413.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class AppsyncGraphqlGenerationResult implements GenerationResult {
* @param operations A record of FileName to FileContent
* in the format of Record<string,string>
*/
constructor(private operations: ClientOperations) {}
constructor(public operations: ClientOperations) {}
private writeSchemaToFile = async (
basePath: string,
filePath: string,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import { BackendIdentifier } from '@aws-amplify/deployed-backend-client';
import { createGraphqlDocumentGenerator } from './create_graphql_document_generator.js';

describe('model generator factory', () => {
it('throws an error if a null apiId is passed in', async () => {
it('throws an error if a null backendIdentifier is passed in', async () => {
assert.throws(() =>
createGraphqlDocumentGenerator({ apiId: null as unknown as string })
createGraphqlDocumentGenerator({
backendIdentifier: null as unknown as BackendIdentifier,
credentialProvider: null as unknown as AwsCredentialIdentityProvider,
})
);
});

it('throws an error if a null backendIdentifier is passed in', async () => {
assert.throws(() =>
createGraphqlDocumentGenerator({
backendIdentifier: { stackName: 'foo' },
credentialProvider: null as unknown as AwsCredentialIdentityProvider,
})
);
});
});
38 changes: 32 additions & 6 deletions packages/model-generator/src/create_graphql_document_generator.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
import { AppSyncClient } from '@aws-sdk/client-appsync';
import {
BackendIdentifier,
BackendOutputClient,
} from '@aws-amplify/deployed-backend-client';
import { graphqlOutputKey } from '@aws-amplify/backend-output-schemas';
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import { AppsyncGraphqlGenerationResult } from './appsync_graphql_generation_result.js';
import { AppSyncIntrospectionSchemaFetcher } from './appsync_schema_fetcher.js';
import { AppSyncGraphqlDocumentGenerator } from './graphql_document_generator.js';
import { GraphqlDocumentGenerator } from './model_generator.js';

export type GraphqlDocumentGeneratorFactoryParams = {
apiId: string;
backendIdentifier: BackendIdentifier;
credentialProvider: AwsCredentialIdentityProvider;
};

/**
* Factory function to compose a model generator
*/
export const createGraphqlDocumentGenerator = ({
apiId,
backendIdentifier,
credentialProvider,
}: GraphqlDocumentGeneratorFactoryParams): GraphqlDocumentGenerator => {
if (!apiId) {
throw new Error('`apiId` must be defined');
if (!backendIdentifier) {
throw new Error('`backendIdentifier` must be defined');
}
if (!credentialProvider) {
throw new Error('`credentialProvider` must be defined');
}

const fetchSchema = async () => {
const backendOutputClient = new BackendOutputClient(
credentialProvider,
backendIdentifier
);
const output = await backendOutputClient.getOutput();
const apiId = output[graphqlOutputKey]?.payload.awsAppsyncApiId;
if (!apiId) {
throw new Error(`Unable to determine AppSync API ID.`);
}

return new AppSyncIntrospectionSchemaFetcher(new AppSyncClient()).fetch(
apiId
);
};
return new AppSyncGraphqlDocumentGenerator(
() =>
new AppSyncIntrospectionSchemaFetcher(new AppSyncClient()).fetch(apiId),
fetchSchema,
(fileMap) => new AppsyncGraphqlGenerationResult(fileMap)
);
};
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
import assert from 'node:assert';
import { describe, it } from 'node:test';
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import { BackendIdentifier } from '@aws-amplify/deployed-backend-client';
import { createGraphqlTypesGenerator } from './create_graphql_types_generator.js';

describe('types generator factory', () => {
it('throws an error if a null apiId is passed in', async () => {
it('throws an error if a null backendIdentifier is passed in', async () => {
assert.throws(() =>
createGraphqlTypesGenerator({ apiId: null as unknown as string })
createGraphqlTypesGenerator({
backendIdentifier: null as unknown as BackendIdentifier,
credentialProvider: null as unknown as AwsCredentialIdentityProvider,
})
);
});

it('throws an error if a null backendIdentifier is passed in', async () => {
assert.throws(() =>
createGraphqlTypesGenerator({
backendIdentifier: { stackName: 'foo' },
credentialProvider: null as unknown as AwsCredentialIdentityProvider,
})
);
});
});
38 changes: 32 additions & 6 deletions packages/model-generator/src/create_graphql_types_generator.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,51 @@
import { AppSyncClient } from '@aws-sdk/client-appsync';
import {
BackendIdentifier,
BackendOutputClient,
} from '@aws-amplify/deployed-backend-client';
import { graphqlOutputKey } from '@aws-amplify/backend-output-schemas';
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
import { AppsyncGraphqlGenerationResult } from './appsync_graphql_generation_result.js';
import { AppSyncIntrospectionSchemaFetcher } from './appsync_schema_fetcher.js';
import { AppSyncGraphqlTypesGenerator } from './graphql_types_generator.js';
import { GraphqlTypesGenerator } from './model_generator.js';

export type GraphqlTypesGeneratorFactoryParams = {
apiId: string;
backendIdentifier: BackendIdentifier;
credentialProvider: AwsCredentialIdentityProvider;
};

/**
* Factory function to compose a model generator
*/
export const createGraphqlTypesGenerator = ({
apiId,
backendIdentifier,
credentialProvider,
}: GraphqlTypesGeneratorFactoryParams): GraphqlTypesGenerator => {
if (!apiId) {
throw new Error('`apiId` must be defined');
if (!backendIdentifier) {
throw new Error('`backendIdentifier` must be defined');
}
if (!credentialProvider) {
throw new Error('`credentialProvider` must be defined');
}

const fetchSchema = async () => {
const backendOutputClient = new BackendOutputClient(
credentialProvider,
backendIdentifier
);
const output = await backendOutputClient.getOutput();
const apiId = output[graphqlOutputKey]?.payload.awsAppsyncApiId;
if (!apiId) {
throw new Error(`Unable to determine AppSync API ID.`);
}

return new AppSyncIntrospectionSchemaFetcher(new AppSyncClient()).fetch(
apiId
);
};
return new AppSyncGraphqlTypesGenerator(
() =>
new AppSyncIntrospectionSchemaFetcher(new AppSyncClient()).fetch(apiId),
fetchSchema,
(fileMap) => new AppsyncGraphqlGenerationResult(fileMap)
);
};
17 changes: 17 additions & 0 deletions packages/model-generator/src/generate_api_code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import assert from 'assert';
import { describe, it, mock } from 'node:test';
import { GenerateAPICodeProps, generateAPICode } from './generate_api_code.js';

describe('generateAPICode', () => {
describe('graphql-codegen', () => {});
describe('modelgen', () => {});
describe('introspection', () => {});

it('throws error on unknown format', async () => {
const props = {
format: 'unsupported',
stackName: 'stack_name',
} as unknown as GenerateAPICodeProps;
await assert.rejects(() => generateAPICode(props));
});
});
Loading

0 comments on commit faea5eb

Please sign in to comment.