Adding to The Project

The add command lets you define a new resource or function group.

Adding a Simple Resource

The CRUDL functions will be generated in the functions/resourcename/ folder and the serverless.yml will be updated accordingly.

For example, let's create a course resource, which has a couple of simple attributes. cd into the project directory and run:

mug add resource course -a "name,subtitle,description"
1

This will generate the following files/ subdirectories in the folder functions/course/:

-rw-r--r-- course.json
-rw-r--r-- course.go
-rw-r--r-- serverless.yml
-rw-r--r-- create/main.go
-rw-r--r-- delete/main.go
-rw-r--r-- list/main.go
-rw-r--r-- read/main.go
-rw-r--r-- update/main.go
1
2
3
4
5
6
7
8

The resource definition is kept track of in the course.json like this. I use this as a development step to eventually enable definition through json input:

{
  "name": "course",
  "type": "Course",
  "ident": "course",
  "attributes": [
    {
      "name": "id",
      "ident": "id",
      "goType": "string",
      "awsType": "S",
      "hash": true
    },
    {
      "name": "name",
      "ident": "name",
      "goType": "string",
      "awsType": "S",
      "hash": false
    },
    {
      "name": "subtitle",
      "ident": "subtitle",
      "goType": "string",
      "awsType": "S",
      "hash": false
    },
    {
      "name": "description",
      "ident": "description",
      "goType": "string",
      "awsType": "S",
      "hash": false
    }
  ],
  "nested": null,
  "imports": [
    "github.com/gofrs/uuid"
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

The course's struct in the course.go looks like this:

// Course defines the Course model
type Course struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Subtitle    string `json:"subtitle"`
	Description string `json:"description"`
}
1
2
3
4
5
6
7

Identifying Attribute

As you can see an ID attribute of type string is automatically added. This ID will also be used as the hash key for the table.

It is important to note, that DynamoDB is not best friends with UUID types. The marshall/ unmarshall process is still a little buggy, so at this point it is safer to just store UUIDs as strings and marshall/ unmarshall them in the functions code, instead of letting DynamoDB do that work.

If wish to define your own identifying attribute, you can do so by specifying the required flags of the command. For details see the Commands Reference.

General Attributes

The type for an attribute is by default string if none is provided. E.g., if you would like to add a number just provide the golang type with the attribute's name separated by a colon (😃 like this:

mug add resource course -a "name,subtitle,description,price:float32"
1

The course.go file will also contain all the wrapper methods to interact with the database, just in case you want to have another solution as DynamoDB as persistence layer. The main.go files in the function subdirectories will contain the actual lambda functionality.

Complex Resource Definition with Nested Objects

With Dynamo DB being a NoSQL database you certainly cannot use relationships like you may be used to from relational databases like MySQL or PostgreSQL. Usually you overcome this by deciding which entities you work with (querying, writing, etc.) and embedding all related information.

With mug you can easily generate such resources with a little more complex attribute definition to the -a attributes flag:

  • {} wraps nested objects (1-1 relationship)
  • [] wraps slices of objects (1-n relationship).

For example, let's generate a user, who has an address and may have multiple enrollments to courses: Please make sure to wrap the attribute definition with "(double quotes) to ensure the recursive parsing works!

mug add resource user -a "name,isActive:bool,email,
address:{street,zip,city},
enrollments:[courseID,startDate:time.Time,endDate:time.Time]"
1
2
3

The generated go struct(s) will look like this:

// User defines the User model
type User struct {
	ID       string `json:"id"`
	Name     string `json:"name"`
	IsActive bool   `json:"is_active"`
	Email    string `json:"email"`

	Address     Address       `json:"address"`
	Enrollments []Enrollment  `json:"enrollments"`
}

// Address defines the Address model
type Address struct {
	Street string `json:"street"`
	Zip    string `json:"zip"`
	City   string `json:"city"`
}

// Enrollment defines the Enrollments model
type Enrollment struct {
	CourseID  string    `json:"course_id"`
	StartDate time.Time `json:"start_date"`
	EndDate   time.Time `json:"end_date"`
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

Of course, you can also reference the ID in an object, however, you will have to manage this in your own code - getting the ID or multiple IDs for m-n relationships and fetching the referenced objects afterwards.

Adding Function Groups, Functions etc.

Adding function groups or functions is very similar. You can also remove resources, function groups or functions from the previous.

Have a look at the appropriate command syntax in the Commands Reference.