A step by step tutorial that will teach you the fundamentals of building and maintaining a project with Wrapt.
Let's say that we want to create an application to manage recipes. We're going to call it CarbonKitchen
and it
should start out by storing recipes and their associated ingredients.
To get things started, we we are going to build a bare bones yaml
or json
file to lay out what we want our project to look like. This file is going to describe what our particular domain looks like
and then we can add additional features and logic afterward.
Don't feel pressured to get this exactly correct from the get go. This file is NOT meant to be a concrete implementation of your API, just a starting point that you can build on over time.
So what's this file look like? Let's go over an example. For a full list of the configuration option details, you can go to the domain-template page.
We're going to start out by creating a new yaml
file and adding a domain name of CarbonKitchen
.
DomainName: CarbonKitchen
Next, we need to lay out each of the logical contextual boundaries within our domain (a.k.a. bounded contexts).
In this domain, three come to mind: 1) Recipes
to store our recipes 2) Planning
to store our meal plans and 3) Shopping
to store our shopping lists.
Let's start out with the RecipeManagement
bounded context and name it with a property called ProjectName
.
DomainName: CarbonKitchen
BoundedContexts:
- ProjectName: RecipeManagement
Then, we'll describe our database set up for each bounded context using the DbContext property. I'm also going to set port to run on locally, but this is optional.
DomainName: CarbonKitchen
BoundedContexts:
- ProjectName: RecipeManagement
Port: 5005
DbContext:
ContextName: RecipesDbContext
DatabaseName: RecipeManagement
Provider: postgres
Then let's add in our Recipe
Entity with a variety of
properties based on our requirements. Be sure to check the entity properties page to
see what's required and what defaults are used. We're also going to add the features that we want for this particular entity.
DomainName: CarbonKitchen
BoundedContexts:
- ProjectName: RecipeManagement
Port: 5005
DbContext:
ContextName: RecipesDbContext
DatabaseName: RecipeManagement
Provider: postgres
Entities:
- Name: Recipe
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: Title
Type: string
CanFilter: true
CanSort: true
- Name: Directions
Type: string
CanFilter: true
CanSort: true
- Name: RecipeSourceLink
Type: string
CanFilter: true
CanSort: true
- Name: Description
Type: string
CanFilter: true
CanSort: true
- Name: ImageLink
Type: string
CanFilter: true
CanSort: true
Note that Entities
is a list, so we can add more than one if we want:
DomainName: CarbonKitchen
BoundedContexts:
- ProjectName: RecipeManagement
Port: 5005
DbContext:
ContextName: RecipesDbContext
DatabaseName: RecipeManagement
Provider: postgres
Entities:
- Name: Recipe
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: Title
Type: string
CanFilter: true
CanSort: true
- Name: Directions
Type: string
CanFilter: true
CanSort: true
- Name: RecipeSourceLink
Type: string
CanFilter: true
CanSort: true
- Name: Description
Type: string
CanFilter: true
CanSort: true
- Name: ImageLink
Type: string
CanFilter: true
CanSort: true
- Name: Ingredient
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: RecipeId
Type: int?
CanFilter: true
CanSort: true
- Name: Name
Type: string
CanFilter: true
CanSort: true
- Name: Unit
Type: string
CanFilter: true
CanSort: true
- Name: Amount
Type: double?
CanFilter: true
CanSort: true
Now I'm going to add in some Swagger documentation to provide a little extra context. Optional, but nice to have. You can also add other optional properties like authorization settings if you'd like to include those here.
DomainName: CarbonKitchen
BoundedContexts:
- ProjectName: RecipeManagement
Port: 5005
DbContext:
ContextName: RecipesDbContext
DatabaseName: RecipeManagement
Provider: postgres
Entities:
- Name: Recipe
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: Title
Type: string
CanFilter: true
CanSort: true
- Name: Directions
Type: string
CanFilter: true
CanSort: true
- Name: RecipeSourceLink
Type: string
CanFilter: true
CanSort: true
- Name: Description
Type: string
CanFilter: true
CanSort: true
- Name: ImageLink
Type: string
CanFilter: true
CanSort: true
- Name: Ingredient
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: RecipeId
Type: int?
CanFilter: true
CanSort: true
- Name: Name
Type: string
CanFilter: true
CanSort: true
- Name: Unit
Type: string
CanFilter: true
CanSort: true
- Name: Amount
Type: double?
CanFilter: true
CanSort: true
SwaggerConfig:
Title: Carbon Kitchen Recipes
Description: Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at carbonkitchen.com/dev/docs
ApiContact:
Name: Carbon Kitchen
Email: devsupport@CarbonKitchen.com
Url: https://www.carbonkitchen.com
Now that we've put together our domain layout, let's actually build our solution. To start, make sure you've followed the install instructions.
Then, open Command Prompt, Powershell, Terminal, etc. and cd
to whatever directory you want to create your project repository in. Finally, we just need to run one command:
craftsman new:domain C:\Users\Paul\Documents\WraptTemplates\NewCarbonKitchen.yaml
Note that the filepath here should match wherever you saved your yaml file. A relative path should also work.
Once that's done, Craftsman will have added an entire API for you in whatever directory you ran this in. Check out the project architecture and organization page for more details.
Now you can cd
into your bounded context directory and run dotnet run --project {ProjectName}
and your API is up and all the boilerplate taken care of 🥳
So, we have this existing project, but what if we wanted to add a new entity to capture shopping list items so that we can add ingredients we need for our grocery outing?
All we need to do is create another yaml
or json
file (based on the add entity template) that describes this new entity. Something like this:
AddSwaggerComments: true
Entities:
- Name: ShoppingListItem
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: Amount
Type: double?
CanFilter: true
CanSort: true
- Name: Name
Type: string
CanFilter: true
CanSort: true
- Name: Category
Type: string
CanFilter: true
CanSort: true
- Name: Unit
Type: string
CanFilter: true
CanSort: true
Then, we can add that entity to our project using the add:entity command:
craftsman add:entity C:\Users\Paul\Documents\WraptTemplates\ShoppingListEntity.yaml
So we built out the bounded context for our Recipes
, but what if we wanted to add the Shopping
bounded context? Let's make a
new file (using a bounded-contexts template to capture those details:
BoundedContexts:
- ProjectName: ShoppingManagement
Port: 5010
DbContext:
ContextName: ShoppingDbContext
DatabaseName: ShoppingManagement
Provider: Postgres
Entities:
- Name: ShoppingList
Features:
- Type: AddRecord
- Type: GetRecord
- Type: GetList
- Type: UpdateRecord
- Type: DeleteRecord
Properties:
- Name: Store
Type: string
CanFilter: true
CanSort: true
SwaggerConfig:
Title: Carbon Kitchen Shopping
Description: Our API uses a REST based design, leverages the JSON data format, and relies upon HTTPS for transport. We respond with meaningful HTTP response codes and if an error occurs, we include error details in the response body. API Documentation is at carbonkitchen.com/dev/docs
ApiContact:
Name: Carbon Kitchen
Email: devsupport@CarbonKitchen.com
Url: https://www.carbonkitchen.com
Then we can go to our domain directory (the one with the .gitignore):
cd C:\my\domain\directory
Then we can use the add:bc command to add the new context:
add:bc C:\fullpath\my-new-bc.yaml
Great! Now we have a new project, but we want to add some custom business logic. Maybe we want to do some special validation when we're adding a new recipe or add another endpoint to manage ingredients in batch. This is all completely doable! For details, see the page on customizing Wrapt projects.