This release comes with a major rewrite of the Prisma-AppSync Client API and several breaking changes. Please make sure to read details below before upgrading.
🪓 Breaking changesPrisma-AppSync Client API rewritten from the ground upClient API custom resolvers rewriteClient API Hooks rewriteFine-Grained Access Control rewriteNew Prisma-AppSync Client optionsNew Prisma-AppSync Generator optionsNew syntax for AppSync Authorizations modesNew data sanitizer behaviourAuto-generated documentation🎉 New features and improvementsNew installer (scaffolding tool)Customise GraphQL Schema outputSupport for Atomic OperationsSupport for Case Sensitivity (PostgreSQL and MongoDB connectors only)CDK boilerplate upgraded to v2+TypeScript types improved for better DXBundle size and performancesErrors handling and server logs improved🐞 Bug fixes🐙 Issue #26: Issue using nullable relation fields with mutations🐙 Issue #32: Issue performing tests because of JEST_WORKER_ID👋 Github Sponsors
🪓 Breaking changes
Prisma-AppSync Client API rewritten from the ground up
BREAKING
- Usage simplified by adopting a more opinionated approach. Also provides a better TypeScript DX closer to Prisma Client.
- Fine-gained access control and hooks have been re-engineered entirely to make them easier to use and more flexible for all project sizes.
- Adopted a full TDD approach with both unit and integration tests. This is to help bring Prisma-AppSync to a stable version quicker.
Before:
typescript// init prisma-appsync client const app = new PrismaAppSync({ connectionUrl: process.env.CONNECTION_URL }) // direct lambda resolver for appsync export const main = async (event) => { // parse the `event` from your Lambda function app.parseEvent(event) // handle CRUD operations / resolve query const result = await app.resolve() // close database connection await app.prisma.$disconnect() // return query result return Promise.resolve(result) }
After:
typescriptconst prismaAppSync = new PrismaAppSync() // direct lambda resolver for appsync export const resolver = async (event) => { return await prismaAppSync.resolve({ event }) }
Client API custom resolvers rewrite
BREAKING
Before:
typescriptapp.registerCustomResolvers({ notify: async ({ args }: CustomResolverProps) => { return { message: `${args.message} from notify` } } })
After:
typescriptreturn await prismaAppSync.resolve<'notify'>({ event, resolvers: { notify: async ({ args }: QueryParams) => { return { message: `${args.message} from notify`, } }, } })
Client API Hooks rewrite
BREAKING
Before:
typescript// execute before resolve app.beforeResolve(async (props) => {}) // execute after resolve app.afterResolve(async (props) => {})
After:
typescriptreturn await prismaAppSync.resolve<'likePost'>({ event, // AppSync event hooks: { // execute before any query 'before:**': async (props) => {}, // execute after any query 'after:**': async (props) => {}, // execute after custom resolver query `likePost` // (e.g. `query { likePost(postId: 3) }`) 'after:likePost': async ({ prismaClient, authIdentity, args }) => { await prismaClient.notification.create({ data: { event: 'POST_LIKED', targetId: args.postId, userId: authIdentity.sub, } }) }, } })
Fine-Grained Access Control rewrite
BREAKING
Before:
typescript// before resolving any query app.beforeResolve(async ({ authIdentity }: BeforeResolveProps) => { // rules only apply to Cognito authorization type if (authIdentity.authorization !== AuthModes.AMAZON_COGNITO_USER_POOLS) { return false } // get current user from database, using Prisma // we only need to know the user ID const currentUser = await prisma.user.findUnique({ select: { id: true }, where: { cognitoSub: authIdentity.sub } }) || { id: null } // everyone can access (get + list) or create Posts app.allow({ action: AuthActions.access, subject: 'Post' }) app.allow({ action: AuthActions.create, subject: 'Post' }) // only the author is allowed to modify a given Post app.deny({ action: AuthActions.modify, subject: 'Post', // IF `Post.ownerId` NOT_EQUAL_TO `currentUser.id` THEN DENY_QUERY condition: { ownerId: { $ne: currentUser.id } } }) })
After:
typescriptreturn await prismaAppSync.resolve({ event, shield: ({ authorization, identity }: QueryParams) => { const isCognitoAuth = authorization === Authorizations.AMAZON_COGNITO_USER_POOLS const isOwner = { owner: { cognitoSub: identity?.sub } } // Prisma syntax return { '**': { rule: isCognitoAuth, reason: ({ model }) => `${model} access is restricted to logged-in users.`, }, 'modify/post{,/**}': { rule: isOwner, reason: ({ model }) => `${model} can only be modified by their owner.`, }, } }, })
New Prisma-AppSync Client options
BREAKING
connectionUrl
parameter renamed intoconnectionString
. This parameter is optional and leverage Prisma Client naming convention and defaults.
- New
maxDepth
parameter that improve security and prevent clients from abusing query depth. Defaults to3
.
typescriptconst prismaAppSync = new PrismaAppSync({ // optional, DB connection string, default to env var `DATABASE_URL` connectionString, // optional, enable data sanitizer for DB storage (incl. XSS parser), default to true sanitize, // optional, enable debug server logs, default to false debug, // optional, pagination for listQueries, default to 50 defaultPagination, // optional, allowed graphql query depth, default to 3 maxDepth, })
New Prisma-AppSync Generator options
BREAKING
customSchema
parameter renamed intoextendSchema
.
customResolvers
parameter renamed intoextendResolvers
.
- new parameter
defaultDirective
, to globally apply default directives.
typescriptgenerator appsync { provider = "prisma-appsync" // optional params output = "./generated/prisma-appsync" extendSchema = "./custom-schema.gql" extendResolvers = "./custom-resolvers.yaml" defaultDirective = "@auth(model: [{ allow: apiKey }])" }
New syntax for AppSync Authorizations modes
BREAKING
Before:
json/// @PrismaAppSync.type: '@aws_api_key @aws_cognito_user_pools(cognito_groups: [\"admins\"])' model Post { id Int @id @default(autoincrement()) title String }
After:
json/// @auth(model: [{ allow: apiKey }, { allow: userPools, groups: ["admins"] }]) model Post { id Int @id @default(autoincrement()) title String }
👆 Output:
@aws_api_key @aws_cognito_user_pools(cognito_groups: ["admins"])
New data sanitizer behaviour
BREAKING
Enabling the data sanitizer will now automatically "clarify/decode" the data before sending it back to the client. Meaning client-side decoding is not anymore necessary, while your data will still be parsed for XSS before storage.
Auto-generated documentation
BREAKING
To reduce maintenance burden, auto-generated API docs have been removed from Prisma-AppSync in favour of better description of the data (accessible via the native GraphQL documentation from your favourite GraphQL IDE).
In case this is problematic for you and you’d like auto-generated docs to make a come back, please consider supporting the project and opening a new issue.
🎉 New features and improvements
New installer (scaffolding tool)
NEW FEATURE
New installer that can be run via
npx create prisma-appsync-app
. Nicely plug with existing Prisma projects (non-destroying), while also allows to scaffold new projects from scratch.bash___ _ _ __ / _ \_ __(◭)___ _ __ ___ __ _ /_\ _ __ _ __ / _\_ _ _ __ ___ / /◭)/ '__| / __| '_ ` _ \ / _` |_____ //◭\\| '_ \| '_ \\ \| | | | '_ \ / __| / ___/| | | \__ \ | | | | | (◭| |_____/ _ \ |◭) | |◭) |\ \ |_| | | | | (__ \/ |_| |_|___/_| |_| |_|\__,_| \_/ \_/ .__/| .__/\__/\__, |_| |_|\___| |_| |_| |___/ ◭ Prisma-AppSync Installer v1.0.0
Customise GraphQL Schema output
NEW FEATURE
json/// @gql(queries: { list: 'posts' }, subscriptions: null) model Post { id Int @id @default(autoincrement()) title String }
👆 Output: Default
listPosts
query renamed to posts
/ No subscriptions for the Post modelSupport for Atomic Operations
NEW FEATURE
graphqlmutation { updatePost( where: { id: 1 }, operation: { views: { increment: 1 } } ) { views } }
Support for Case Sensitivity (PostgreSQL and MongoDB connectors only)
NEW FEATURE
graphqlquery { listPosts( where: { title: { contains: "prisma", mode: "insensitive" } } ) { title } }
CDK boilerplate upgraded to v2+
IMPROVEMENT
CDK boilerplate was entirely rewritten to offer a more easy to use, simpler syntax making it more approachable for people who are new to AWS CDK.
TypeScript types improved for better DX
IMPROVEMENT
Hovering on Prisma-AppSync types and Client API methods using VSCode is now displaying docs and examples across the entire codebase.
Bundle size and performances
IMPROVEMENT
Noticeable gains in bundle size and runtime performances. Lots of dependencies removed from the previous version, in favour of custom utils functions.
Errors handling and server logs improved
IMPROVEMENT
Both errors handling and server logs (accessible from CloudWatch) have been improved to includes more details and be easily readable.
typescript// Example object returned from the API { "error": "Query has depth of 4, which exceeds max depth of 3.", "type": "FORBIDDEN", "code": 401 } // Error codes const errorCodes = { FORBIDDEN: 401, BAD_USER_INPUT: 400, INTERNAL_SERVER_ERROR: 500, }
🐞 Bug fixes
FIXES
🐙 Issue #26: Issue using nullable relation fields with mutations
🐙 Issue #32: Issue performing tests because of JEST_WORKER_ID
👋 Github Sponsors
CONTRIBUTION
Enjoy using Prisma-AppSync? Please consider sponsoring me at 🐙 maoosi so I can spend more time working on the project.