weixin_39884872 2020-11-29 12:51 采纳率: 0%
浏览 0

Request for improved schema.graphql documentation and schema verfication output

Note: If your feature-request is regarding the AWS Amplify Console service, please log it in the official AWS Amplify Console forum

Is your feature request related to a problem? Please describe. It isn't a problem per-se, but when my schema has an issue with a connection, the debug output is really more relevant to the amplify cli app itself and tells very little about where the problem it's talking about is located. If it's something obvious about a type "type Blah" somewhere in it, you get lucky- but mysterious fields on null, and other errors are tough to locate, especially if you're making the same mistake due to a lack of understanding in a bunch of places and you can't tell if you've squashed one or not.

This also leads me to requesting some additional documentation clarification and examples in the way of a slightly more complex schema definition i'd shove straight into my schema.graphql.

Some additional insight into knowing how to get intellij to be aware of the directives you've created would be appreciated. It was very difficult to understand at first which things were stuff you had in the background that would magically work despite the red in my IDE, that I didn't need to define some of the things.. and it was difficult to figure out which defines I do in fact need. It also took a minute to figure out things like "owner" are one of those enums I don't really have quick access to without searching around in graphql documentation.

the learning curve for someone totally new to graphql and amplify was tough for me as I can't tell what's stuff specific to you that I need to look up in your documentation (or what's missing) and what's in the vanilla graphql basics. I ran my schema past a guy who knew graphql but not amplify and got no additional insights.

I've blown a couple of days iterating, which amounts to changing a line or two, tabbing back to the command line, running codegen and modelgen and trying to divine the problem and iterate.

Describe the solution you'd like Could I humbly request that you add some more extensive examples and documentation on the extensions/directives in GraphQL- particularly more advanced connections- and improve the debug output of modelgen to explain where it fails with connections/keys weird errors.

Would like to see a little bit more detailed example with pivot tables and cognito/LWA auth.

Mainly though- the debug output is impossible to decipher. null on fields? where? NO idea. even if i succeed and get everything to compile models, then I get a dynamo 1-1 key error which doesn't make sense for my schema, but can never figure out what type or line is blowing up

It's hard to know whether types like AWSTimestamp are things I should be using, or letting amplify expand.

Giving additional insight to the IntelliJ setup (it was miraculous I even discovered graphqlconfig yaml) would be really helpful. I think I have all the right plugins.

Standby for additional comment with schema example

该提问来源于开源项目:aws-amplify/amplify-cli

  • 写回答

6条回答 默认 最新

  • weixin_39884872 2020-11-29 12:51
    关注

    I'm not keen on giving my schema exactly, so I'm going to paste it and edit some names to obfuscate my project a little- it may introduce typos that aren't really part of my "bug". FYI/YMMV/FWIW

    Much of this was through hard earned documentation scrubbing and googling/duckducking (gooseing? "duck duck go(ose)?".. I may have the auth stuff totally wrong- but I was trying to get it close enough.. I originally had the cognito stuff attached to a different model..

    I think this is the gist of what I was trying to do in terms of links of things. Some of the original intent is purposefully lost, and it may not make sense why I thought I needed a particular type.. but nevertheless, here's what's left. I did remove a couple types and associated connections, hopefully leaving everything syntactically correct(to where I had it).. but I haven't specifically tried this particular config. Forgive some casing issues introduced by search/replace to change concept names.

    
    schema {
      query: QueryRoot
    }
    
    type Badge 
      (fields: ["id"])
      (name: "badgesByCreatorID", fields: ["creatorID", "id"])
      (name: "badgesByTitle", fields: ["title", "id"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      title: String!
      description: String!
      enabled: Boolean!
      visible: Boolean!
      creatorID: ID!
      creator: Entity! (fields: ["creatorID"])
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type EarnedBadges 
      (fields: ["id"])
      (name: "earnedBadgesByBadgeID", fields: ["badgeID"])
      (name: "earnedBadgesByEntityID", fields: ["entityID"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      badgeID: ID!
      badge: Badge! (fields: ["badgeID"])
      entityID: ID!
      entity: Entity! (fields: ["entityID"])
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    enum EmailType {
      WORK
      HOME
      PERSONAL
      BUSINESS
    }
    
    enum PrimaryType {
      PRIMARY
      OTHER
    }
    
    
    type AssociatedEntityEmailAddress 
    (rules: [
      { allow: public, operations: [read] }
    ])
    {
      id: ID!
      emailID: ID!
      emailAddress: EmailAddress! (fields: ["emailID"])
      entityID: ID!
      entity: Entity! (fields: ["entityID"])
      # timestamps
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type EmailAddress 
      (fields: ["id"])
      (name: "emailsByEmail", fields: ["email", "id"])
      (name: "emailsByEntityID", fields: ["entityID", "id"])
      (name: "primaryEmailsByEntityID", fields: ["entityID", "id", "primary"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      entityID: ID # ownerID # set once associated
      associatedEntityEmailAddressID: ID # set once associated
      type: EmailType!
      lock: LockType
      lockDate: Int
      email: String!
      emailVerified: Boolean!
      primary: PrimaryType!
      notifications: Boolean!
      visible: Boolean!
      secret: Boolean!
      creatorID: ID!
      creator: Entity! (fields: ["creatorID"]) # no rights once created unless entityID matches owner
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type AssociatedEntityPhoneNumber 
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      phoneID: ID!
      phoneNumber: PhoneNumber! (fields: ["phoneID"])
      entityID: ID!
      entity: Entity! (fields: ["entityID"])
      # timestamps
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type PhoneNumber 
      (fields: ["id"])
      (name: "phonesByEntityID", fields: ["entityID", "id"])
      (name: "primaryPhonesByEntityID", fields: ["entityID", "id", "primary"])
      (name: "phonesByPhoneNumber", fields: ["phone", "id"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      entityID: ID # set once associated
      associatedPhoneNumberID: ID # set once associated
      type: PhoneType!
      lock: LockType
      lockDate: Int
      phone: String!
      phoneVerified: Boolean!
      tollFree: Boolean!
      primary: PrimaryType!
      notifications: Boolean!
      visible: Boolean!
      secret: Boolean!
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    enum PhoneType {
      VOIP
      MOBILE
      LANDLINE
    }
    
    enum EntityType {
      UNKNOWN
      PERSON
      BUSINESS
      ORGANIZATION
      AGENCY
      API
    }
    
    enum EntitySecurity {
      USER
      ADMIN
    }
    
    enum LockType {
      CONFIRMATION
      ADMIN
      PASSWORD
      ABUSE
      BLACKLIST
    }
    
    type RandomAssociatedData 
      (fields: ["id"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      entityID: ID!
      entity: Entity! (fields: ["entityID"])
      someData: String!
      createdAt: AWSTimestamp! # never update- just replace
    }
    
    # semipivot table- 1:M allows multiple entities per cognito entity(?)
    type AssociatedCognitoEntity 
       # https://aws.amazon.com/blogs/mobile/graphql-security-appsync-amplify/
      (rules: [
        # Defaults to use the "owner" field.
        { allow: owner },
    
        # Authorize the update mutation and both queries. Use `queries: null` to disable auth for queries.
        { allow: owner, ownerField: "owner", operations: [update, read] }
    
        # Admin users can access any operation.
        { allow: groups, groups: ["Admin"] }
      ])
    {
      id: ID!
      type: EntityType!
      cognitoID: String!
      owner: String # may be same as primaryEntityID?
      primaryEntityID: ID!
      primaryEntity: Entity! (fields: ["primaryEntityID"])
      primaryRandomAssociatedDataID: ID!
      primaryRandomAssociatedData: RandomAssociatedData! (fields: ["primaryRandomAssociatedDataID"])
      # all known entities associated with this cognito user
      entities: [Entity!]! (fields: ["id"])
      # plus main props of base Cognito profile
      name: String
      email: String
      phone: String
      picture: String
      profile: String
      username: String
      gender: String
      # timestamps
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    # originally what I was trying to use as auth class
    type Entity 
      (fields: ["id"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      associatedCognitoEntityID: ID # set once associated
      RandomAssociatedDataID: ID! # ALL entities get a key
      RandomAssociatedData: RandomAssociatedData! (fields: ["RandomAssociatedDataID"])
      type: EntityType!
      entitySecurity: EntitySecurity!
      lock: LockType
      lockDate: Int
      username: String
      usernameDate: Int
      password: String
      passwordDate: Int
      name: String
      nameDate: Int
      gender: String
      genderDate: Int
      picture: String
      pictureVisible: Boolean!
      pictureDate: Int
      link: String
      linkConfirmed: Boolean!
      linkVisible: Boolean!
      linkDate: Int
      # proven claimed for this identity - AUTHORITY
      # TODO: NOTE: multiple emails/phones/entities/cognitos with conflicting attributes (phone/email) will/should be in conflict/prevented
      # users ideally shouldn't have multiple entities per cognito
      # and even more ideally shouldn't any phones or emails on non primary entities
      # hopefully uniqueness of phone number and email will prevent one cognito having
      # two+ entities with the same phones or emails. They may be forced to move a phone/email
      # over if they log in with a cognito that matches a phone from one entity and an email
      # from another.
      # Similarly, if a user logs in with another provider, creating a new account with the same
      # email as an existing account, they should be blocked/the accounts should be merged.
      associatedPhones: [AssociatedEntityPhoneNumber!]! (fields: ["id"]) # all phones, including one for primary
      associatedEmails: [AssociatedEntityEmailAddress!]! (fields: ["id"]) # all emails, including one for primary
      # Votes ABOUT this entity - NO AUTHORITY
      CountedVotes: [CountedVote!]! (name: "CountedVoteVoteID", fields: ["id"])
      # created BY this entity - AUTHORITY
      myVotes: [Vote!]! (name: "CreatorEntityVotes", fields: ["id"])
      # groups this entity is participating in (created?)
      mygroups: [Group!]! (fields: ["id"])
      # badged earned by this entity
      myEarnedBadges: [EarnedBadges!]! (fields: ["id"])
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type Group 
      (fields: ["id"])
      (name: "groupsByCreatorID", fields: ["creatorID", "id"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      lock: LockType
      lockDate: Int
      memo: String
      memoDate: Int
      description: String
      descriptionDate: Int
      link: String
      linkVisible: Boolean!
      linkDate: Int
      hidden: Boolean!
      entities: [Entity!]! (fields: ["id"]) # entities involved, NO authority
      Votes: [Vote!]! (fields: ["id"]) # associated Votes
      creatorID: ID!
      creator: Entity! (fields: ["creatorID"]) # AUTHORITY
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    # pivot table for Votes
    type CountedVote 
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      VoteID: ID!
      Vote: Vote! (name: "CountedVoteVoteID", fields: ["VoteID"])
      entityID: ID!
      entity: Entity! (name: "CountedVoteEntityID", fields: ["entityID"])
      someData: String!
      # timestamps
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    type Vote 
      (fields: ["id"])
      (name: "VotesByCreatorID", fields: ["creatorID"])
      (rules: [
        { allow: public, operations: [read] }
      ])
    {
      id: ID!
      CountedVoteID: ID # set once applied
      Vote: Int!
      VoteDate: Int!
      memo: String
      memoVisible: Boolean!
      link: String
      linkVisible: Boolean!
      linkDate: Int
      emailID: ID
      phoneID: ID
      groupID: ID
      visible: Boolean!
      hidden: Boolean!
      creatorID: ID!
      creator: Entity! (name: "CreatorEntityVotes", fields: ["creatorID"])
      createdAt: AWSTimestamp!
      updatedAt: AWSTimestamp!
    }
    
    
    type QueryRoot {
      badge(id: ID!): Badge  (cognito_groups: ["Users", "Admin"])
      getVoteByID(id: ID!): Vote  (cognito_groups: ["Users", "Admin"])
      getgroupByID(id: ID!): Group  (cognito_groups: ["Users", "Admin"])
      getEntityByID(id: ID!): Entity  (cognito_groups: ["Users", "Admin"])
      getEmailByID(id: ID!): EmailAddress  (cognito_groups: ["Users", "Admin"])
      getEmailByEmail(email: String!): EmailAddress  (cognito_groups: ["Users", "Admin"])
      getPhoneByID(id: ID!): PhoneNumber  (cognito_groups: ["Users", "Admin"])
      getPhoneByPhoneNumber(phone: String!): PhoneNumber  (cognito_groups: ["Users", "Admin"])
    }
    
    评论

报告相同问题?