Closed Alonitor closed 5 years ago
I never worked with AppSync. What do you need to make it work?
Here's what I came up with for AppSync using an API key. I plan on switching to Cognito user pools in the coming week. I suspect from this thread that it will be much simpler than I expected.
store/index
:
import VuexORM from '@vuex-orm/core'
import VuexORMGraphQL from '@vuex-orm/plugin-graphql'
import database from '../database'
import awsmobile from '../aws-exports'
const options = {
connectionQueryMode: 'nodes',
debug: process.env.NODE_ENV !== 'production',
database: database,
url: awsmobile.aws_appsync_graphqlEndpoint,
headers: {
'x-api-key': awsmobile.aws_appsync_apiKey
}
}
VuexORM.use(VuexORMGraphQL, options)
export const plugins = [
VuexORM.install(database)
]
I got it working with AppSync but quickly ran into a limitation that vuex-orm (at the time) did not fully support UUID (strings) as primary keys. That was a few months ago though, so that may be different now - I haven't looked at recent updates. Might be looking into before you spend too much time on it though.
Hi and thank you for your responses! Im learning Vue and building/porting an app/web that I want to build with Vue/vuetify and use AWS Amplify for the back end as much as possible. It's all a proof of concept and learning project so far. I read up on Vuex, Vuex Orm and this GraphQL plugin, and this all sounds very sensible ting to implement in a datadriven Vue app. I was thinking since AWS Amplify uses AWS Appsync for it GraphQL API, and as far as I could read, Appsync GraphQL is based on/made by Appollo and that these where compatible, that this plugin should work out of the box?
@toadkicker : Thank you for this! I tried your setup, but it does not seem to get anything from Appsync. I cannot see any requests going to Appsync? This is my store.js file:
import Vue from 'vue'
import Vuex from 'vuex'
import VuexORM from "@vuex-orm/core";
import VuexORMGraphQL from "@vuex-orm/plugin-graphql";
import awsmobile from './aws-exports'
/* eslint-disable no-console */
Vue.use(Vuex)
const database = new VuexORM.Database()
const options = {
connectionQueryMode: 'nodes',
debug: process.env.NODE_ENV !== 'production',
database: database,
url: awsmobile.aws_appsync_graphqlEndpoint,
headers: {
'x-api-key': awsmobile.aws_appsync_apiKey
}
}
VuexORM.use(VuexORMGraphQL, options);
export const store = new Vuex.Store({
plugins: [VuexORM.install(database)]
})
//export default store
console.log(store.state.entities)
console.log(store)
//console.log(store.state.entities.Calculators.data[1].title)
Im probably missing something obvious, so I keep googling and see if I can figure it out.
@cameroncf where did you see that information? I am not able to find much about it searching for uuid
in core and here.
and that these where compatible, that this plugin should work out of the box?
Should, but it's not guaranteed due to the fact that this plugin currently has a opinion how the GraphQL Schema should look like :)
Ok, I got further here now, and if I get a complete solution I will post it. But for now I seem to be stuck at this error trying to create a new post:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in v-on handler (Promise/async): "Error: GraphQL error: Validation error of type UnknownType: Unknown type PostInput
GraphQL error: Validation error of type MissingFieldArgument: Missing field argument input @ 'createPost'
GraphQL error: Validation error of type UnknownArgument: Unknown field argument post @ 'createPost'
GraphQL error: Validation error of type FieldUndefined: Field 'nodes' in type 'ModelCommentConnection' is undefined @ 'createPost/comments/nodes'"
Appsync create mutation should look like this:
export const createPost = `mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
id
title
content
publishedAt
comments {
items {
id
author
content
publishedAt
postId
}
nextToken
}
}
}
`;
So it seams that the created "PostInput" should be just "input". Is there a way to do this?
@Alonitor That is because this plugin's opinion is to favor camelCase instead of TitleCase.
Thank you guy's for helping me out. Im probably going to abandon this path for now. It seams that this wont work with AWS appsync out of the box as I had hoped.
Im also really looking for a solution where I dont need to do repetetive tasks regarding the data layer. Ideally it would be nice to define you data classes (model), then have the schema be generated from this, update Appsync and then just related to your object model. But I will look into this again if it will work with appsync.
Anyway good work and keep on it! :)
Well I am assigned to work on this for the next several weeks so I will see what I can do. On Apr 18, 2019, 18:21 -0700, Alonitor notifications@github.com, wrote:
Closed #86. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.
I don't want to close this. Because in my opinion this plugin should support AWS AppSync and all other GraphQL Schemas.
My idea is to have some kind of Adapter Pattern here which allows to simply configure the schema-layout with presets (appsync
, rails-graphql
, graphene
, and so on) or to simply pass a custom adapter.
I want to have that for version 1.0.0 (which means: ASAP). I'm very busy currently but I wish to put some work into this in the next weeks.
Thank you very much guys for your input and this discussion! :)
Ok Grate!! Here are some more thoughts, you may use as you like: It would be nice to take into account AWS Amplify. The Amplify CLI lets you create among other things the GraphQL API (Appsync). Amplify creates some folders in your project under the folder "Amplify". Here you can find ./amplify/backend/api/[yourapp]/schema.graphql This is where you define your schema/model and Amplify will grab this file, create all your backend needs and write all the files you need back into your project (if you ask for it (default is yes)). If you do it will create/update files in src/graphql. Here it will create files containing your queries, mutations, subscriptions as well as a schema.json file.
So I'm thinking two possible top level approaches:
And if I understand the concept right, there probably has to be a new connection mode that matches the generated queries, mutations, subscriptions in the src/graphql folder.
Here's what I got working:
plugins/aws
:
import Vue from 'vue'
import Amplify, * as AmplifyModules from 'aws-amplify'
import { AmplifyPlugin } from 'aws-amplify-vue'
import awsexports from '../aws-exports'
Amplify.configure(awsexports)
Amplify.configure({
API: {
graphql_endpoint: awsexports.aws_appsync_graphqlEndpoint,
graphql_headers: () => ({
'x-api-key': awsexports.aws_appsync_apiKey
})
}
})
Vue.use(AmplifyPlugin, AmplifyModules)
store/index.js
:
import VuexORM from '@vuex-orm/core'
import VuexORMGraphQL from '@vuex-orm/plugin-graphql'
import database from '../database'
import awsmobile from '../aws-exports'
const options = {
connectionQueryMode: 'nodes',
database: database,
url: awsmobile.aws_appsync_graphqlEndpoint,
includeExtensions: true,
headers: {
'x-api-key': awsmobile.aws_appsync_apiKey
},
debug: process.env.NODE_ENV !== 'production'
}
VuexORM.use(VuexORMGraphQL, options)
export const plugins = [
VuexORM.install(database)
]
database/index.ts
:
import { Database } from '@vuex-orm/core'
import Company from '../models/Company'
database.register(Company)
export default database
models/Company.ts
:
import { Model } from '@vuex-orm/core'
export default class Company extends Model {
static entity = 'companies';
static primaryKey = 'pKey';
static fields() {
return {
name: this.attr('name'),
pKey: this.attr('pKey')
}
}
}
I'll preface this that I'm using Nuxt to build with, so fetch
is specific to them. If you aren't using Nuxt, just change listCompanies()
from .all()
to .fetch()
. Now for the part where Amplify and this plugin come together in Vue:
<amplify-connect :query="companies">
<template slot-scope="{ loading, data, errors }">
<div v-if="loading">
Loading...
</div>
<div v-else-if="errors.length > 0">
Errors {{ errors }}
</div>
<div v-else-if="data">
<div v-for="company in listCompanies" :key="company.pKey">
<h1>{{ company.name }}</h1>
</div>
</div>
</template>
</amplify-connect>
</template>
<script>
import { components } from 'aws-amplify-vue'
import Company from '@/models/Company'
export default {
name: 'CompaniesPage',
components: { ...components },
computed: {
listCompanies() {
return Company.all()
}
},
fetch() {
Company.fetch()
}
}
</script>
I've implemented a basic adapter pattern. Could you take a look if this would help you?
https://github.com/vuex-orm/plugin-graphql/pull/89
I will merge this next week after I've tested it and I'm open for feedback :)
Merged (but not released yet)
@toadkicker How did you customize the function of vuex-orm
to match the AppSync schemas?
I am having trouble changing the default name of listed items of nodes
to the AppSync default of items
.
I added a default appsync adapter to the project some time ago. I haven’t had a recent use case for this tool so I can’t confirm if it still works in a live app.
To do that, import the appsync adapter and pass it into query/mutation builder as your template constructor.
Was using https://github.com/atulmy/gql-query-builder to do it
@phortx Is there a way to rename nodes
to items
when getting lists?
Currently not possible, I think. Please feel free to create a PR :)
hi @toadkicker I have been working for a few months on a Nuxtjs project with Amplify backend and I am only discovering vuex-orm and your graphql plugin 😱 I would have saved a lot of time had I seen this before. At least I think, since I am trying to implement it right now and I seem to run into some 401 issues as I am using Amplify endpoints with IAM authentification. The Introspection fails because of it. And also, do you have an example repo or something working I can look at with this kind of Nuxt /Vuex ORM / Amplify setup?
Is it possible to use this with AWS Appsync?