Writing a webshop for a underground lightsaber dealer based out of Tatooine

simmetopia

Simon Bundgaard-Egeberg

Posted on August 30, 2019

Writing a webshop for a underground lightsaber dealer based out of Tatooine

In the end of September (24') IT-Minds will he hosting a workshop To the moon with ApolloGraphQL. In this workshop we will be building a webshop for Watto who is a known slavetrader based out of tatooine.

Watto quite suddenly stumbled upon some lightsaber parts, which he is trying to fence over a webshop which you have been hired to build.

First of we design the needed functionality.

The Model

Since we will be dealing with users and trading we need some kind of tradeable item. This specific webshop will only handle the trade of items.

A lightsaber item could be designed as :

model Item {
  id                 String     @default(cuid()) @id @unique
  saberPart          SaberParts
  partName           String
  partDescription    String?
  price              Float?
}

enum SaberParts {
  CRYSTAL
  POWER_CORE
  CRYSTAL_VIBRATOR
  HILT
}

These items will be traded in a Transaction. These transaction will have a buyer and a seller. A transaction object will act as the bill of sales for both parties.

Also we need a user which will hold a reference to the sells and purchases they have made.

Pretty good so far.

The backend schema

After having created the underlying data structure, we need to find the best way to expose this data to our webshop.

First of all we need users. These users should be able to signup and login after having signed up.
For brevity a user is only specified by a unique username.

To construct our app schema we will be using prisma-nexus. Prisma nexus is a code-first app schema creation tool.

The root type of a GraphQL schema will be {Mutation: {...}, Query: {...}, Subscription: {...} }.

The subscription part is left out since this is used to implement a websocket like interface, and is not needed for this specific underground webshop.

To be able to specify the different mutations and queries on our app schema, GraphQL needs to know what kind of types it will/can return.

Lets implement how our Item model would look when implemented on our app schema:

const Item = objectType({
  name: 'Item',
  definition(t) {
    t.model.id();
    t.field('saberPart', {
      type: 'saberPart',
    });

    t.model.partDescription();
    t.model.partName();
  },
});

In this code we are specifying that on our schema there exists an objectType called 'Item'. The definition of this type is specified in the definition function.

Since we have used prisma nexus to write our schema, we can use a field on t called model. This will take the value defined in the model and put that on the appschema. When using typescript, you will even have intellisense for these types.

When defining a new type, the t.field is used. The first string will be the name of the field, and after will be the type. As we remember from the database schema shown before, the saberPart is an enum type.

We got the model down, now to change it!

This is where we will be defining keys on query and mutation part of the GraphQL schema. Lets start by how we would create an item.

const ItemArgs = inputObjectType({                                                                                                                             
  name: 'ItemArgs',                                                                                                                                            
  definition: t => {                                                                                                                                           
    t.string('partDescription', { required: true });
    t.string('partName', { required: true });
    t.field('saberPart', { type: 'saberPart', required: true });
  },
});

t.field('itemCreate', {
  type: 'Item',
  args: { data: arg({ type: ItemArgs, required: true }) },
  resolve: (_, { data }, ctx) => {
    const { partName, partDescription, saberPart } = data;
    return ctx.photon.items.create({
      data: {
        partName,
        partDescription,
        isAvailableLocally: true,
        saberPart,
      },
    });
  },
})

The t.field shown above is a definition field on a type called Mutation, defined just like the Item type.

These fields however will control what arguments this mutation will have. Above the mutation will have an argument called data which is of the ItemArgs type.

Lastly in the resolver is where the actual magic is happening, here we are taking data from the arguments, and the ctx which ApolloServer will inject into every resolver, we can create our type. Photon is a auto generated object that acts as and interface to our database.

The ctx.photon.items.create return a promise, but ApolloServer is smart enough to know that is has to wait for the data before returning data to the client.

The frontend!

We have the underlying model! We have to application schema, lets use it!

mutation {
  itemCreate(
    data: {
      partDescription: "This is true"
      partName: "Major Hilt saber"
      saberPart: CRYSTAL_VIBRATOR
    }
  ) {
    id
  }
}

Firstly we are specifying that this is a mutation, and the mutation to call will be itemCreate. We specify the data args as modeled above.

When we have made this item, say we are not interested in the new item, we just want to know that this got added to the database correctly. Therefore we just ask for the id in return. However if you wanted data in return, you would just specify it.

In the case with this very small object, it does not make a big difference. But imagine you have a giant type, with 37 fields of large amounts of data. Where you can pick the exact data you want in return, or just the id, to make sure the request finished.

The response of above query will be a json object:

{
  "data": {
    "itemCreate": {
      "id": "cjzxl45pr00000bva21oz2my4"
    }
  }
}

Notice how the response matches the query above, another great feature about GraphQL.

If you live in Aarhus in Denmark, you can join this workshop for free by going to: https://www.facebook.com/events/397576180864407/, otherwise i will post the workshop Github URL and readme after the 23'rd.

If you have questions don't hesitate to leave a comment below, or just show some love. Happy coding.

💖 💪 🙅 🚩
simmetopia
Simon Bundgaard-Egeberg

Posted on August 30, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related