Skip to content

Commit

Permalink
feat(api-graphql): custom subscriptions (#13154)
Browse files Browse the repository at this point in the history
  • Loading branch information
iartemiev committed Mar 21, 2024
1 parent 1aafa48 commit 2b71e29
Show file tree
Hide file tree
Showing 15 changed files with 397 additions and 80 deletions.
1 change: 0 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"editor.detectIndentation": false,
"editor.insertSpaces": false,
"editor.tabSize": 4,
"prettier.requireConfig": true,
"typescript.tsdk": "node_modules/typescript/lib",
"formattingToggle.affects": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1580,6 +1580,32 @@ const amplifyConfig = {
},
},
},
subscriptions: {
onPostLiked: {
name: 'onPostLiked',
isArray: false,
type: {
model: 'Post',
},
isRequired: false,
},
onPostUpdated: {
name: 'onPostUpdated',
isArray: false,
type: {
model: 'Post',
},
isRequired: false,
arguments: {
postId: {
name: 'postId',
isArray: false,
type: 'String',
isRequired: false,
},
},
},
},
},
};
export default amplifyConfig;
30 changes: 21 additions & 9 deletions packages/api-graphql/__tests__/fixtures/modeled/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,9 @@ const schema = a.schema({
viewCount: a.integer(),
status: a.enum(['draft', 'pending', 'published']),
})
.secondaryIndexes([
a.index('title'),
a.index('description').sortKeys(['viewCount']),
.secondaryIndexes(index => [
index('title'),
index('description').sortKeys(['viewCount']),
]),
Product: a
.model({
Expand Down Expand Up @@ -120,7 +120,7 @@ const schema = a.schema({
argumentContent: a.string().required(),
})
.returns(a.ref('EchoResult'))
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.public()]),

// custom query returning a primitive type
Expand All @@ -130,23 +130,23 @@ const schema = a.schema({
inputString: a.string().required(),
})
.returns(a.string())
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.public()]),
echoNestedCustomTypes: a
.query()
.arguments({
input: a.string().required(),
})
.returns(a.ref('ProductTrackingMeta'))
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.public()]),
echoModelHasNestedTypes: a
.query()
.arguments({
input: a.string().required(),
})
.returns(a.ref('Product'))
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.public()]),
// custom mutation returning a non-model type
PostLikeResult: a.customType({
Expand All @@ -158,7 +158,7 @@ const schema = a.schema({
postId: a.id().required(),
})
.returns(a.ref('PostLikeResult'))
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.private()]),

// custom mutation returning a model type
Expand All @@ -182,9 +182,21 @@ const schema = a.schema({
postId: a.id().required(),
})
.returns(a.ref('Post'))
.function('echoFunction')
.handler(a.handler.function('echoFunction'))
.authorization([a.allow.private()]),

onPostLiked: a
.subscription()
.for(a.ref('likePostReturnPost'))
.returns(a.ref('Post'))
.handler(a.handler.custom({ entry: './jsResolver_base.js' })),

onPostUpdated: a
.subscription()
.for(a.ref('Post').mutations(['update']))
.arguments({ postId: a.string() })
.returns(a.ref('Post'))
.handler(a.handler.custom({ entry: './jsResolver_base.js' })),
//#endregion
});

Expand Down
122 changes: 120 additions & 2 deletions packages/api-graphql/__tests__/internals/generateClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
expectSubWithlibraryConfigHeaders,
} from '../utils/expects';
import { Observable, from } from 'rxjs';
import * as internals from '../../src/internals';

const serverManagedFields = {
id: 'some-id',
Expand Down Expand Up @@ -1996,7 +1995,9 @@ describe('generateClient', () => {
const spy = jest.fn(() => from([graphqlMessage]));
(raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy };

client.models.Note.onCreate().subscribe({
const onC = client.models.Note.onCreate();

onC.subscribe({
next(value) {
expect(spy).toHaveBeenCalledWith(
expect.objectContaining({
Expand Down Expand Up @@ -5181,6 +5182,8 @@ describe('generateClient', () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetAllMocks();
jest.restoreAllMocks();

Amplify.configure(configFixture as any);

jest
Expand Down Expand Up @@ -5392,6 +5395,121 @@ describe('generateClient', () => {
expect(comments[0]).toEqual(expect.objectContaining(listCommentItem));
});

test('can subscribe to custom subscription', done => {
const postToSend = {
__typename: 'Post',
...serverManagedFields,
content: 'a lovely post',
};

const graphqlMessage = {
data: {
onPostLiked: postToSend,
},
};

const client = generateClient<Schema>({ amplify: Amplify });

const spy = jest.fn(() => from([graphqlMessage]));
(raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy };

const spyGql = jest.spyOn(raw.GraphQLAPI as any, 'graphql');

const expectedOperation = 'subscription';
const expectedFieldAndSelectionSet =
'onPostLiked {id content owner createdAt updatedAt}';

const sub = client.subscriptions.onPostLiked().subscribe({
next(value) {
expect(value).toEqual(expect.objectContaining(postToSend));

expect(spyGql).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
query: expect.stringContaining(expectedOperation),
variables: {},
}),
expect.anything(),
);
expect(spyGql).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
query: expect.stringContaining(expectedFieldAndSelectionSet),
variables: {},
}),
expect.anything(),
);
done();
},
error(error) {
expect(error).toBeUndefined();
done('bad news!');
},
});

sub.unsubscribe();
});

test('can subscribe to custom subscription with args', done => {
const postToSend = {
__typename: 'Post',
...serverManagedFields,
postId: 'abc123',
content: 'a lovely post',
};

const graphqlMessage = {
data: {
onPostLiked: postToSend,
},
};

const client = generateClient<Schema>({ amplify: Amplify });

const spy = jest.fn(() => from([graphqlMessage]));
(raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy };

const spyGql = jest.spyOn(raw.GraphQLAPI as any, 'graphql');

const expectedOperation = 'subscription($postId: String)';
const expectedFieldAndSelectionSet =
'onPostUpdated(postId: $postId) {id content owner createdAt updatedAt}';

const sub = client.subscriptions
.onPostUpdated({ postId: 'abc123' })
.subscribe({
next(value) {
expect(value).toEqual(expect.objectContaining(postToSend));

expect(spyGql).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
query: expect.stringContaining(expectedOperation),

variables: { postId: 'abc123' },
}),
expect.anything(),
);
expect(spyGql).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({
query: expect.stringContaining(expectedFieldAndSelectionSet),

variables: { postId: 'abc123' },
}),
expect.anything(),
);
done();
},
error(error) {
expect(error).toBeUndefined();
done('bad news!');
},
});

sub.unsubscribe();
});

test('includes client level headers', async () => {
const spy = mockApiResponse({
data: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ describe('server generateClient', () => {
return result;
});

const mockContextSpec = {};
const mockContextSpec = { token: { value: Symbol('test') } };

const result = await client.queries.echo(mockContextSpec, {
argumentContent: 'echo argumentContent value',
Expand Down
4 changes: 2 additions & 2 deletions packages/api-graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
},
"homepage": "https://aws-amplify.github.io/",
"devDependencies": {
"@aws-amplify/data-schema": "^0.13.9",
"@aws-amplify/data-schema": "^0.14.1",
"@rollup/plugin-typescript": "11.1.5",
"rollup": "^4.9.6",
"typescript": "5.0.2"
Expand All @@ -87,7 +87,7 @@
"dependencies": {
"@aws-amplify/api-rest": "4.0.21",
"@aws-amplify/core": "6.0.21",
"@aws-amplify/data-schema-types": "^0.7.6",
"@aws-amplify/data-schema-types": "^0.7.11",
"@aws-sdk/types": "3.387.0",
"graphql": "15.8.0",
"rxjs": "^7.8.1",
Expand Down

0 comments on commit 2b71e29

Please sign in to comment.